Class: ActiveRecord::ConnectionAdapters::RubyfbAdapter

Inherits:
AbstractAdapter
  • Object
show all
Defined in:
lib/active_record/connection_adapters/rubyfb_adapter.rb

Overview

Usage Notes

Sequence (Generator) Names

The Firebird 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 Firebird 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) OR VALUE IS NULL);

When the Firebird 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 Firebird 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 lines to your environment.rb file:

ActiveRecord::ConnectionAdapters::RubyfbAdapter.boolean_domain[:true] = 'T'
ActiveRecord::ConnectionAdapters::RubyfbAdapter.boolean_domain[:false] = 'F'

Boolean columns are detected by name and domain name patterns configurable by:

ActiveRecord::ConnectionAdapters::RubyfbAdapter.boolean_domain[:domain_pattern], default = /boolean/i
ActiveRecord::ConnectionAdapters::RubyfbAdapter.boolean_domain[:name_pattern], default = /^is_/i

BLOB Elements

The Firebird adapter currently provides only limited support for BLOB columns. You cannot currently retrieve a BLOB as an IO stream. When selecting a BLOB, the entire element is converted into a String. BLOB handling is supported by writing an empty BLOB to the database on insert/update and then executing a second query to save the BLOB.

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 unqouted (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 Firebird Adapter now supports Migrations.

Create/Drop Table and Sequence Generators

Creating or dropping a table will automatically create/drop a correpsonding sequence generator, using the default naming convension. You can specify a different name using the :sequence option; no generator is created if :sequence is set to false.

Rename Table

The Firebird #rename_table Migration should be used with caution. Firebird 1.5 lacks built-in support for this feature, so it is implemented by making a copy of the original table (including column definitions, indexes and data records), and then dropping the original table. Constraints and Triggers are not properly copied, so avoid this method if your original table includes constraints (other than the primary key) or triggers. (Consider manually copying your table or using a view instead.)

Connection Options

The following options are supported by the Rubyfb adapter. None of the options have default values.

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

:host

Set to "remote.host.name" for remote database connections. May be omitted for local connections if a full database path is specified for :database. Some platforms require a value of "localhost" for local connections when using a Firebird database alias.

:service

Specifies a service name for the connection. Only used if :host is provided. Required when connecting to a non-standard service.

:port

Specifies the connection port. Only used if :host is provided and :service is not. Required when connecting to a non-standard port and :service is not defined.

:username

Specifies the database user. May be omitted or set to nil (together with :password) to use the underlying operating system user credentials on supported platforms.

:password

Specifies the database password. Must be provided if :username is explicitly specified; should be omitted if OS user credentials are are being used.

:charset

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

:sql_role_name

Specifies the SQL role name used by the connection.

Direct Known Subclasses

RubyfbAR31Adapter

Constant Summary collapse

TEMP_COLUMN_NAME =
'AR$TEMP_COLUMN'
ADAPTER_NAME =
'Rubyfb'.freeze
IDENTIFIER_MAX_LENGTH =

maximum length of identifiers

30
@@boolean_domain =
{ :name => "d_boolean", :type => "smallint", :true => 1, :false => 0, :domain_pattern=>/boolean/i, :name_pattern=>/^is_/i }

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, logger, connection_params = nil) ⇒ RubyfbAdapter

Returns a new instance of RubyfbAdapter.


328
329
330
331
332
333
334
335
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 328

def initialize(connection, logger, connection_params = nil)
  super(connection, logger)
  @connection_params = connection_params
  @transaction = nil
  @blobs_disabled = 0
  @statements = {}
  @visitor = Arel::Visitors::RubyFB.new self if defined?(Arel::Visitors::RubyFB)
end

Class Method Details

.visitor_for(pool) ⇒ Object

:nodoc:


337
338
339
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 337

def self.visitor_for(pool) # :nodoc:
  Arel::Visitors::RubyFB.new(pool)
end

Instance Method Details

#active?Boolean

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

