Class: ActiveRecord::ConnectionAdapters::IBM_DBAdapter

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

Overview

The IBM_DB Adapter requires the native Ruby driver (ibm_db) for IBM data servers (ibm_db.so). config the hash passed as an initializer argument content:

mandatory parameters

adapter:     'ibm_db'        // IBM_DB Adapter name
username:    'db2user'       // data server (database) user
password:    'secret'        // data server (database) password
database:    'ARUNIT'        // remote database name (or catalog entry alias)

optional (highly recommended for data server auditing and monitoring purposes)

schema:      'rails123'      // name space qualifier
account:     'tester'        // OS account (client workstation)
app_user:    'test11'        // authenticated application user
application: 'rtests'        // application name
workstation: 'plato'         // client workstation name

remote TCP/IP connection (required when no local database catalog entry available)

host:        'socrates'      // fully qualified hostname or IP address
port:        '50000'         // data server TCP/IP port number

When schema is not specified, the username value is used instead.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, logger, config, conn_options) ⇒ IBM_DBAdapter

Returns a new instance of IBM_DBAdapter.



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
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 301

def initialize(connection, logger, config, conn_options)
  # Caching database connection configuration (+connect+ or +reconnect+ support)
  @connection = connection
  @conn_options = conn_options
  @database = config[:database]
  @username = config[:username]
  @password = config[:password]
  if config.has_key?(:host)
    @host   = config[:host]
    @port   = config[:port] || 50000 # default port
  end
  @schema   = config[:schema]

  # Caching database connection options (auditing and billing support)
  @app_user    = conn_options[:app_user]     if conn_options.has_key?(:app_user)
  @account     = conn_options[:account]      if conn_options.has_key?(:account)
  @application = conn_options[:application]  if conn_options.has_key?(:application)
  @workstation = conn_options[:workstation]  if conn_options.has_key?(:workstation)

  # Calls the parent class +ConnectionAdapters+' initializer
  # which sets @connection, @logger, @runtime and @last_verification
  super(@connection, logger)

  if @connection
    server_info = IBM_DB::server_info( @connection )
    case server_info.DBMS_NAME
      when /DB2\//i             # DB2 for Linux, Unix and Windows (LUW)
        @servertype = IBM_DB2_LUW.new(self)
      when /DB2/i               # DB2 for zOS
        case server_info.DBMS_VER
          when /09/             # DB2 for zOS version 9
            @servertype = IBM_DB2_ZOS.new(self)
          when /08/             # DB2 for zOS version 8
            @servertype = IBM_DB2_ZOS_8.new(self)
          else                  # DB2 for zOS version 7
            raise "Only DB2 z/OS version 8 and above are currently supported"
        end
      when /AS/i                # DB2 for i5 (iSeries)
        @servertype = IBM_DB2_I5.new(self)
      when /IDS/i               # Informix Dynamic Server
        @servertype = IBM_IDS.new(self)
    end
  end

  # Executes the +set schema+ statement using the schema identifier provided
  @servertype.set_schema(@schema) if @schema && @schema != @username
end

Instance Attribute Details

#accountObject

Returns the value of attribute account.



294
295
296
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 294

def 
  @account
end

#app_userObject

Returns the value of attribute app_user.



294
295
296
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 294

def app_user
  @app_user
end

#applicationObject

Returns the value of attribute application.



294
295
296
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 294

def application
  @application
end

#connectionObject (readonly)

Returns the value of attribute connection.



292
293
294
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 292

def connection
  @connection
end

#schemaObject

Returns the value of attribute schema.



294
295
296
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 294

def schema
  @schema
end

#servertypeObject (readonly)

Returns the value of attribute servertype.



292
293
294
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 292

def servertype
  @servertype
end

#sqlObject

Returns the value of attribute sql.



293
294
295
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 293

def sql
  @sql
end

#workstationObject

Returns the value of attribute workstation.



294
295
296
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 294

def workstation
  @workstation
