class ActiveRecord::ConnectionAdapters::FbAdapter

The Fb adapter relies on the Fb extension.

Usage Notes

Sequence (Generator) Names

The Fb adapter supports the same approach adopted for the Oracle adapter. See ActiveRecord::Base#set_sequence_name for more details.

Note that in general there is no need to create a BEFORE INSERT trigger corresponding to a Firebird sequence generator when using ActiveRecord. In other words, you don’t have to try to make Firebird simulate an AUTO_INCREMENT or IDENTITY column. When saving a new record, ActiveRecord pre-fetches the next sequence value for the table and explicitly includes it in the INSERT statement. (Pre-fetching the next primary key value is the only reliable method for the Fb adapter to report back the id after a successful insert.)

BOOLEAN Domain

Firebird 1.5 does not provide a native BOOLEAN type. But you can easily define a BOOLEAN domain for this purpose, e.g.:

CREATE DOMAIN D_BOOLEAN AS SMALLINT CHECK (VALUE IN (0, 1));

When the Fb adapter encounters a column that is based on a domain that includes “BOOLEAN” in the domain name, it will attempt to treat the column as a BOOLEAN.

By default, the Fb adapter will assume that the BOOLEAN domain is defined as above. This can be modified if needed. For example, if you have a legacy schema with the following BOOLEAN domain defined:

CREATE DOMAIN BOOLEAN AS CHAR(1) CHECK (VALUE IN ('T', 'F'));

…you can add the following line to your environment.rb file:

ActiveRecord::ConnectionAdapters::Fb.boolean_domain = { :true => 'T', :false => 'F' }

Column Name Case Semantics

Firebird and ActiveRecord have somewhat conflicting case semantics for column names.

Firebird

The standard practice is to use unquoted column names, which can be thought of as case-insensitive. (In fact, Firebird converts them to uppercase.) Quoted column names (not typically used) are case-sensitive.

ActiveRecord

Attribute accessors corresponding to column names are case-sensitive. The defaults for primary key and inheritance columns are lowercase, and in general, people use lowercase attribute names.

In order to map between the differing semantics in a way that conforms to common usage for both Firebird and ActiveRecord, uppercase column names in Firebird are converted to lowercase attribute names in ActiveRecord, and vice-versa. Mixed-case column names retain their case in both directions. Lowercase (quoted) Firebird column names are not supported. This is similar to the solutions adopted by other adapters.

In general, the best approach is to use unquoted (case-insensitive) column names in your Firebird DDL (or if you must quote, use uppercase column names). These will correspond to lowercase attributes in ActiveRecord.

For example, a Firebird table based on the following DDL:

CREATE TABLE products (
  id BIGINT NOT NULL PRIMARY KEY,
  "TYPE" VARCHAR(50),
  name VARCHAR(255) );

…will correspond to an ActiveRecord model class called Product with the following attributes: id, type, name.

Quoting "TYPE" and other Firebird reserved words:

In ActiveRecord, the default inheritance column name is type. The word type is a Firebird reserved word, so it must be quoted in any Firebird SQL statements. Because of the case mapping described above, you should always reference this column using quoted-uppercase syntax ("TYPE") within Firebird DDL or other SQL statements (as in the example above). This holds true for any other Firebird reserved words used as column names as well.

Migrations

The Fb adapter does not currently support Migrations.

Connection Options

The following options are supported by the Fb adapter.

:database

Required option. Specifies one of: (i) a Firebird database alias; (ii) the full path of a database file; or (iii) a full Firebird connection string. Do not specify :host, :service or :port as separate options when using a full connection string.

:username

Specifies the database user. Defaults to ‘sysdba’.

:password

Specifies the database password. Defaults to ‘masterkey’.

:charset

Specifies the character set to be used by the connection. Refer to the Firebird documentation for valid options.

Public Class Methods

new(connection, logger, connection_params=nil) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 195
def initialize(connection, logger, connection_params=nil)
  super(connection, logger)
  @connection_params = connection_params
end

Public Instance Methods

active?() click to toggle source

CONNECTION MANAGEMENT ====================================

# File lib/active_record/connection_adapters/fb_adapter.rb, line 274
def active?
  @connection.open?
