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'.freeze

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

#delete, #exec_insert, #exec_query, #exec_update, #insert, #select_all, #update

Methods included from ArJdbc::Abstract::ConnectionManagement

#active?, #disconnect!, #reconnect!

Methods included from ArJdbc::Abstract::Core

#initialize, #jdbc_connection, #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.



46
47
48
# File 'lib/arjdbc/jdbc/adapter.rb', line 46

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



125
126
127
# File 'lib/arjdbc/jdbc/adapter.rb', line 125

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


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

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.



100
101
102
# File 'lib/arjdbc/jdbc/adapter.rb', line 100

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



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

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



224
225
226
# File 'lib/arjdbc/jdbc/adapter.rb', line 224

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

#data_source_exists?(name) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#data_sourcesObject



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

def data_sources
  tables
end

#database_nameObject

Returns the underlying database name.



184
185
186
# File 'lib/arjdbc/jdbc/adapter.rb', line 184

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



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

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).



271
272
273
274
275
276
277
278
# File 'lib/arjdbc/jdbc/adapter.rb', line 271

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.



291
292
293
294
295
296
297
298
299
# File 'lib/arjdbc/jdbc/adapter.rb', line 291

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



338
339
340
# File 'lib/arjdbc/jdbc/adapter.rb', line 338

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

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



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

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)


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

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.



60
61
62
# File 'lib/arjdbc/jdbc/adapter.rb', line 60

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.



52
53
54
55
# File 'lib/arjdbc/jdbc/adapter.rb', line 52

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)


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

def last_inserted_id(result)
  if result.is_a?(Hash) || result.is_a?(ActiveRecord::Result)
    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:



165
166
167
# File 'lib/arjdbc/jdbc/adapter.rb', line 165

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



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

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



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

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



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

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

#structure_dumpObject

Abstract adapter default implementation does nothing silently.

Raises:

  • (NotImplementedError)


171
172
173
# File 'lib/arjdbc/jdbc/adapter.rb', line 171

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



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

def supports_foreign_keys?
  @connection.supports_foreign_keys?
end

#supports_migrations?true

JDBC adapters support migration.

Returns:

  • (true)


178
179
180
# File 'lib/arjdbc/jdbc/adapter.rb', line 178

def supports_migrations?
  true
end

#supports_views?Boolean

Returns:

  • (Boolean)


229
230
231
# File 'lib/arjdbc/jdbc/adapter.rb', line 229

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)


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

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

#tables(name = nil) ⇒ Object



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

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



357
358
359
# File 'lib/arjdbc/jdbc/adapter.rb', line 357

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

#valid_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/arjdbc/jdbc/adapter.rb', line 158

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

#write_large_object(*args) ⇒ Object

Deprecated.

Rather use #update_lob_value instead.



350
351
352
# File 'lib/arjdbc/jdbc/adapter.rb', line 350

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