Returns:

  • (Boolean)

463
464
465
466
467
468
469
470
471
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 463

def active? # :nodoc:
  return false if @connection.closed?
  begin
   execute('select first 1 cast(1 as smallint) from rdb$database')
   true
  rescue
   false
  end
end

#adapter_nameObject

:nodoc:


343
344
345
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 343

def adapter_name #:nodoc:
  ADAPTER_NAME
end

#add_column(table_name, column_name, type, options = {}) ⇒ Object

:nodoc:


752
753
754
755
756
757
758
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 752

def add_column(table_name, column_name, type, options = {}) # :nodoc:
  super
rescue StatementInvalid
  raise unless non_existent_domain_error?
  create_boolean_domain
  super
end

#add_limit_offset!(sql, options) ⇒ Object

:nodoc:


564
565
566
567
568
569
570
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 564

def add_limit_offset!(sql, options) # :nodoc:
  if options[:limit]
    limit_string = "FIRST #{options[:limit]}"
    limit_string << " SKIP #{options[:offset]}" if options[:offset]
    sql.sub!(/\A(\s*SELECT\s)/i, '\&' + limit_string + ' ')
  end
end

#begin_db_transactionObject

:nodoc:


548
549
550
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 548

def begin_db_transaction() # :nodoc:
  @transaction = @connection.start_transaction
end

#change_column(table_name, column_name, type, options = {}) ⇒ Object

:nodoc:


760
761
762
763
764
765
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 760

def change_column(table_name, column_name, type, options = {}) # :nodoc:
  change_column_type(table_name, column_name, type, options)
  change_column_position(table_name, column_name, options[:position]) if options.include?(:position)
  change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
  change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
end

#change_column_default(table_name, column_name, default) ⇒ Object

:nodoc:


767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 767

def change_column_default(table_name, column_name, default) # :nodoc:
  table_name = table_name.to_s.upcase
  sql = <<-end_sql
    UPDATE rdb$relation_fields f1
    SET f1.rdb$default_source =
          (SELECT f2.rdb$default_source FROM rdb$relation_fields f2
           WHERE f2.rdb$relation_name = '#{table_name}'
           AND f2.rdb$field_name = '#{TEMP_COLUMN_NAME}'),
        f1.rdb$default_value =
          (SELECT f2.rdb$default_value FROM rdb$relation_fields f2
           WHERE f2.rdb$relation_name = '#{table_name}'
           AND f2.rdb$field_name = '#{TEMP_COLUMN_NAME}')
    WHERE f1.rdb$relation_name = '#{table_name}'
    AND f1.rdb$field_name = '#{ar_to_fb_case(column_name.to_s)}'
  end_sql
  transaction do
    add_column(table_name, TEMP_COLUMN_NAME, :string, :default => default)
    exec_query(sql)
    remove_column(table_name, TEMP_COLUMN_NAME)
  end
end

#change_column_null(table_name, column_name, null, default = nil) ⇒ Object


789
790
791
792
793
794
795
796
797
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 789

def change_column_null(table_name, column_name, null, default = nil)
  table_name = table_name.to_s.upcase
  column_name = column_name.to_s.upcase

  unless null || default.nil?
    exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
  end
  exec_query("UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = #{null ? 'null' : '1'} WHERE (RDB$FIELD_NAME = '#{column_name}') and (RDB$RELATION_NAME = '#{table_name}')")
end

#clear_cache!Object


502
503
504
505
506
507
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 502

def clear_cache!
  @statements.each_value do |s|
    s.close
  end
  @statements.clear
end

#column_name_lengthObject

the maximum length of a column name


372
373
374
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 372

def column_name_length
  IDENTIFIER_MAX_LENGTH
end

#columns(table_name, name = nil) ⇒ Object

:nodoc:


665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 665

