1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
|
require 'date'
require 'bigdecimal'
require 'bigdecimal/util'
require 'active_support/core_ext/benchmark'
require 'active_record/connection_adapters/schema_cache'
require 'active_record/connection_adapters/abstract/schema_dumper'
require 'monitor'
module ActiveRecord
module ConnectionAdapters # :nodoc:
extend ActiveSupport::Autoload
autoload :Column
autoload :ConnectionSpecification
autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do
autoload :IndexDefinition
autoload :ColumnDefinition
autoload :TableDefinition
autoload :Table
autoload :AlterTable
end
autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
autoload :ConnectionHandler
autoload :ConnectionManagement
end
autoload_under 'abstract' do
autoload :SchemaStatements
autoload :DatabaseStatements
autoload :DatabaseLimits
autoload :Quoting
autoload :ConnectionPool
autoload :QueryCache
end
autoload_at 'active_record/connection_adapters/abstract/transaction' do
autoload :ClosedTransaction
autoload :RealTransaction
autoload :SavepointTransaction
end
# Active Record supports multiple database systems. AbstractAdapter and
# related classes form the abstraction layer which makes this possible.
# An AbstractAdapter represents a connection to a database, and provides an
# abstract interface for database-specific functionality such as establishing
# a connection, escaping values, building the right SQL fragments for ':offset'
# and ':limit' options, etc.
#
# All the concrete database adapters follow the interface laid down in this class.
# ActiveRecord::Base.connection returns an AbstractAdapter object, which
# you can use.
#
# Most of the methods in the adapter are useful during migrations. Most
# notably, the instance methods provided by SchemaStatement are very useful.
class AbstractAdapter
include Quoting, DatabaseStatements, SchemaStatements
include DatabaseLimits
include QueryCache
include ActiveSupport::Callbacks
include MonitorMixin
include ColumnDumper
SIMPLE_INT = /\A\d+\z/
define_callbacks :checkout, :checkin
attr_accessor :visitor, :pool
attr_reader :schema_cache, :last_use, :in_use, :logger
alias :in_use? :in_use
def self.type_cast_config_to_integer(config)
if config =~ SIMPLE_INT
config.to_i
else
config
end
end
def self.type_cast_config_to_boolean(config)
if config == "false"
false
else
config
end
end
def initialize(connection, logger = nil, pool = nil) #:nodoc:
super()
@connection = connection
@in_use = false
@instrumenter = ActiveSupport::Notifications.instrumenter
@last_use = false
@logger = logger
@pool = pool
@query_cache = Hash.new { |h,sql| h[sql] = {} }
@query_cache_enabled = false
@schema_cache = SchemaCache.new self
@visitor = nil
end
def valid_type?(type)
true
end
class SchemaCreation
def initialize(conn)
@conn = conn
@cache = {}
end
def accept(o)
m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
send m, o
end
private
def visit_AlterTable(o)
sql = "ALTER TABLE #{quote_table_name(o.name)} "
sql << o.adds.map { |col| visit_AddColumn col }.join(' ')
end
def visit_AddColumn(o)
sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
sql = "ADD #{quote_column_name(o.name)} #{sql_type}"
add_column_options!(sql, column_options(o))
end
def visit_ColumnDefinition(o)
sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
column_sql = "#{quote_column_name(o.name)} #{sql_type}"
add_column_options!(column_sql, column_options(o)) unless o.primary_key?
column_sql
end
def visit_TableDefinition(o)
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE "
create_sql << "#{quote_table_name(o.name)} ("
create_sql << o.columns.map { |c| accept c }.join(', ')
create_sql << ") #{o.options}"
create_sql
end
def column_options(o)
column_options = {}
column_options[:null] = o.null unless o.null.nil?
column_options[:default] = o.default unless o.default.nil?
column_options[:column] = o
column_options
end
def quote_column_name(name)
@conn.quote_column_name name
end
def quote_table_name(name)
@conn.quote_table_name name
end
def type_to_sql(type, limit, precision, scale)
@conn.type_to_sql type.to_sym, limit, precision, scale
end
def add_column_options!(column_sql, column_options)
@conn.add_column_options! column_sql, column_options
column_sql
end
end
def schema_creation
SchemaCreation.new self
end
def lease
synchronize do
unless in_use
@in_use = true
@last_use = Time.now
end
end
end
def schema_cache=(cache)
cache.connection = self
@schema_cache = cache
end
def expire
@in_use = false
end
def unprepared_visitor
self.class::BindSubstitution.new self
end
def unprepared_statement
old, @visitor = @visitor, unprepared_visitor
yield
ensure
@visitor = old
end
# Returns the human-readable name of the adapter. Use mixed case - one
# can always use downcase if needed.
def adapter_name
'Abstract'
end
# Does this adapter support migrations? Backend specific, as the
# abstract adapter always returns +false+.
def supports_migrations?
false
end
# Can this adapter determine the primary key for tables not attached
# to an Active Record class, such as join tables? Backend specific, as
# the abstract adapter always returns +false+.
def supports_primary_key?
false
end
# Does this adapter support using DISTINCT within COUNT? This is +true+
# for all adapters except sqlite.
def supports_count_distinct?
true
end
# Does this adapter support DDL rollbacks in transactions? That is, would
# CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL,
# SQL Server, and others support this. MySQL and others do not.
def supports_ddl_transactions?
false
end
def supports_bulk_alter?
false
end
# Does this adapter support savepoints? PostgreSQL and MySQL do,
# SQLite < 3.6.8 does not.
def supports_savepoints?
false
end
# Should primary key values be selected from their corresponding
# sequence before the insert statement? If true, next_sequence_value
# is called before each insert to set the record's primary key.
# This is false for all adapters but Firebird.
def prefetch_primary_key?(table_name = nil)
false
end
# Does this adapter support index sort order?
def supports_index_sort_order?
false
end
# Does this adapter support partial indices?
def supports_partial_index?
false
end
# Does this adapter support explain? As of this writing sqlite3,
# mysql2, and postgresql are the only ones that do.
def supports_explain?
false
end
# Does this adapter support setting the isolation level for a transaction?
def supports_transaction_isolation?
false
end
# Does this adapter support database extensions? As of this writing only
# postgresql does.
def supports_extensions?
false
end
# A list of extensions, to be filled in by adapters that support them. At
# the moment only postgresql does.
def extensions
[]
end
# A list of index algorithms, to be filled by adapters that support them.
# MySQL and PostgreSQL have support for them right now.
def index_algorithms
{}
end
# QUOTING ==================================================
# Returns a bind substitution value given a +column+ and list of current
# +binds+.
def substitute_at(column, index)
Arel::Nodes::BindParam.new '?'
end
# REFERENTIAL INTEGRITY ====================================
# Override to turn off referential integrity while executing <tt>&block</tt>.
def disable_referential_integrity
yield
end
# CONNECTION MANAGEMENT ====================================
# Checks whether the connection to the database is still active. This includes
# checking whether the database is actually capable of responding, i.e. whether
# the connection isn't stale.
def active?
end
# Disconnects from the database if already connected, and establishes a
# new connection with the database. Implementors should call super if they
# override the default implementation.
def reconnect!
clear_cache!
reset_transaction
end
# Disconnects from the database if already connected. Otherwise, this
# method does nothing.
def disconnect!
clear_cache!
reset_transaction
end
# Reset the state of this connection, directing the DBMS to clear
# transactions and other connection-related server-side state. Usually a
# database-dependent operation.
#
# The default implementation does nothing; the implementation should be
# overridden by concrete adapters.
def reset!
# this should be overridden by concrete adapters
end
###
# Clear any caching the database adapter may be doing, for example
# clearing the prepared statement cache. This is database specific.
def clear_cache!
# this should be overridden by concrete adapters
end
# Returns true if its required to reload the connection between requests for development mode.
# This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
def requires_reloading?
false
end
# Checks whether the connection to the database is still active (i.e. not stale).
# This is done under the hood by calling <tt>active?</tt>. If the connection
# is no longer active, then this method will reconnect to the database.
def verify!(*ignored)
reconnect! unless active?
end
# Provides access to the underlying database driver for this adapter. For
# example, this method returns a Mysql object in case of MysqlAdapter,
# and a PGconn object in case of PostgreSQLAdapter.
#
# This is useful for when you need to call a proprietary method such as
# PostgreSQL's lo_* methods.
def raw_connection
@connection
end
def open_transactions
@transaction.number
end
def increment_open_transactions
ActiveSupport::Deprecation.warn "#increment_open_transactions is deprecated and has no effect"
end
def decrement_open_transactions
ActiveSupport::Deprecation.warn "#decrement_open_transactions is deprecated and has no effect"
end
def transaction_joinable=(joinable)
message = "#transaction_joinable= is deprecated. Please pass the :joinable option to #begin_transaction instead."
ActiveSupport::Deprecation.warn message
@transaction.joinable = joinable
end
def create_savepoint
end
def rollback_to_savepoint
end
def release_savepoint
end
def case_sensitive_modifier(node)
node
end
def case_insensitive_comparison(table, attribute, column, value)
table[attribute].lower.eq(table.lower(value))
end
def current_savepoint_name
"active_record_#{open_transactions}"
end
# Check the connection back in to the connection pool
def close
pool.checkin self
end
protected
def log(sql, name = "SQL", binds = [])
@instrumenter.instrument(
"sql.active_record",
:sql => sql,
:name => name,
:connection_id => object_id,
:binds => binds) { yield }
rescue => e
message = "#{e.class.name}: #{e.message}: #{sql}"
@logger.error message if @logger
exception = translate_exception(e, message)
exception.set_backtrace e.backtrace
raise exception
end
def translate_exception(exception, message)
# override in derived class
ActiveRecord::StatementInvalid.new(message)
end
end
end
end
|