Merged updates from trunk into stable branch
[feedcatcher.git] / vendor / rails / activerecord / lib / active_record / connection_adapters / abstract_adapter.rb
1 require 'benchmark'
2 require 'date'
3 require 'bigdecimal'
4 require 'bigdecimal/util'
5
6 # TODO: Autoload these files
7 require 'active_record/connection_adapters/abstract/schema_definitions'
8 require 'active_record/connection_adapters/abstract/schema_statements'
9 require 'active_record/connection_adapters/abstract/database_statements'
10 require 'active_record/connection_adapters/abstract/quoting'
11 require 'active_record/connection_adapters/abstract/connection_pool'
12 require 'active_record/connection_adapters/abstract/connection_specification'
13 require 'active_record/connection_adapters/abstract/query_cache'
14
15 module ActiveRecord
16 module ConnectionAdapters # :nodoc:
17 # ActiveRecord supports multiple database systems. AbstractAdapter and
18 # related classes form the abstraction layer which makes this possible.
19 # An AbstractAdapter represents a connection to a database, and provides an
20 # abstract interface for database-specific functionality such as establishing
21 # a connection, escaping values, building the right SQL fragments for ':offset'
22 # and ':limit' options, etc.
23 #
24 # All the concrete database adapters follow the interface laid down in this class.
25 # ActiveRecord::Base.connection returns an AbstractAdapter object, which
26 # you can use.
27 #
28 # Most of the methods in the adapter are useful during migrations. Most
29 # notably, the instance methods provided by SchemaStatement are very useful.
30 class AbstractAdapter
31 include Quoting, DatabaseStatements, SchemaStatements
32 include QueryCache
33 include ActiveSupport::Callbacks
34 define_callbacks :checkout, :checkin
35
36 @@row_even = true
37
38 def initialize(connection, logger = nil) #:nodoc:
39 @connection, @logger = connection, logger
40 @runtime = 0
41 @last_verification = 0
42 @query_cache_enabled = false
43 end
44
45 # Returns the human-readable name of the adapter. Use mixed case - one
46 # can always use downcase if needed.
47 def adapter_name
48 'Abstract'
49 end
50
51 # Does this adapter support migrations? Backend specific, as the
52 # abstract adapter always returns +false+.
53 def supports_migrations?
54 false
55 end
56
57 # Does this adapter support using DISTINCT within COUNT? This is +true+
58 # for all adapters except sqlite.
59 def supports_count_distinct?
60 true
61 end
62
63 # Does this adapter support DDL rollbacks in transactions? That is, would
64 # CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL,
65 # SQL Server, and others support this. MySQL and others do not.
66 def supports_ddl_transactions?
67 false
68 end
69
70 # Does this adapter support savepoints? PostgreSQL and MySQL do, SQLite
71 # does not.
72 def supports_savepoints?
73 false
74 end
75
76 # Should primary key values be selected from their corresponding
77 # sequence before the insert statement? If true, next_sequence_value
78 # is called before each insert to set the record's primary key.
79 # This is false for all adapters but Firebird.
80 def prefetch_primary_key?(table_name = nil)
81 false
82 end
83
84 def reset_runtime #:nodoc:
85 rt, @runtime = @runtime, 0
86 rt
87 end
88
89 # QUOTING ==================================================
90
91 # Override to return the quoted table name. Defaults to column quoting.
92 def quote_table_name(name)
93 quote_column_name(name)
94 end
95
96 # REFERENTIAL INTEGRITY ====================================
97
98 # Override to turn off referential integrity while executing <tt>&block</tt>.
99 def disable_referential_integrity(&block)
100 yield
101 end
102
103 # CONNECTION MANAGEMENT ====================================
104
105 # Checks whether the connection to the database is still active. This includes
106 # checking whether the database is actually capable of responding, i.e. whether
107 # the connection isn't stale.
108 def active?
109 @active != false
110 end
111
112 # Disconnects from the database if already connected, and establishes a
113 # new connection with the database.
114 def reconnect!
115 @active = true
116 end
117
118 # Disconnects from the database if already connected. Otherwise, this
119 # method does nothing.
120 def disconnect!
121 @active = false
122 end
123
124 # Reset the state of this connection, directing the DBMS to clear
125 # transactions and other connection-related server-side state. Usually a
126 # database-dependent operation.
127 #
128 # The default implementation does nothing; the implementation should be
129 # overridden by concrete adapters.
130 def reset!
131 # this should be overridden by concrete adapters
132 end
133
134 # Returns true if its safe to reload the connection between requests for development mode.
135 def requires_reloading?
136 true
137 end
138
139 # Checks whether the connection to the database is still active (i.e. not stale).
140 # This is done under the hood by calling <tt>active?</tt>. If the connection
141 # is no longer active, then this method will reconnect to the database.
142 def verify!(*ignored)
143 reconnect! unless active?
144 end
145
146 # Provides access to the underlying database driver for this adapter. For
147 # example, this method returns a Mysql object in case of MysqlAdapter,
148 # and a PGconn object in case of PostgreSQLAdapter.
149 #
150 # This is useful for when you need to call a proprietary method such as
151 # PostgreSQL's lo_* methods.
152 def raw_connection
153 @connection
154 end
155
156 def open_transactions
157 @open_transactions ||= 0
158 end
159
160 def increment_open_transactions
161 @open_transactions ||= 0
162 @open_transactions += 1
163 end
164
165 def decrement_open_transactions
166 @open_transactions -= 1
167 end
168
169 def transaction_joinable=(joinable)
170 @transaction_joinable = joinable
171 end
172
173 def create_savepoint
174 end
175
176 def rollback_to_savepoint
177 end
178
179 def release_savepoint
180 end
181
182 def current_savepoint_name
183 "active_record_#{open_transactions}"
184 end
185
186 def log_info(sql, name, ms)
187 if @logger && @logger.debug?
188 name = '%s (%.1fms)' % [name || 'SQL', ms]
189 @logger.debug(format_log_entry(name, sql.squeeze(' ')))
190 end
191 end
192
193 protected
194 def log(sql, name)
195 if block_given?
196 result = nil
197 ms = Benchmark.ms { result = yield }
198 @runtime += ms
199 log_info(sql, name, ms)
200 result
201 else
202 log_info(sql, name, 0)
203 nil
204 end
205 rescue Exception => e
206 # Log message and raise exception.
207 # Set last_verification to 0, so that connection gets verified
208 # upon reentering the request loop
209 @last_verification = 0
210 message = "#{e.class.name}: #{e.message}: #{sql}"
211 log_info(message, name, 0)
212 raise ActiveRecord::StatementInvalid, message
213 end
214
215 def format_log_entry(message, dump = nil)
216 if ActiveRecord::Base.colorize_logging
217 if @@row_even
218 @@row_even = false
219 message_color, dump_color = "4;36;1", "0;1"
220 else
221 @@row_even = true
222 message_color, dump_color = "4;35;1", "0"
223 end
224
225 log_entry = " \e[#{message_color}m#{message}\e[0m "
226 log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
227 log_entry
228 else
229 "%s %s" % [message, dump]
230 end
231 end
232 end
233 end
234 end