def columns(table_name, name = nil) # :nodoc:
  sql = <<-end_sql
    SELECT r.rdb$field_name, r.rdb$field_source, f.rdb$field_type, f.rdb$field_sub_type,
           COALESCE(f.rdb$character_length, f.rdb$field_length) as rdb$field_length, f.rdb$field_precision, f.rdb$field_scale,
           COALESCE(r.rdb$default_source, f.rdb$default_source) as rdb$default_source,
           COALESCE(r.rdb$null_flag, f.rdb$null_flag) as rdb$null_flag
    FROM rdb$relation_fields r
    JOIN rdb$fields f ON r.rdb$field_source = f.rdb$field_name
    WHERE r.rdb$relation_name = '#{table_name.to_s.upcase}'
    ORDER BY r.rdb$field_position
  end_sql

  select_rows(sql, name).collect do |row|
    field_values = row.collect do |value|
      case value
        when String then value.rstrip
        else value
      end
    end
    FirebirdColumn.new(self, *field_values)
  end
end

#commit_db_transactionObject

:nodoc:


552
553
554
555
556
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 552

def commit_db_transaction() # :nodoc:
  @transaction.commit
ensure
  @transaction = nil
end

#create_table(name, options = {}, &block) ⇒ Object

:nodoc:


711
712
713
714
715
716
717
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 711

def create_table(name, options = {}, &block) # :nodoc:
  create_table_and_sequence(name, options, &block)
rescue StatementInvalid
  raise unless non_existent_domain_error?
  create_boolean_domain
  create_table_and_sequence(name, options, &block)
end

#create_table_and_sequence(name, options = {}, &block) ⇒ Object

:nodoc:


689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 689

def create_table_and_sequence(name, options = {}, &block) # :nodoc:
  create_sequence = options[:id] != false
  table_td = nil
  super_create_table(name, options) do |td|
    unless create_sequence
      class << td
        attr_accessor :create_sequence
        def primary_key(*args)
          self.create_sequence = true
          super(*args)
        end
      end
      table_td = td
    end
    yield td if block_given?            
  end
  if create_sequence || table_td.create_sequence
    sequence_name = options[:sequence] || default_sequence_name(name)
    create_sequence(name, sequence_name)
  end
end

#current_databaseObject

SCHEMA STATEMENTS ========================================


626
627
628
629
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 626

def current_database # :nodoc:
  file = @connection.database.file.split(':').last
  File.basename(file, '.*')
end

#default_sequence_name(table_name, primary_key = nil) ⇒ Object

:nodoc:


410
411
412
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 410

def default_sequence_name(table_name, primary_key = nil) # :nodoc:
  "#{table_name}_seq".upcase
end

#disconnect!Object

:nodoc:


473
474
475
476
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 473

def disconnect! # :nodoc:
  clear_cache!
  @connection.close rescue nil
end

#drop_table(name, options = {}) ⇒ Object

:nodoc:


719
720
721
722
723
724
725
726
727
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 719

def drop_table(name, options = {}) # :nodoc:
  super(name)
  unless options[:sequence] == false
    sequence_name = options[:sequence] || default_sequence_name(name)
    if sequence_exists?(sequence_name)
      drop_sequence(sequence_name) 
    end
  end
end

#dump_schema_informationObject

:nodoc:


829
830
831
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 829

def dump_schema_information # :nodoc:
  super << ";\n"
end

#exec_insert(sql, name, binds) ⇒ Object Also known as: exec_update


537
538
539
540
541
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 537

def exec_insert(sql, name, binds)
  with_blobs_disabled do
    super
  end
end

#exec_query(sql, name = 'SQL', binds = [], &block) ⇒ Object


509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 509

def exec_query(sql, name = 'SQL', binds = [], &block)
  log(sql, name, binds) do
    unless binds.empty?
      cache = @statements[sql]
      binds = binds.map do |col, val|
        type_cast(val, col)
      end
    end
    s = cache || @connection.create_statement(sql)
    s.prepare(@transaction) unless s.prepared?
    
    if Rubyfb::Statement::DDL_STATEMENT == s.type
      clear_cache!
    elsif cache.nil? && !binds.empty?
      @statements[sql] = cache = s
    end
    if name == 'EXPLAIN'
      return s.plan.tap do
        s.close unless cache
      end
    elsif cache
      s.exec(binds, @transaction, &block)
    else
      s.exec_and_close(binds, @transaction, &block)
    end
  end