end

Instance Method Details

#active?Boolean

Tests the connection status

Returns:

  • (Boolean)


416
417
418
419
420
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 416

def active?
  IBM_DB::active @connection
  rescue
    false
end

#adapter_nameObject

Name of the adapter



297
298
299
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 297

def adapter_name
  'IBM_DB'
end

#add_limit_offset!(sql, options) ⇒ Object

Modifies a sql statement in order to implement a LIMIT and an OFFSET. A LIMIT defines the number of rows that should be fetched, while an OFFSET defines from what row the records must be fetched. IBM data servers implement a LIMIT in SQL statements through: FETCH FIRST n ROWS ONLY, where n is the number of rows required. The implementation of OFFSET is more elaborate, and requires the usage of subqueries and the ROW_NUMBER() command in order to add row numbering as an additional column to a copy of the existing table.

Examples

add_limit_offset!(‘SELECT * FROM staff’, => 10) generates: “SELECT * FROM staff FETCH FIRST 10 ROWS ONLY”

add_limit_offset!(‘SELECT * FROM staff’, => 10, :offset => 30) generates “SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_rownum FROM (SELECT * FROM staff) AS I) AS O WHERE sys_row_num BETWEEN 31 AND 40”



597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 597

def add_limit_offset!(sql, options)
  # If there is a limit
  if limit = options[:limit]
    # if the limit is zero
    if limit == 0
      # Returns a query that will always generate zero records
      # (e.g. WHERE sys_row_num BETWEEN 1 and 0)
      sql = @servertype.query_offset_limit(sql, 0, limit)
    # If there is a non-zero limit
    else
      offset = options[:offset]
      # If an offset is specified builds the query with offset and limit,
      # otherwise retrieves only the first +limit+ rows
      sql = @servertype.query_offset_limit(sql, offset, limit)
    end
  end
  # Returns the sql query in any case
  sql
end

#begin_db_transactionObject

Begins the transaction (and turns off auto-committing)



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

def begin_db_transaction
  # Turns off the auto-commit
  IBM_DB::autocommit(@connection, IBM_DB::SQL_AUTOCOMMIT_OFF)
end

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

Changes the column’s definition according to the new options. See TableDefinition#column for details of the options you can use.

Examples
change_column(:suppliers, :name, :string, :limit => 80)
change_column(:accounts, :description, :text)


931
932
933
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 931

def change_column(table_name, column_name, type, options = {})
  @servertype.change_column(table_name, column_name, type, options)
end

#change_column_default(table_name, column_name, default) ⇒ Object

Sets a new default value for a column. This does not set the default value to NULL, instead, it needs DatabaseStatements#execute which can execute the appropriate SQL statement for setting the value.

Examples

change_column_default(:suppliers, :qualification, 'new')
change_column_default(:accounts, :authorized, 1)

Method overriden to satisfy IBM data servers syntax.



942
943
944
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 942

def change_column_default(table_name, column_name, default)
  @servertype.change_column_default(table_name, column_name, default)
end

#columns(table_name, name = nil) ⇒ Object

Returns an array of Column objects for the table specified by table_name



824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 824

