Class: ActiveRecord::ConnectionAdapters::IBM_DataServer

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

Overview

This class contains common code across DB’s (DB2 LUW, zOS, i5 and IDS)

Direct Known Subclasses

IBM_DB2, IBM_IDS

Instance Method Summary collapse

Constructor Details

#initialize(adapter, ar3) ⇒ IBM_DataServer

Returns a new instance of IBM_DataServer.



2136
2137
2138
2139
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2136

def initialize(adapter, ar3)
  @adapter = adapter
  @isAr3 = ar3
end

Instance Method Details

#change_column_default(table_name, column_name, default) ⇒ Object



2280
2281
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2280

def change_column_default(table_name, column_name, default)
end

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



2283
2284
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2283

def change_column_null(table_name, column_name, null, default)
end

#check_reserved_words(col_name) ⇒ Object



2153
2154
2155
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2153

def check_reserved_words(col_name)
  col_name.to_s
end

#columns(table_name, name = nil) ⇒ Object

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



2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2498

def columns(table_name, name = nil)
  # to_s required because it may be a symbol.
  table_name = 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
  stmt = IBM_DB.columns( @adapter.connection, nil, 
                             set_case(@adapter.serverschema), 
                             set_case(table_name) )
  if(stmt)
    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')
        # If default value is IDENTITY GENERATED BY DEFAULT (this value is retrieved in case of id columns)
        column_default_value = nil if (column_default_value && column_default_value.upcase =~ /IDENTITY GENERATED BY DEFAULT/i)
        # 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|bigint/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+.
          if @adapter.servertype.instance_of?(IBM_DB2_I5)
            # T006&T014: time and Timestamp parsing (which perhaps should be in IBM_DBColumn instead
            columns << IBM_DB_I5Column.new(column_name, column_default_value, column_type, column_nullable)
          else
            columns << IBM_DBColumn.new(column_name, column_default_value, column_type, column_nullable)
          end
        end
      end
    rescue StandardError => fetch_error # Handle driver fetch errors
      error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
      if error_msg && !error_msg.empty?
        raise "Failed to retrieve column metadata during fetch: #{error_msg}"
      else
        error_msg = "An unexpected error occurred during retrieval of column metadata for #{table_name}"
        error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
        raise error_msg
      end
    ensure  # Free resources associated with the statement
      IBM_DB.free_stmt(stmt) if stmt
    end
  else  # Handle driver execution errors
    error_msg = IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN )
    if error_msg && !error_msg.empty?
      raise "Failed to retrieve column metadata due to error: #{error_msg}"
    else
      raise StandardError.new('An unexpected error occurred during retrieval of columns metadata')
    end
  end

  # Returns the columns array
  return columns
end

#create_database(dbName, codeSet = nil, mode = nil) ⇒ Object



2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2325

def create_database(dbName, codeSet=nil, mode=nil)
  connect_str = build_conn_str_for_dbops()

  #Ensure connection is closed before trying to drop a database.
  #As a connect call would have been made by call seeing connection in active
  disconnect!

  begin
    createConn = IBM_DB.connect(connect_str, '', '')
  rescue StandardError => connect_err
    raise "Failed to connect to server due to: #{connect_err}"
  end

  if(IBM_DB.createDB(createConn,dbName,codeSet,mode))
    IBM_DB.close(createConn)
    return true
  else
    error = IBM_DB.getErrormsg(createConn, IBM_DB::DB_CONN)
    IBM_DB.close(createConn)
    raise "Could not create Database due to: #{error}"
  end
end

#create_index_after_table(table_name, cloumn_name) ⇒ Object



2144
2145
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2144

def create_index_after_table (table_name,cloumn_name)
end

#drop_database(dbName) ⇒ Object



2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2302

def drop_database(dbName)
  connect_str = build_conn_str_for_dbops()

  #Ensure connection is closed before trying to drop a database. 
  #As a connect call would have been made by call seeing connection in active
  disconnect!

  begin
    dropConn = IBM_DB.connect(connect_str, '', '')
  rescue StandardError => connect_err
    raise "Failed to connect to server due to: #{connect_err}"
  end

  if(IBM_DB.dropDB(dropConn,dbName))
    IBM_DB.close(dropConn)
    return true
  else
    error = IBM_DB.getErrormsg(dropConn, IBM_DB::DB_CONN)
    IBM_DB.close(dropConn)
    raise "Could not drop Database due to: #{error}"
  end
end

#execute(sql, name = nil) ⇒ Object



2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2245

def execute(sql, name = nil)
  begin
    if stmt = IBM_DB.exec(@adapter.connection, sql)
      stmt   # Return the statement object
    else
      raise StatementInvalid, IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN )
    end
  rescue StandardError => exec_err
    if exec_err && !exec_err.message.empty?
      raise "Failed to execute statement due to: #{exec_err}"
    else
      raise
    end
  end