end

#execute(sql, name = nil, &block) ⇒ Object

:nodoc:


493
494
495
496
497
498
499
500
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 493

def execute(sql, name = nil, &block) # :nodoc:
  exec_result = exec_query(sql, name, [], &block)
  if exec_result.instance_of?(Rubyfb::ResultSet)
    exec_result.close
    exec_result = nil
  end
  return exec_result
end

#execute_procedure(procedure_name, values = {}) ⇒ Object


842
843
844
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 842

def execute_procedure(procedure_name, values={})
  @connection.prepare_call(procedure_name).execute(values, @transaction)
end

#in_clause_lengthObject Also known as: ids_in_list_limit


381
382
383
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 381

def in_clause_length
  1000
end

#index_name(table_name, options) ⇒ Object

returned shortened index name if default is too large (from oracle-enhanced)


730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 730

def index_name(table_name, options) #:nodoc:
  default_name = super(table_name, options).to_s
  # sometimes options can be String or Array with column names
  options = {} unless options.is_a?(Hash)
  identifier_max_length = options[:identifier_max_length] || index_name_length
  return default_name if default_name.length <= identifier_max_length
  
  # remove 'index', 'on' and 'and' keywords
  shortened_name = "i_#{table_name}_#{Array(options[:column]) * '_'}"
  
  # leave just first three letters from each word
  if shortened_name.length > identifier_max_length
    shortened_name = shortened_name.split('_').map{|w| w[0,3]}.join('_')
  end
  # generate unique name using hash function
  if shortened_name.length > identifier_max_length
    shortened_name = 'i'+Digest::SHA1.hexdigest(default_name)[0,identifier_max_length-1]
  end
  @logger.warn "#{adapter_name} shortened default index name #{default_name} to #{shortened_name}" if @logger
  shortened_name
end

#index_name_lengthObject

the maximum length of an index name


377
378
379
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 377

def index_name_length
  IDENTIFIER_MAX_LENGTH
end

#indexes(table_name, name = nil) ⇒ Object

:nodoc:


655
656
657
658
659
660
661
662
663
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 655

def indexes(table_name, name = nil) # :nodoc:
  (table_name, false, name).inject([]) do |indexes, row|
    if indexes.empty? or indexes.last.name != row[0]
      indexes << IndexDefinition.new(table_name, row[0].rstrip.downcase, row[1] == 1, [])
    end
    indexes.last.columns << row[2].rstrip.downcase
    indexes
  end
end

#insert_fixture(fixture, table_name) ⇒ Object

Inserts the given fixture into the table. Overridden to properly handle blobs.


580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 580

def insert_fixture(fixture, table_name) #:nodoc:
  if ActiveRecord::Base.pluralize_table_names
    klass = table_name.singularize.camelize
  else
    klass = table_name.camelize
  end
  klass = klass.constantize rescue nil
  if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base)
    with_blobs_disabled do
      super
    end
    write_blobs(table_name, klass, fixture, false)
  else
    super
  end
end

#last_inserted_id(result) ⇒ Object


544
545
546
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 544

def last_inserted_id(result)
  nil #TODO
end

#native_database_typesObject

:nodoc:


386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 386

def native_database_types # :nodoc:
  {
    :primary_key => "BIGINT NOT NULL PRIMARY KEY",
    :string      => { :name => "varchar", :limit => 255 },
    :text        => { :name => "blob sub_type text" },
    :integer     => { :name => "bigint" },
    :decimal     => { :name => "decimal" },
    :numeric     => { :name => "numeric" },
    :float       => { :name => "float" },
    :datetime    => { :name => "timestamp" },
    :timestamp   => { :name => "timestamp" },
    :time        => { :name => "time" },
    :date        => { :name => "date" },
    :binary      => { :name => "blob sub_type 0" },
    :boolean     => boolean_domain
  }