def columns(table_name, name = nil)
  # to_s required because it may be a symbol.
  table_name = @servertype.set_case(table_name.to_s)
  # Checks if a blank table name has been given.
  # If so it returns an empty array
  return [] if table_name.strip.empty?
  # +columns+ will contain the resulting array
  columns = []
  # Statement required to access all the columns information
  if stmt = IBM_DB::columns( @connection, nil, 
                             @servertype.set_case(@schema), 
                             @servertype.set_case(table_name) )
    begin
      # Fetches all the columns and assigns them to col.
      # +col+ is an hash with keys/value pairs for a column
      while col = IBM_DB::fetch_assoc(stmt)
        column_name = col["column_name"].downcase
        # Assigns the column default value.
        column_default_value = col["column_def"]
        # If there is no default value, it assigns NIL
        column_default_value = nil if (column_default_value && column_default_value.upcase == 'NULL')
        # Removes single quotes from the default value
        column_default_value.gsub!(/^'(.*)'$/, '\1') unless column_default_value.nil?
        # Assigns the column type
        column_type = col["type_name"].downcase
        # Assigns the field length (size) for the column
        column_length = col["column_size"]
        column_scale = col["decimal_digits"]
        # The initializer of the class Column, requires the +column_length+ to be declared 
        # between brackets after the datatype(e.g VARCHAR(50)) for :string and :text types. 
        # If it's a "for bit data" field it does a subsitution in place, if not
        # it appends the (column_length) string on the supported data types
        unless column_length.nil? || 
               column_length == '' || 
               column_type.sub!(/ \(\) for bit data/i,"(#{column_length}) FOR BIT DATA") || 
               !column_type =~ /char|lob|graphic/i
          if column_type =~ /decimal/i
            column_type << "(#{column_length},#{column_scale})"
          elsif column_type =~ /smallint|integer|double|date|time|timestamp|xml/i
            column_type << ""  # override native limits incompatible with table create
          else
            column_type << "(#{column_length})"
          end
        end
        # col["NULLABLE"] is 1 if the field is nullable, 0 if not.
        column_nullable = (col["nullable"] == 1) ? true : false
        # Make sure the hidden column (db2_generated_rowid_for_lobs) in DB2 z/OS isn't added to the list
        if !(column_name =~ /db2_generated_rowid_for_lobs/i)
          # Pushes into the array the *IBM_DBColumn* object, created by passing to the initializer
          # +column_name+, +default_value+, +column_type+ and +column_nullable+.
          columns << IBM_DBColumn.new(column_name, column_default_value, column_type, column_nullable)
        end
      end
    rescue StandardError  # Handle driver fetch errors
      error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
      if error_msg && !error_msg.empty?
        raise "Failed to retrieve column metadata during fetch: #{error_msg}"
      else
        raise
      end
    ensure  # Free resources associated with the statement
      IBM_DB::free_result(stmt)
    end
  else  # Handle driver execution errors
    error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
    if error_msg && !error_msg.empty?
      raise "Failed to retrieve column metadata due to error: #{error_msg}"
    else
      raise StandardError('Unexpected error during columns metadata retrieval')
    end
  end
  # Returns the columns array
  return columns
end

#commit_db_transactionObject

Commits the transaction and turns on auto-committing



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

def commit_db_transaction
  # Commits the transaction
  IBM_DB::commit @connection rescue nil
  # Turns on auto-committing
  IBM_DB::autocommit @connection, IBM_DB::SQL_AUTOCOMMIT_ON
end

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

DATABASE STATEMENTS



466
467
468
469
470
471
472
473
474
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 466

def create_table(name, options = {})
  @servertype.setup_for_lob_table
  super
  # force implicit id column (primary key) unless :id => false
  unless !options[:id].nil? and
         !options[:id]
    @servertype.create_index_after_table(name)
  end
end

#default_sequence_name(table, column) ⇒ Object

method add_limit_offset!



617
618
619
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 617

def default_sequence_name(table, column) # :nodoc:
  "#{table}_#{column}_seq"
end

#disconnect!Object

Closes the current connection



454
455
456
457
458
459
460
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 454

def disconnect!
  # Attempts to close the connection. The methods will return:
  # * true if succesfull
  # * false if the connection is already closed
  # * nil if an error is raised
  IBM_DB::close(@connection) rescue nil
end

#execute(sql, name = nil) ⇒ Object

Executes and logs sql commands and returns a IBM_DB::Statement object.



523
524
525
526
527
528
529
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 523

def execute(sql, name = nil)
  # Logs and execute the sql instructions.
  # The +log+ method is defined in the parent class +AbstractAdapter+
  log(sql, name) do
    @servertype.execute(sql, name)
  end
end

#indexes(table_name, name = nil) ⇒ Object

