Class: ActiveRecord::ConnectionAdapters::JdbcAdapter

Inherits:
AbstractAdapter
  • Object
show all
Includes:
ActiveRecord::ConnectionAdapters::Jdbc::ConnectionPoolCallbacks, ArJdbc::Abstract::ConnectionManagement, ArJdbc::Abstract::Core, ArJdbc::Abstract::DatabaseStatements, ArJdbc::Abstract::TransactionSupport
Defined in:
lib/arjdbc/jdbc/adapter.rb

Overview

Built on top of ActiveRecord::ConnectionAdapters::AbstractAdapter which provides the abstract interface for database-specific functionality, this class serves 2 purposes in AR-JDBC :

  • as a base class for sub-classes
  • usable standalone (or with a mixed in adapter spec module)

Historically this class is mostly been used standalone and that's still a valid use-case esp. since (with it's arjdbc.jdbc.RubyJdbcConnectionClass) JDBC provides a unified interface for all databases in Java it tries to do it's best implementing all ActiveRecord functionality on top of that. This might no be perfect that's why it checks for a config[:adapter_spec] module (or tries to resolve one from the JDBC driver's meta-data) and if the database has "extended" AR-JDBC support mixes in the given module for each adapter instance. This is sufficient for most database specific specs we support, but for compatibility with native (MRI) adapters it's perfectly fine to sub-class the adapter and override some of its API methods.

Constant Summary collapse

ADAPTER_NAME =
'JDBC'

Constants included from ArJdbc::Abstract::DatabaseStatements

ArJdbc::Abstract::DatabaseStatements::NO_BINDS

Instance Attribute Summary collapse

Attributes included from ArJdbc::Abstract::Core

#config

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ArJdbc::Abstract::TransactionSupport

#begin_db_transaction, #begin_isolated_db_transaction, #commit_db_transaction, #create_savepoint, #exec_rollback_db_transaction, #exec_rollback_to_savepoint, #release_savepoint, #supports_savepoints?, #supports_transaction_isolation?

Methods included from ArJdbc::Abstract::DatabaseStatements

#exec_insert, #exec_query, #exec_update, #select_all

Methods included from ArJdbc::Abstract::ConnectionManagement

#active?, #disconnect!, #really_valid?, #reconnect!

Methods included from ArJdbc::Abstract::Core

#extract_raw_bind_values, #initialize, #jdbc_connection, #log, #translate_exception, #translate_exception_class

Methods included from ActiveRecord::ConnectionAdapters::Jdbc::ConnectionPoolCallbacks

#on_checkin, #on_checkout

Instance Attribute Details

#prepared_statementsObject (readonly)

Returns the value of attribute prepared_statements.



48
49
50
# File 'lib/arjdbc/jdbc/adapter.rb', line 48

def prepared_statements
  @prepared_statements
end

Class Method Details

.arel2_visitors(config) ⇒ Hash

Deprecated.

re-implemented - no longer used

If there's a self.arel2_visitors(config) method on the adapter spec than it is preferred and will be used instead of this one.

Returns:

  • (Hash)

    the AREL visitor to use



127
128
129
# File 'lib/arjdbc/jdbc/adapter.rb', line 127

def self.arel2_visitors(config)
  { 'jdbc' => ::Arel::Visitors::ToSql }
end

.configure_arel2_visitors(config) ⇒ Object

Deprecated.

re-implemented - no longer used

See Also:

  • #arel2_visitors


133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/arjdbc/jdbc/adapter.rb', line 133

def self.configure_arel2_visitors(config)
  visitors = ::Arel::Visitors::VISITORS
  klass = config[:adapter_spec]
  klass = self unless klass.respond_to?(:arel2_visitors)
  visitor = nil
  klass.arel2_visitors(config).each do |name, arel|
    visitors[name] = ( visitor = arel )
  end
  if visitor && config[:adapter] =~ /^(jdbc|jndi)$/
    visitors[ config[:adapter] ] = visitor
  end
  visitor
end

.prepared_statements?(config) ⇒ Boolean (protected)

Allows changing the prepared statements setting for this connection. def prepared_statements=(statements) @prepared_statements = statements end

Returns:

  • (Boolean)

See Also:



425
426
427
428
429
# File 'lib/arjdbc/jdbc/adapter.rb', line 425

def self.prepared_statements?(config)
  config.key?(:prepared_statements) ?
    type_cast_config_to_boolean(config.fetch(:prepared_statements)) :
      false # off by default - NOTE: on AR 4.x it's on by default !?
end

Instance Method Details

#adapter_nameString

Returns the 'JDBC' adapter name.

Returns:

  • (String)

    the 'JDBC' adapter name.



102
103
104
# File 'lib/arjdbc/jdbc/adapter.rb', line 102

def adapter_name
  ADAPTER_NAME
end

#adapter_spec(config) ⇒ Module

Locate the specialized (database specific) adapter specification module if one exists based on provided configuration data. This module will than extend an instance of the adapter (unless an :adapter_class provided).

This method is called during ArJdbc::Abstract::Core#initialize unless an explicit config[:adapter_spec] is set.

Parameters:

  • config

    the configuration to check for :adapter_spec

Returns:

  • (Module)

    the database specific module



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/arjdbc/jdbc/adapter.rb', line 74

def adapter_spec(config)
  dialect = (config[:dialect] || config[:driver]).to_s
  ::ArJdbc.modules.each do |constant| # e.g. ArJdbc::MySQL
    if constant.respond_to?(:adapter_matcher)
      spec = constant.adapter_matcher(dialect, config)
      return spec if spec
    end
  end

  unless config.key?(:dialect)
    begin # does nothing unless config[:jndi] || config[:data_source]
      dialect = ::ArJdbc.(config) do
        || config[:dialect] = .getDatabaseProductName
      end
      return adapter_spec(config) if dialect # re-try matching with :dialect
    rescue => e
      ::ArJdbc.warn("failed to set :dialect from database meda-data: #{e.inspect}")
    else
      return adapter_spec(config) # re-try matching a spec with set config[:dialect]
    end
  end

  nil
end

#columns(table_name, name = nil) ⇒ Object



226
227
228
# File 'lib/arjdbc/jdbc/adapter.rb', line 226

def columns(table_name, name = nil)
  @connection.columns(table_name.to_s)
end

#data_source_exists?(name) ⇒ Boolean

Returns:

  • (Boolean)


314
315
316
# File 'lib/arjdbc/jdbc/adapter.rb', line 314

def data_source_exists?(name)
  table_exists?(name)
end

#data_sourcesObject



309
310
311
# File 'lib/arjdbc/jdbc/adapter.rb', line 309

def data_sources
  tables
end

#database_nameObject

Returns the underlying database name.



186
187
188
# File 'lib/arjdbc/jdbc/adapter.rb', line 186

def database_name
  @connection.database_name
end

#exec_query_raw(sql, name = 'SQL', binds = []) {|v1, v2| ... } ⇒ Array

Similar to ArJdbc::Abstract::DatabaseStatements#exec_query except it returns "raw" results in an array where each rows is a hash with keys as columns (just like Rails used to do up until 3.0) instead of wrapping them in a ActiveRecord::ConnectionAdapters::JdbcAdapter#ActiveRecord#ActiveRecord::Result. In case a block is given it will yield each row from the result set instead of returning mapped query results in an array.

Parameters:

  • sql

    the query string (or AREL object)

  • name (defaults to: 'SQL')

    logging marker for the executed SQL statement log entry

  • binds (defaults to: [])

    the bind parameters

Yields:

  • (v1, v2)

    depending on the row values returned from the query

Returns:

  • (Array)

    unless a block is given



245
246
247
248
249
250
251
252
253
# File 'lib/arjdbc/jdbc/adapter.rb', line 245

def exec_query_raw(sql, name = 'SQL', binds = [], &block)
  sql = to_sql(sql, binds) if sql.respond_to?(:to_sql)

  if prepared_statements?
    log(sql, name, binds) { @connection.execute_query_raw(sql, binds, &block) }
  else
    log(sql, name) { @connection.execute_query_raw(sql, &block) }
  end
end

#execute(sql, name = nil, binds = nil) ⇒ Object

Note:

This method does not use prepared statements.

Note:

The method does not emulate various "native" execute results on MRI.

Executes the SQL statement in the context of this connection. The return value from this method depends on the SQL type (whether it's a SELECT, INSERT etc.). For INSERTs a generated id might get returned while for UPDATE statements the affected row count. Please note that this method returns "raw" results (in an array) for statements that return a result set, while ArJdbc::Abstract::DatabaseStatements#exec_query is expected to return a ActiveRecord::Result (since AR 3.1).



267
268
269
270
271
272
273
274
# File 'lib/arjdbc/jdbc/adapter.rb', line 267

def execute(sql, name = nil, binds = nil)
  sql = to_sql(sql, binds) if binds
  if name == :skip_logging
    _execute(sql, name)
  else
    log(sql, name) { _execute(sql, name) }
  end
end

#execute_quietly(sql, name = 'SQL') ⇒ Object

Kind of execute(sql) rescue nil but logging failures at debug level only.



287
288
289
290
291
292
293
294
295
# File 'lib/arjdbc/jdbc/adapter.rb', line 287

def execute_quietly(sql, name = 'SQL')
  log(sql, name) do
    begin
      _execute(sql)
    rescue => e
      logger.debug("#{e.class}: #{e.message}: #{sql}")
    end
  end
end

#foreign_keys(table_name) ⇒ Object



334
335
336
# File 'lib/arjdbc/jdbc/adapter.rb', line 334

def foreign_keys(table_name)
  @connection.foreign_keys(table_name)
end

#indexes(table_name, name = nil, schema_name = nil) ⇒ Object



319
320
321
# File 'lib/arjdbc/jdbc/adapter.rb', line 319

def indexes(table_name, name = nil, schema_name = nil)
  @connection.indexes(table_name, name, schema_name)
end

#is_a?(klass) ⇒ Boolean

Will return true even when native adapter classes passed in e.g. jdbc_adapter.is_a? ConnectionAdapter::PostgresqlAdapter

This is only necessary (for built-in adapters) when config[:adapter_class] is forced to nil and the :adapter_spec module is used to extend the JdbcAdapter, otherwise we replace the class constants for built-in adapters (MySQL, PostgreSQL and SQLite3).

Returns:

  • (Boolean)


114
115
116
117
118
119
120
121
# File 'lib/arjdbc/jdbc/adapter.rb', line 114

def is_a?(klass)
  # This is to fake out current_adapter? conditional logic in AR tests
  if klass.is_a?(Class) && klass.name =~ /#{adapter_name}Adapter$/i
    true
  else
    super
  end
end

#jdbc_column_classObject

Returns the (JDBC) ActiveRecord column class for this adapter. This is used by (database specific) spec modules to override the class.



62
63
64
# File 'lib/arjdbc/jdbc/adapter.rb', line 62

def jdbc_column_class
  ::ActiveRecord::ConnectionAdapters::JdbcColumn
end

#jdbc_connection_class(spec) ⇒ Object

Returns the (JDBC) connection class to be used for this adapter. This is used by (database specific) spec modules to override the class used assuming some of the available methods have been re-defined.



54
55
56
57
# File 'lib/arjdbc/jdbc/adapter.rb', line 54

def jdbc_connection_class(spec)
  connection_class = spec.jdbc_connection_class if spec && spec.respond_to?(:jdbc_connection_class)
  connection_class ? connection_class : ::ActiveRecord::ConnectionAdapters::JdbcConnection
end

#last_inserted_id(result) ⇒ Integer, NilClass (protected)

Take an id from the result of an INSERT query.

Returns:

  • (Integer, NilClass)


361
362
363
364
365
366
367
368
369
370
371
# File 'lib/arjdbc/jdbc/adapter.rb', line 361

def last_inserted_id(result)
  if result.is_a?(Hash) || result.is_a?(ActiveRecord::Result)
    # If table does not have primary key defined
    return nil if result.first.blank?


    result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
  else
    result
  end
end

#modify_types(types) ⇒ Object

Allows for modification of the detected native types.

Parameters:

  • types

    the resolved native database types

See Also:



167
168
169
# File 'lib/arjdbc/jdbc/adapter.rb', line 167

def modify_types(types)
  types
end

#native_database_typesHash

DB specific types are detected but adapter specs (or extenders) are expected to hand tune these types for concrete databases.

Returns:

  • (Hash)

    the native database types



151
152
153
154
155
156
157
# File 'lib/arjdbc/jdbc/adapter.rb', line 151

def native_database_types
  @native_database_types ||= begin
    types = @connection.native_database_types
    modify_types(types)
    types
  end
end

#pk_and_sequence_for(table) ⇒ Object



324
325
326
# File 'lib/arjdbc/jdbc/adapter.rb', line 324

def pk_and_sequence_for(table)
  ( key = primary_key(table) ) ? [ key, nil ] : nil
end

#prepared_statements?Boolean (protected)

Returns whether :prepared_statements are to be used.

Returns:

  • (Boolean)

    whether :prepared_statements are to be used



414
415
416
417
# File 'lib/arjdbc/jdbc/adapter.rb', line 414

def prepared_statements?
  return @prepared_statements unless (@prepared_statements ||= nil).nil?
  @prepared_statements = self.class.prepared_statements?(config)
end

#primary_keys(table) ⇒ Object



329
330
331
# File 'lib/arjdbc/jdbc/adapter.rb', line 329

def primary_keys(table)
  @connection.primary_keys(table)
end

#structure_dumpObject

Abstract adapter default implementation does nothing silently.

Raises:

  • (NotImplementedError)


173
174
175
# File 'lib/arjdbc/jdbc/adapter.rb', line 173

def structure_dump
  raise NotImplementedError, "structure_dump not supported"
end

#supports_foreign_keys?Boolean

Does our database (+ its JDBC driver) support foreign-keys?

Returns:

  • (Boolean)

Since:

  • 1.3.18



341
342
343
# File 'lib/arjdbc/jdbc/adapter.rb', line 341

def supports_foreign_keys?
  @connection.supports_foreign_keys?
end

#supports_migrations?true

JDBC adapters support migration.

Returns:

  • (true)


180
181
182
# File 'lib/arjdbc/jdbc/adapter.rb', line 180

def supports_migrations?
  true
end

#supports_views?Boolean

Returns:

  • (Boolean)


231
232
233
# File 'lib/arjdbc/jdbc/adapter.rb', line 231

def supports_views?
  @connection.supports_views?
end

#table_definitionObject (protected)

aliasing #create_table_definition as #table_definition :



374
# File 'lib/arjdbc/jdbc/adapter.rb', line 374

alias table_definition create_table_definition

#table_exists?(name) ⇒ Boolean

Returns:

  • (Boolean)


303
304
305
306
# File 'lib/arjdbc/jdbc/adapter.rb', line 303

def table_exists?(name)
  return false unless name
  @connection.table_exists?(name) # schema_name = nil
end

#tables(name = nil) ⇒ Object



298
299
300
# File 'lib/arjdbc/jdbc/adapter.rb', line 298

def tables(name = nil)
  @connection.tables
end

#update_lob_value(record, column, value) ⇒ Object

Parameters:

  • record

    the record e.g. User.find(1)

  • column

    the model's column e.g. User.columns_hash['photo']

  • value

    the lob value - string or (IO or Java) stream



353
354
355
# File 'lib/arjdbc/jdbc/adapter.rb', line 353

def update_lob_value(record, column, value)
  @connection.update_lob_value(record, column, value)
end

#valid_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/arjdbc/jdbc/adapter.rb', line 160

def valid_type?(type)
  ! native_database_types[type].nil?
end

#write_large_object(*args) ⇒ Object

Deprecated.

Rather use #update_lob_value instead.



346
347
348
# File 'lib/arjdbc/jdbc/adapter.rb', line 346

def write_large_object(*args)
  @connection.write_large_object(*args)
end