end

#next_sequence_value(sequence_name) ⇒ Object

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


575
576
577
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 575

def next_sequence_value(sequence_name)
  Rubyfb::Generator.new(quote_generator_name(sequence_name), @connection).next(1, @transaction)
end

#prefetch_primary_key?(table_name = nil) ⇒ Boolean

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

Returns:

  • (Boolean)

406
407
408
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 406

def prefetch_primary_key?(table_name = nil)
  true
end

#primary_key(table_name) ⇒ Object


649
650
651
652
653
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 649

def primary_key(table_name)
  if pk_row = (table_name, true).to_a.first
		pk_row[2].rstrip.downcase
  end
end

#quote(value, column = nil) ⇒ Object

We use quoting in order to implement BLOB handling. In order to do this we quote a BLOB to an empty string which will force Firebird to create an empty BLOB in the db for us.


420
421
422
423
424
425
426
427
428
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 420

def quote(value, column = nil) # :nodoc:
  if [Date, Time].include?(value.class)
    "CAST('#{type_cast(value, column).to_s(:db)}' AS #{value.acts_like?(:time) ? 'TIMESTAMP' : 'DATE'})"
  elsif @blobs_disabled.nonzero? && value && column && [:text, :binary].include?(column.type)
    "''"
  else
    super
  end
end

#quote_column_name(column_name) ⇒ Object

:nodoc:


434
435
436
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 434

def quote_column_name(column_name) # :nodoc:
  %Q("#{ar_to_fb_case(column_name.to_s)}")
end

#quote_string(string) ⇒ Object

:nodoc:


430
431
432
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 430

def quote_string(string) # :nodoc:
  string.gsub(/'/, "''")
end

#quoted_falseObject

:nodoc:


442
443
444
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 442

def quoted_false # :nodoc:
  quote(boolean_domain[:false])
end

#quoted_trueObject

:nodoc:


438
439
440
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 438

def quoted_true # :nodoc:
  quote(boolean_domain[:true])
end

#reconnect!Object

:nodoc:


483
484
485
486
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 483

def reconnect! # :nodoc:
  disconnect!
  @connection = @connection.database.connect(*@connection_params)
end

#recreate_database!Object

:nodoc:


631
632
633
634
635
636
637
638
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 631

def recreate_database! # :nodoc:
  sql = "SELECT rdb$character_set_name FROM rdb$database"
  charset = select_rows(sql).first[0].rstrip
  disconnect!
  @connection.database.drop(*@connection_params)
  Rubyfb::Database.create(@connection.database.file,
    @connection_params[0], @connection_params[1], 4096, charset)
end

#remove_index(table_name, options) ⇒ Object

:nodoc:


803
804
805
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 803

def remove_index(table_name, options) #:nodoc:
  exec_query("DROP INDEX #{quote_column_name(index_name(table_name, options))}")
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object

:nodoc:


799
800
801
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 799

def rename_column(table_name, column_name, new_column_name) # :nodoc:
  exec_query("ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}")
end

#rename_table(name, new_name) ⇒ Object

:nodoc:


807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 807

def rename_table(name, new_name) # :nodoc:
  if table_has_constraints_or_dependencies?(name)
    raise ActiveRecordError,
      "Table #{name} includes constraints or dependencies that are not supported by " <<
      "the Firebird rename_table migration. Try explicitly removing the constraints/" <<
      "dependencies first, or manually renaming the table."
  end

  transaction do
    copy_table(name, new_name)
    copy_table_indexes(name, new_name)
  end
  begin
    copy_table_data(name, new_name)
    copy_sequence_value(name, new_name)
  rescue
    drop_table(new_name)
    raise
  end
  drop_table(name)
end

#reset!Object


478
479
480
481
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 478

def reset!
  clear_cache!
  super
end

#rollback_db_transactionObject

:nodoc:


558
559
560
561
562
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 558

def rollback_db_transaction() # :nodoc:
  @transaction.rollback
ensure
  @transaction = nil
end

#select_rows(sql, name = nil) ⇒ Object

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


489
490
491
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 489

def select_rows(sql, name = nil)
  select_raw(sql, name).last
end

#super_create_tableObject


688
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 688

alias_method :super_create_table, :create_table

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)