Returns an array of non-primary key indexes for a specified table name



778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 778

def indexes(table_name, name = nil)
  # to_s required because +table_name+ may be a symbol.
  table_name = table_name.to_s
  # Checks if a blank table name has been given.
  # If so it returns an empty array of columns.
  return [] if table_name.strip.empty?

  # +indexes+ will contain the resulting array
  indexes = []
  # Query table statistics for all indexes on the table
  # "TABLE_NAME:   #{index_stats[2]}"
  # "NON_UNIQUE:   #{index_stats[3]}"
  # "INDEX_NAME:   #{index_stats[5]}"
  # "COLUMN_NAME:  #{index_stats[8]}"
  if stmt = IBM_DB::statistics( @connection, nil, 
                                @servertype.set_case(@schema), 
                                @servertype.set_case(table_name), 1 )
    begin
      while ( index_stats = IBM_DB::fetch_array(stmt) )
        if index_stats[5]                                          # INDEX_NAME
          index_name = index_stats[5].downcase
          # Non-unique index type (not the primary key)
          unless index_stats[3] == 0                               # NON_UNIQUE
            index_unique = (index_stats[3] == 0)
            index_columns = index_stats[8].map{|c| c.downcase}     # COLUMN_NAME
            # Create an IndexDefinition object and add to the indexes array
            indexes << IndexDefinition.new(table_name, index_name, index_unique, index_columns)
          end
        end
      end
    ensure  # Free resources associated with the statement
      IBM_DB::free_result(stmt) if stmt
    end
  else  # Handle driver execution errors
    error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
    if error_msg && !error_msg.empty?
      raise "Failed to retrieve index metadata due to error: #{error_msg}"
    else
      raise StandardError('Unexpected error during index retrieval')
    end
  end
  # Returns the indexes array
  return indexes
end

#insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) ⇒ Object

Perform an insert and returns the last ID generated. This can be the ID passed to the method or the one auto-generated by the database, and retrieved by the last_generated_id method.



509
510
511
512
513
514
515
516
517
518
519
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 509

def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
  if stmt = execute(sql, name)
    begin
      @sql = sql
      return id_value || @servertype.last_generated_id(stmt)
      # Ensures to free the resources associated with the statement
    ensure
      IBM_DB::free_result(stmt)
    end
  end
end

#log_query(sql, name) ⇒ Object

:nodoc:



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

def log_query(sql, name) #:nodoc:
  # Used by handle_lobs
  log(sql,name){}
end

#native_database_typesObject

Returns a Hash of mappings from the abstract data types to the native database types



704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 704

def native_database_types
  {
    :primary_key => @servertype.primary_key,
    :string      => { :name => "varchar", :limit => 255 },
    :text        => { :name => "clob" },
    :integer     => { :name => "integer" },
    :float       => { :name => "float" },
    :datetime    => { :name => @servertype.get_datetime_mapping },
    :timestamp   => { :name => @servertype.get_datetime_mapping },
    :time        => { :name => @servertype.get_time_mapping },
    :date        => { :name => "date" },
    :binary      => { :name => "blob" },

    # IBM data servers don't have a native boolean type.
    # A boolean can be represented  by a smallint,
    # adopting the convention that False is 0 and True is 1
    :boolean     => { :name => "smallint"},
    :xml         => { :name => "xml"},
    :decimal     => { :name => "decimal" },
    :rowid       => { :name => "rowid" }, # rowid is a supported datatype on z/OS and i/5
    :serial      => { :name => "serial" } # rowid is a supported datatype on Informix Dynamic Server
  }
end

#quote(value, column = nil) ⇒ Object

Properly quotes the various data types. value contains the data, column is optional and contains info on the field



628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 628