end

#get_datetime_mappingObject



2271
2272
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2271

def get_datetime_mapping
end

#get_double_mappingObject



2277
2278
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2277

def get_double_mapping
end

#get_time_mappingObject



2274
2275
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2274

def get_time_mapping
end

#indexes(table_name, name = nil) ⇒ Object

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



2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2377

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 = []
  pk_index = nil
  index_schema = []
  
  #fetch the primary keys of the table using function primary_keys
  #TABLE_SCHEM:: pk_index[1]
  #TABLE_NAME:: pk_index[2]
  #COLUMN_NAME:: pk_index[3]
  #PK_NAME:: pk_index[5]
  stmt = IBM_DB.primary_keys( @adapter.connection, nil, 
                             set_case(@adapter.serverschema), 
                             set_case(table_name))
  if(stmt)
    begin
      while ( pk_index_row = IBM_DB.fetch_array(stmt) )
        if pk_index_row[5] 
          pk_index_name = pk_index_row[5].downcase
          pk_index_columns = [pk_index_row[3].downcase]           # COLUMN_NAME
          if pk_index 
            pk_index.columns = pk_index.columns + pk_index_columns
          else
            pk_index = IndexDefinition.new(table_name, pk_index_name, true, pk_index_columns)
          end
        end 
      end
    rescue StandardError => fetch_error # Handle driver fetch errors
      error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
      if error_msg && !error_msg.empty?
        raise "Failed to retrieve primarykey metadata during fetch: #{error_msg}"
      else
        error_msg = "An unexpected error occurred during retrieval of primary key metadata"
        error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
        raise error_msg
      end
    ensure  # Free resources associated with the statement
      IBM_DB.free_stmt(stmt) if stmt
    end
  else  # Handle driver execution errors
    error_msg = IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN )
    if error_msg && !error_msg.empty?
      raise "Failed to retrieve primary key metadata due to error: #{error_msg}"
    else
      raise StandardError.new('An unexpected error occurred during primary key retrieval')
    end
  end

  # 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]}"

  stmt = IBM_DB.statistics( @adapter.connection, nil, 
                            set_case(@adapter.serverschema), 
                            set_case(table_name), 1 )
  if(stmt)
    begin
      while ( index_stats = IBM_DB.fetch_array(stmt) )
          is_composite = false
        if index_stats[5]             # INDEX_NAME
          index_name = index_stats[5].downcase
          index_unique = (index_stats[3] == 0)
          index_columns = [index_stats[8].downcase]     # COLUMN_NAME
          index_qualifier = index_stats[4].downcase             #Index_Qualifier
          # Create an IndexDefinition object and add to the indexes array
          i = 0;
          indexes.each do |index|
            if index.name == index_name && index_schema[i] == index_qualifier
               index.columns = index.columns + index_columns
               is_composite = true
            end 
            i = i+1
          end
        
          unless is_composite 
            indexes << IndexDefinition.new(table_name, index_name, index_unique, index_columns)
            index_schema << index_qualifier
          end 
        end
      end
    rescue StandardError => fetch_error # Handle driver fetch errors
      error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
      if error_msg && !error_msg.empty?
        raise "Failed to retrieve index metadata during fetch: #{error_msg}"
      else
        error_msg = "An unexpected error occurred during retrieval of index metadata"
        error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
        raise error_msg
      end
    ensure  # Free resources associated with the statement
      IBM_DB.free_stmt(stmt) if stmt
    end
  else  # Handle driver execution errors
    error_msg = IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN )
    if error_msg && !error_msg.empty?
      raise "Failed to retrieve index metadata due to error: #{error_msg}"
    else
      raise StandardError.new('An unexpected error occurred during index retrieval')
    end
  end
    
  # remove the primary key index entry.... should not be dumped by the dumper    
  i = 0
  indexes.each do |index|
    if pk_index && index.columns == pk_index.columns
      indexes.delete_at(i)
    end
    i = i+1
  end 
  # Returns the indexes array
  return indexes
end

#last_generated_id(stmt) ⇒ Object



2141
2142
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2141

def last_generated_id(stmt)
end

#limit_not_supported_typesObject



2298
2299
2300
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2298

def limit_not_supported_types
  [:integer, :double, :date, :time, :timestamp, :xml, :bigint]
end

#prepare(sql, name = nil) ⇒ Object

Praveen



2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2228

def prepare(sql,name = nil)
  begin
    stmt = IBM_DB.prepare(@adapter.connection, sql)
    if( stmt )
      stmt
    else
      raise StatementInvalid, IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN )
    end
  rescue StandardError => prep_err
    if prep_err && !prep_err.message.empty?
      raise "Failed to prepare sql #{sql} due to: #{prep_err}"
    else 
      raise
    end
  end