end
disconnect!() click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 278
def disconnect!
  @connection.close rescue nil
end
expand(sql, args) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 302
def expand(sql, args)
  sql + ', ' + args * ', '
end
log(sql, args, name, &block) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 306
def log(sql, args, name, &block)
  super(expand(sql, args), name, &block)
end
native_database_types() click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 426
def native_database_types
  {
    :primary_key => "integer not null primary key",
    :string      => { :name => "varchar", :limit => 255 },
    :text        => { :name => "blob sub_type text" },
    :integer     => { :name => "integer" },
    :float       => { :name => "float" },
    :decimal     => { :name => "decimal" },
    :datetime    => { :name => "timestamp" },
    :timestamp   => { :name => "timestamp" },
    :time        => { :name => "time" },
    :date        => { :name => "date" },
    :binary      => { :name => "blob" },
    :boolean     => { :name => "integer" }
  }
end
next_sequence_value(sequence_name) click to toggle source

Returns the next sequence value from a sequence generator. Not generally called directly; used by ActiveRecord to get the next primary key value when inserting a new database record (see prefetch_primary_key?).

# File lib/active_record/connection_adapters/fb_adapter.rb, line 372
def next_sequence_value(sequence_name)
  select_one("SELECT GEN_ID(#{sequence_name}, 1) FROM RDB$DATABASE", nil, :array).first
end
prefetch_primary_key?(table_name = nil) click to toggle source

Returns true for Fb adapter (since Firebird requires primary key values to be pre-fetched before insert). See also next_sequence_value.

# File lib/active_record/connection_adapters/fb_adapter.rb, line 206
def prefetch_primary_key?(table_name = nil)
  true
end
quote_date(value) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 237
def quote_date(value)
  "@#{Base64.encode64(value.strftime('%Y-%m-%d')).chop}@"
end
quote_number(value) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 232
def quote_number(value)
  # "@#{Base64.encode64(value.to_s).chop}@"
  value.to_s
end
quote_object(obj) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 249
def quote_object(obj)
  if obj.respond_to?(:quoted_id)
    obj.quoted_id
  elsif obj.respond_to?(:to_str)
    "@#{Base64.encode64(obj.to_str).chop}@"
  else
    "@#{Base64.encode64(obj.to_yaml).chop}@"
  end
end
quote_timestamp(value) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 241
def quote_timestamp(value)
  "@#{Base64.encode64(value.strftime('%Y-%m-%d %H:%M:%S')).chop}@"
end
reconnect!() click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 282
def reconnect!
  disconnect!
  @connection = Fb::Database.connect(@connection_params)
end
remove_index(table_name, options = {}) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 418
def remove_index(table_name, options = {})
  execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
end
rename_column(table_name, column_name, new_column_name) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 414
def rename_column(table_name, column_name, new_column_name)
  execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} TO #{new_column_name}"
end
supports_migrations?() click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 422
def supports_migrations?
  false
end
table_alias_length() click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 410
def table_alias_length
  255
end
tables(name = nil) click to toggle source
# File lib/active_record/connection_adapters/fb_adapter.rb, line 400
def tables(name = nil)
  @connection.table_names.map {|t| t.downcase }
end
translate(sql) { |sql, args| ... } click to toggle source

DATABASE STATEMENTS ======================================

# File lib/active_record/connection_adapters/fb_adapter.rb, line 289
def translate(sql)
  sql.gsub!(%r\bIN\s+\(NULL\)/, 'IS NULL')
  sql.sub!(%r\bWHERE\s.*$/m) do |m|
    m.gsub(%r\s=\s*NULL\b/, ' IS NULL')
  end
  sql.gsub!(%r\sIN\s+\([^\)]*\)/i) do |m|
    m.gsub(%r\(([^\)]*)\)/) { |n| n.gsub(%r\@(.*?)\@/) { |n| "'#{quote_string(Base64.decode64(n[1..-1]))}'" } }
  end
  args = []
  sql.gsub!(%r\@(.*?)\@/) { |m| args << Base64.decode64(m[1..-1]); '?' }
  yield(sql, args) if block_given?
end