def quote(value, column = nil)
  case value
    # If it's a numeric value and the column type is not a string, it shouldn't be quoted
    # (IBM_DB doesn't accept quotes on numeric types)
    when Numeric
      # If the column type is text or string, return the quote value
      if column && column.type == :text || column && column.type == :string
        "'#{value}'"
      else
        # value is Numeric, column.type is not a string,
        # therefore it converts the number to string without quoting it
        value.to_s
      end
    when String, ActiveSupport::Multibyte::Chars
    if column && column.type == :binary
      # If quoting is required for the insert/update of a BLOB
      unless caller[0] =~ /add_column_options/i
        # Invokes a convertion from string to binary
          @servertype.set_binary_value
      else
        # Quoting required for the default value of a column
          @servertype.set_binary_default(value)
        end
    elsif column && column.type == :text
        unless caller[0] =~ /add_column_options/i
          "'@@@IBMTEXT@@@'"
        else
          @servertype.set_text_default(value)
        end
    elsif column && column.type == :xml
        unless caller[0] =~ /add_column_options/i
          "'<ibm>@@@IBMXML@@@</ibm>'"
        else
          "#{value}"
        end
    else
      "'#{quote_string(value)}'"
    end
    when TrueClass then quoted_true    # return '1' for true
    when FalseClass then quoted_false  # return '0' for false
    when NilClass
      if column && column.instance_of?(IBM_DBColumn) && !column.primary && !column.null
        "''"                           # allow empty inserts if not nullable or identity
      else                             # in order to support default ActiveRecord constructors
        "NULL"
      end
    else super                         # rely on superclass handling
  end
end

#quote_column_name(name) ⇒ Object



694
695
696
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 694

def quote_column_name(name)
   @servertype.check_reserved_words(name)
end

#quote_string(string) ⇒ Object

Quotes a given string, escaping single quote (‘) characters.



679
680
681
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 679

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

#quoted_falseObject



690
691
692
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 690

def quoted_false
  "0"
end

#quoted_trueObject

true is represented by a smallint 1, false by 0, as no native boolean type exists in DB2. Numerics are not quoted in DB2.



686
687
688
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 686

def quoted_true
  "1"
end

#reconnect!Object

Closes the current connection and opens a new one



448
449
450
451
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 448

def reconnect!
  disconnect!
  connect
end

#remove_column(table_name, column_name) ⇒ Object

Removes the column from the table definition.

Examples
remove_column(:suppliers, :qualification)


922
923
924
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 922

def remove_column(table_name, column_name)
  @servertype.remove_column(table_name, column_name)
end

#remove_index(table_name, options = {}) ⇒ Object

Remove the given index from the table.

Remove the suppliers_name_index in the suppliers table (legacy support, use the second or third forms).

remove_index :suppliers, :name

Remove the index named accounts_branch_id in the accounts table.

remove_index :accounts, :column => :branch_id

Remove the index named by_branch_party in the accounts table.

remove_index :accounts, :name => :by_branch_party

You can remove an index on multiple columns by specifying the first column.

add_index :accounts, [:username, :password]
remove_index :accounts, :username

Overriden to use the IBM data servers SQL syntax.



959
960
961
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 959

def remove_index(table_name, options = {})
  execute("DROP INDEX #{index_name(table_name, options)}")
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object

Renames a column.

Example
rename_column(:suppliers, :description, :name)


915
916
917
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 915

def rename_column(table_name, column_name, new_column_name)
  @servertype.rename_column(table_name, column_name, new_column_name)
end

#rename_table(name, new_name) ⇒ Object

Renames a table.

Example

rename_table(‘octopuses’, ‘octopi’) Overriden to satisfy IBM data servers syntax



903
904
905
906
907
908
909
910
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 903

def rename_table(name, new_name)
  # SQL rename table statement
  rename_table_sql = "RENAME TABLE #{name} TO #{new_name}"
  stmt = execute(rename_table_sql)
  # Ensures to free the resources associated with the statement
  ensure
    IBM_DB::free_result stmt if stmt
end

#rollback_db_transactionObject

Rolls back the transaction and turns on auto-committing. Must be done if the transaction block raises an exception or returns false