end

#query_offset_limit(sql, offset, limit) ⇒ Object



2265
2266
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2265

def query_offset_limit(sql, offset, limit)
end

#query_offset_limit!(sql, offset, limit, options) ⇒ Object



2268
2269
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2268

def query_offset_limit!(sql, offset, limit, options)
end

#remove_column(table_name, column_name) ⇒ Object

This is supported by the DB2 for Linux, UNIX, Windows data servers and by the DB2 for i5 data servers



2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2159

def remove_column(table_name, column_name)
  begin
    @adapter.execute "ALTER TABLE #{table_name} DROP #{column_name}"
    reorg_table(table_name)
  rescue StandardError => exec_err
    # Provide details on the current XML columns support
    if exec_err.message.include?('SQLCODE=-1242') && exec_err.message.include?('42997')
      raise StatementInvalid, 
            "A column that is part of a table containing an XML column cannot be dropped. \
To remove the column, the table must be dropped and recreated without the #{column_name} column: #{exec_err}"
    else
      raise "#{exec_err}"
    end
  end
end

#reorg_table(table_name) ⇒ Object



2150
2151
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2150

def reorg_table(table_name)
end

#select(stmt) ⇒ Object



2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2175

def select(stmt)
  results = []
  # Fetches all the results available. IBM_DB.fetch_assoc(stmt) returns
  # an hash for each single record.
  # The loop stops when there aren't any more valid records to fetch
  begin
    if(@isAr3)
      while single_hash = IBM_DB.fetch_assoc(stmt)
        # Add the record to the +results+ array
        results <<  single_hash
      end
    else
      while single_hash = IBM_DB.fetch_array(stmt)
        # Add the record to the +results+ array
        results <<  single_hash
      end
    end
  rescue StandardError => fetch_error # Handle driver fetch errors
    error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
    if error_msg && !error_msg.empty?
      raise StatementInvalid,"Failed to retrieve data: #{error_msg}"
    else
      error_msg = "An unexpected error occurred during data retrieval"
      error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
      raise error_msg
    end
  end
  return results
end

#select_rows(sql, name, stmt, results) ⇒ Object



2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2205

def select_rows(sql, name, stmt, results)
  # Fetches all the results available. IBM_DB.fetch_array(stmt) returns
  # an array representing a row in a result set.
  # The loop stops when there aren't any more valid records to fetch
  begin
    while single_array = IBM_DB.fetch_array(stmt)
      #Add the array to results array
      results <<  single_array
    end
  rescue StandardError => fetch_error # Handle driver fetch errors
    error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
    if error_msg && !error_msg.empty?
      raise StatementInvalid,"Failed to retrieve data: #{error_msg}"
    else
      error_msg = "An unexpected error occurred during data retrieval"
      error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
      raise error_msg
    end
  end
  return results
end

#set_binary_default(value) ⇒ Object



2286
2287
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2286

def set_binary_default(value)
end

#set_binary_valueObject



2289
2290
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2289

def set_binary_value
end

#set_case(value) ⇒ Object



2295
2296
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2295

def set_case(value)
end

#set_schema(schema) ⇒ Object



2261
2262
2263
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2261

def set_schema(schema)
  @adapter.execute("SET SCHEMA #{schema}")
end

#set_text_defaultObject



2292
2293
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2292

def set_text_default
end

#setup_for_lob_tableObject



2147
2148
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2147

def setup_for_lob_table ()
end

#task_charset(task) ⇒ Object



2363
2364
2365
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2363

def task_charset(task)
  @adapter.connection.charset
end

#task_collation(task) ⇒ Object



2366
2367
2368
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2366

def task_collation(task)
  @adapter.connection.collation
end

#task_create(task) ⇒ Object

Unit testing (SQLLiteDatabaseTasks, MySQLDatabaseTasks, PostgreSQLDatabaseTasks)



2351
2352
2353
2354
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2351

def task_create(task)
  create_database(dbName)
  task.log("create_database #{filename}")
end

#task_drop(task) ⇒ Object



2355
2356
2357
2358
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2355

def task_drop(task)
  drop_database(dbName)
  task.log("drop_database #{filename}")
end

#task_purge(task) ⇒ Object



2359
2360
2361
2362
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2359

def task_purge(task)
  drop_database(dbName)
  create_database(dbName)
end

#task_structure_dump(task, filename = nil) ⇒ Object



2369
2370
2371
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2369

def task_structure_dump(task,filename=nil)
  task.log("Unsupported function structure_dump #{filename}")
end

#task_structure_load(task, filename = nil) ⇒ Object



2372
2373
2374
# File 'lib/active_record/connection_adapters/ibm_db_adapter.rb', line 2372

def task_structure_load(task,filename=nil)
  task.log("Unsupported function structure_load #{filename}")
end