355
356
357
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 355

def supports_ddl_transactions?
  true
end

#supports_migrations?Boolean

:nodoc:

Returns:

  • (Boolean)

347
348
349
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 347

def supports_migrations? #:nodoc:
  true
end

#supports_statement_cache?Boolean

Returns:

  • (Boolean)

351
352
353
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 351

def supports_statement_cache?
  true
end

#table_alias_lengthObject

:nodoc:


362
363
364
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 362

def table_alias_length #:nodoc:
  IDENTIFIER_MAX_LENGTH
end

#table_exists?(table_name) ⇒ Boolean

Returns:

  • (Boolean)

645
646
647
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 645

def table_exists?(table_name)
  super(table_name.to_s.downcase)
end

#table_name_lengthObject

the maximum length of a table name


367
368
369
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 367

def table_name_length
  IDENTIFIER_MAX_LENGTH
end

#tables(name = nil) ⇒ Object

:nodoc:


640
641
642
643
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 640

def tables(name = nil) # :nodoc:
  sql = "SELECT rdb$relation_name FROM rdb$relations WHERE rdb$system_flag = 0"
  select_rows(sql, name).collect { |row| row[0].rstrip.downcase }
end

#type_cast(value, column) ⇒ Object


446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 446

def type_cast(value, column)
  case value
    when true, false
      value ? boolean_domain[:true] : boolean_domain[:false]
    when Date, Time
      if value.acts_like?(:time)
        zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
        value = value.send(zone_conversion_method) if value.respond_to?(zone_conversion_method)
      else
        value
      end          
    else
      super
  end
end

#type_to_sql(type, limit = nil, precision = nil, scale = nil) ⇒ Object

:nodoc:


833
834
835
836
837
838
839
840
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 833

def type_to_sql(type, limit = nil, precision = nil, scale = nil) # :nodoc:
  case type
    when :integer then integer_sql_type(limit)
    when :float   then float_sql_type(limit)
    when :string  then super(type, limit, precision, scale)
    else super(type, limit, precision, scale)
  end
end

#write_blobs(table_name, klass, attributes, enable_coders) ⇒ Object

Writes BLOB values from attributes, as indicated by the BLOB columns of klass.


598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
# File 'lib/active_record/connection_adapters/rubyfb_adapter.rb', line 598

def write_blobs(table_name, klass, attributes, enable_coders) #:nodoc:
  # is class with composite primary key>
  is_with_cpk = klass.respond_to?(:composite?) && klass.composite?
  if is_with_cpk
    id = klass.primary_key.map {|pk| attributes[pk.to_s] }
  else
    id = quote(attributes[klass.primary_key])
  end
  klass.columns.select { |col| col.sql_type =~ /BLOB$/i }.each do |col|
    value = attributes[col.name]
    next if value.nil?  || (value == '')

    klass.serialized_attributes[col.name].tap do |coder|
      if enable_coders && coder
        value = dump_blob_value(col, coder, value)
      elsif value.respond_to?(:read)
        value = value.read
      end
    end
    uncached do
      sql = is_with_cpk ? "UPDATE #{quote_table_name(table_name)} set #{quote_column_name(col.name)} = ? WHERE #{klass.composite_where_clause(id)}" :
        "UPDATE #{quote_table_name(table_name)} set #{quote_column_name(col.name)} = ? WHERE #{quote_column_name(klass.primary_key)} = #{id}"
      @connection.execute_for(sql, [value.to_s], @transaction)
    end
  end
end