class Sequel::IBMDB::Database

def _execute(conn, sql, opts)

Execute the given SQL on the database.
def _execute(conn, sql, opts)
  stmt = log_yield(sql){conn.execute(sql)}
  if block_given?
    begin
      yield(stmt)
    ensure
      stmt.free
    end
  else  
    stmt.affected
  end
end

def alter_table(name, generator=nil, &block)

code in many cases.
required, but it is necessary for compatibilty with other Sequel
REORG the related table whenever it is altered. This is not always
def alter_table(name, generator=nil, &block)
  res = super
  reorg(name)
  res
end

def begin_transaction(conn, opts={})

So starting a transaction just turns autocommit off.
IBM_DB uses an autocommit setting instead of sending SQL queries.
def begin_transaction(conn, opts={})
  log_yield(TRANSACTION_BEGIN){conn.autocommit = false}
end

def commit_transaction(conn, opts={})

connection and sets autocommit back on.
This commits transaction in progress on the
def commit_transaction(conn, opts={})
  log_yield(TRANSACTION_COMMIT){conn.commit}
end

def connect(server)

Create a new connection object for the given server.
def connect(server)
  opts = server_opts(server)
  
  # use uncataloged connection so that host and port can be supported
  connection_string = ( \
      'Driver={IBM DB2 ODBC DRIVER};' \
      "Database=#{opts[:database]};" \
      "Hostname=#{opts[:host]};" \
      "Port=#{opts[:port] || 50000};" \
      'Protocol=TCPIP;' \
      "Uid=#{opts[:user]};" \
      "Pwd=#{opts[:password]};" \
  )
  Connection.new(connection_string)
end

def disconnect_connection(conn)

Close the given connection.
def disconnect_connection(conn)
  conn.close
end

def execute(sql, opts={}, &block)

Execute the given SQL on the database.
def execute(sql, opts={}, &block)
  if sql.is_a?(Symbol)
    execute_prepared_statement(sql, opts, &block)
  else
    synchronize(opts[:server]){|c| _execute(c, sql, opts, &block)}
  end
rescue Connection::Error => e
  raise_error(e)
end

def execute_insert(sql, opts={})

identity value.
Execute the given SQL on the database, returning the last inserted
def execute_insert(sql, opts={})
  synchronize(opts[:server]) do |c|
    if sql.is_a?(Symbol)
      execute_prepared_statement(sql, opts)
    else
      _execute(c, sql, opts)
    end
    _execute(c, "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1", opts){|stmt| i = stmt.fetch_array.first.to_i; stmt.free; i}
  end
rescue Connection::Error => e
  raise_error(e)
end

def execute_prepared_statement(ps_name, opts)

Execute a prepared statement named by name on the database.
def execute_prepared_statement(ps_name, opts)
  args = opts[:arguments]
  ps = prepared_statements[ps_name]
  sql = ps.prepared_sql
  synchronize(opts[:server]) do |conn|
    unless conn.prepared_statements.fetch(ps_name, []).first == sql
      log_yield("Preparing #{ps_name}: #{sql}"){conn.prepare(sql, ps_name)}
    end
    args = args.map{|v| v.nil? ? nil : prepared_statement_arg(v)}
    stmt = log_yield("Executing #{ps_name}: #{args.inspect}"){conn.execute_prepared(ps_name, *args)}
    if block_given?
      begin
        yield(stmt)
      ensure
        stmt.free
      end
    else  
      stmt.affected
    end
  end
end

def initialize(opts={})

def initialize(opts={})
  super
  @conversion_procs = DB2_TYPES.dup
  @conversion_procs[:timestamp] = method(:to_application_timestamp)
end

def metadata_dataset

accidently treated as booleans.
boolean columns, and some smallint columns are
dataset, since the DB2 metadata does not use
Don't convert smallint to boolean for the metadata
def metadata_dataset
  ds = super
  ds.convert_smallint_to_bool = false
  ds
end

def prepared_statement_arg(v)

as IBM_DB prepared statements argument vlaues.
Format Numeric, Date, and Time types specially for use
def prepared_statement_arg(v)
  case v
  when Numeric
    v.to_s
  when Date, Time
    literal(v).gsub("'", '')
  else
    v
  end
end

def remove_transaction(conn, committed)

Set autocommit back on
def remove_transaction(conn, committed)
  conn.autocommit = true
ensure
  super
end

def rollback_transaction(conn, opts={})

connection and sets autocommit back on.
This rolls back the transaction in progress on the
def rollback_transaction(conn, opts={})
  log_yield(TRANSACTION_ROLLBACK){conn.rollback}
end

def schema_column_type(db_type)

Convert smallint type to boolean if convert_smallint_to_bool is true
def schema_column_type(db_type)
  if Sequel::IBMDB.convert_smallint_to_bool && db_type =~ /smallint/i 
    :boolean
  else
    super
  end
end

def table_exists?(name)

error that indicates it should be REORGed.
of it. This REORGs automatically if the database raises a specific
On DB2, a table might need to be REORGed if you are testing existence
def table_exists?(name)
  v ||= false # only retry once
  sch, table_name = schema_and_table(name)
  name = SQL::QualifiedIdentifier.new(sch, table_name) if sch
  from(name).first
  true
rescue DatabaseError => e
  if e.to_s =~ /Operation not allowed for reason code "7" on table/ && v == false
    # table probably needs reorg
    reorg(name)
    v = true
    retry 
  end
  false
end