574
575
576
577
578
579
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 574

def rollback_db_transaction
  # ROLLBACK the transaction
  IBM_DB::rollback(@connection) rescue nil
  # Turns on auto-committing
  IBM_DB::autocommit @connection, IBM_DB::SQL_AUTOCOMMIT_ON
end

#select_all(sql, name = nil) ⇒ Object

Returns an array of hashes with the column names as keys and column values as values. sql is the select query, and name is an optional description for logging



479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 479

def select_all(sql, name = nil)
  # Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
  sql.gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
  
  results = []
  # Invokes the method +execute+ in order to log and execute the SQL
  # IBM_DB::Statement is returned from which results can be fetched
  if stmt = execute(sql, name)
    begin
      @servertype.select_all(sql, name, stmt, results)
    ensure
      # Ensures to free the resources associated with the statement
      IBM_DB::free_result stmt
    end
  end
  # The array of record hashes is returned
  results
end

#select_one(sql, name = nil) ⇒ Object

Returns a record hash with the column names as keys and column values as values.



500
501
502
503
504
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 500

def select_one(sql, name = nil)
  # Gets the first hash from the array of hashes returned by
  # select_all
  select_all(sql,name).first
end

#supports_migrations?Boolean

This adapter supports migrations. Current limitations: rename_column is not currently supported by the IBM data servers remove_column is not currently supported by the DB2 for zOS data server Tables containing columns of XML data type do not support remove_column

Returns:

  • (Boolean)


402
403
404
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 402

def supports_migrations?
  true
end

#table_alias_lengthObject

Returns the maximum length a table alias identifier can be. IBM data servers (cross-platform) table limit is 128 characters



745
746
747
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 745

def table_alias_length
  128
end

#tables(name = nil) ⇒ Object

Retrieves table’s metadata for a specified shema name



750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 750

def tables(name = nil)
  # Initializes the tables array
  tables = []
  # Retrieve table's metadata through IBM_DB driver
  if stmt = IBM_DB::tables(@connection, nil, 
                           @servertype.set_case(@schema))
    begin
      # Fetches all the records available
      while tab = IBM_DB::fetch_assoc(stmt)
        # Adds the lowercase table name to the array
        tables << tab["table_name"].downcase
      end
    ensure
      IBM_DB::free_result(stmt)  # Free resources associated with the statement
    end
  else # Handle driver execution errors
    error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
    if error_msg && !error_msg.empty?
      raise "Failed to retrieve tables metadata due to error: #{error_msg}"
    else
      raise StandardError('Unexpected error during table metadata retrieval')
    end
  end
  # Returns the tables array
  return tables
end

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

IBM data servers do not support limits on certain data types (unlike MySQL) Limit is supported for the decimal, numeric, varchar, clob, blob data types.



730
731
732
733
734
735
736
737
738
739
740
741
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 730

def type_to_sql(type, limit = nil, precision = nil, scale = nil)
  return super if limit.nil?

  # strip off limits on data types not supporting them
  if [:integer, :double, :date, :time, :timestamp, :xml].include? type
    return type.to_s
  elsif type.to_sym == :boolean
    return "smallint"
  else
    return super
  end
end

#update(sql, name = nil) ⇒ Object Also known as: delete

Executes an “UPDATE” SQL statement



532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 532

def update(sql, name = nil)
  # Make sure the WHERE clause handles NULL's correctly
  sqlarray = sql.split(/\s*WHERE\s*/)
  if !sqlarray[1].nil?
    sqlarray[1].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
    sql = sqlarray[0] + " WHERE " + sqlarray[1]
  end

  # Logs and execute the given sql query.
  if stmt = execute(sql, name)
    begin
      @sql = sql
      # Retrieves the number of affected rows
      IBM_DB::num_rows(stmt)
      # Ensures to free the resources associated with the statement
    ensure
      IBM_DB::free_result(stmt)
    end
  end
end