class Sequel::Oracle::Database

Constants

CONNECTION_ERROR_CODES

ORA-00028: your session has been killed ORA-01012: not logged on ORA-03113: end-of-file on communication channel ORA-03114: not connected to ORACLE

DatasetClass
ORACLE_TYPES
PS_TYPES

Attributes

conversion_procs[R]

Hash of conversion procs for this database.

Public Instance Methods

connect(server) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 26
def connect(server)
  opts = server_opts(server)
  if opts[:database]
    dbname = opts[:host] ?              "//#{opts[:host]}#{":#{opts[:port]}" if opts[:port]}/#{opts[:database]}" : opts[:database]
  else
    dbname = opts[:host]
  end
  conn = OCI8.new(opts[:user], opts[:password], dbname, opts[:privilege])
  if prefetch_rows = opts.fetch(:prefetch_rows, 100)
    conn.prefetch_rows = typecast_value_integer(prefetch_rows)
  end
  conn.autocommit = true
  conn.non_blocking = true
  
  # The ruby-oci8 gem which retrieves oracle columns with a type of
  # DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE is complex based on the
  # ruby version (1.9.2 or later) and Oracle version (9 or later)
  # In the now standard case of 1.9.2 and Oracle 9 or later, the timezone
  # is determined by the Oracle session timezone. Thus if the user
  # requests Sequel provide UTC timezone to the application,
  # we need to alter the session timezone to be UTC
  if Sequel.application_timezone == :utc
    conn.exec("ALTER SESSION SET TIME_ZONE='-00:00'")
  end
  
  class << conn
    attr_reader :prepared_statements
  end
  conn.instance_variable_set(:@prepared_statements, {})
  
  conn
end
disconnect_connection(c) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 60
def disconnect_connection(c)
  c.logoff
rescue OCIException
  nil
end
execute(sql, opts=OPTS, &block) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 66
def execute(sql, opts=OPTS, &block)
  _execute(nil, sql, opts, &block)
end
execute_insert(sql, opts=OPTS) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 70
def execute_insert(sql, opts=OPTS)
  _execute(:insert, sql, opts)
end
freeze() click to toggle source
Calls superclass method Sequel::Oracle::DatabaseMethods#freeze
# File lib/sequel/adapters/oracle.rb, line 74
def freeze
  @conversion_procs.freeze
  super
end

Private Instance Methods

_execute(type, sql, opts=OPTS) { |r| ... } click to toggle source
# File lib/sequel/adapters/oracle.rb, line 81
def _execute(type, sql, opts=OPTS, &block)
  synchronize(opts[:server]) do |conn|
    begin
      return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
      if args = opts[:arguments]
        r = conn.parse(sql)
        args = cursor_bind_params(conn, r, args)
        nr = log_connection_yield(sql, conn, args){r.exec}
        r = nr unless block_given?
      else
        r = log_connection_yield(sql, conn){conn.exec(sql)}
      end
      if block_given?
        yield(r)
      elsif type == :insert
        last_insert_id(conn, opts)
      else
        r
      end
    rescue OCIException, RuntimeError => e
      # ruby-oci8 is naughty and raises strings in some places
      raise_error(e)
    ensure
      r.close if r.is_a?(::OCI8::Cursor)
    end
  end
end
adapter_initialize() click to toggle source
# File lib/sequel/adapters/oracle.rb, line 109
def adapter_initialize
  @autosequence = @opts[:autosequence]
  @primary_key_sequences = {}
  @conversion_procs = ORACLE_TYPES.dup
end
begin_transaction(conn, opts=OPTS) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 218
def begin_transaction(conn, opts=OPTS)
  log_connection_yield(TRANSACTION_BEGIN, conn){conn.autocommit = false}
  set_transaction_isolation(conn, opts)
end
commit_transaction(conn, opts=OPTS) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 223
def commit_transaction(conn, opts=OPTS)
  log_connection_yield(TRANSACTION_COMMIT, conn){conn.commit}
end
connection_execute_method() click to toggle source
# File lib/sequel/adapters/oracle.rb, line 141
def connection_execute_method
  :exec
end
cursor_bind_params(conn, cursor, args) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 118
def cursor_bind_params(conn, cursor, args)
  i = 0
  args.map do |arg, type|
    i += 1
    case arg
    when true
      arg = 'Y'
    when false
      arg = 'N'
    when BigDecimal
      arg = arg.to_f
    when ::Sequel::SQL::Blob
      arg = ::OCI8::BLOB.new(conn, arg)
    end
    if t = PS_TYPES[type]
      cursor.bind_param(i, arg, t)
    else
      cursor.bind_param(i, arg, arg.class)
    end
    arg
  end
end
database_error_classes() click to toggle source
# File lib/sequel/adapters/oracle.rb, line 145
def database_error_classes
  [OCIException, RuntimeError]
end
database_specific_error_class(exception, opts) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 149
def database_specific_error_class(exception, opts)
  return super unless exception.respond_to?(:code)
  case exception.code
  when 1400, 1407
    NotNullConstraintViolation
  when 1
    UniqueConstraintViolation
  when 2291, 2292
    ForeignKeyConstraintViolation
  when 2290
    CheckConstraintViolation
  when 8177
    SerializationFailure
  else
    super
  end
end
disconnect_error?(e, opts) click to toggle source
Calls superclass method Sequel::Database#disconnect_error?
# File lib/sequel/adapters/oracle.rb, line 227
def disconnect_error?(e, opts)
  super || (e.is_a?(::OCIError) && CONNECTION_ERROR_CODES.include?(e.code))
end
execute_prepared_statement(conn, type, name, opts) { |cursor| ... } click to toggle source
# File lib/sequel/adapters/oracle.rb, line 167
def execute_prepared_statement(conn, type, name, opts)
  ps = prepared_statement(name)
  sql = ps.prepared_sql
  if cursora = conn.prepared_statements[name]
    cursor, cursor_sql = cursora
    if cursor_sql != sql
      cursor.close
      cursor = nil
    end
  end
  unless cursor
    cursor = log_connection_yield("PREPARE #{name}: #{sql}", conn){conn.parse(sql)}
    conn.prepared_statements[name] = [cursor, sql]
  end
  args = cursor_bind_params(conn, cursor, opts[:arguments])
  log_sql = "EXECUTE #{name}"
  if ps.log_sql
    log_sql += " ("
    log_sql << sql
    log_sql << ")"
  end
  r = log_connection_yield(log_sql, conn, args){cursor.exec}
  if block_given?
    yield(cursor)
  elsif type == :insert
    last_insert_id(conn, opts)
  else
    r
  end
end
last_insert_id(conn, opts) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 198
def last_insert_id(conn, opts)
  unless sequence = opts[:sequence]
    if t = opts[:table]
      sequence = sequence_for_table(t)
    end
  end
  if sequence
    sql = "SELECT #{literal(sequence)}.currval FROM dual"
    begin
      cursor = log_connection_yield(sql, conn){conn.exec(sql)}
      row = cursor.fetch
      row.each{|v| return (v.to_i if v)}
    rescue OCIError
      nil
    ensure
      cursor.close if cursor
    end
  end
end
oracle_column_type(h) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 231
def oracle_column_type(h)
  case h[:oci8_type]
  when :number
    case h[:scale]
    when 0
      :integer
    when -127
      :float
    else
      :decimal
    end
  when :date
    :datetime
  else
    schema_column_type(h[:db_type])
  end
end
remove_transaction(conn, committed) click to toggle source
Calls superclass method Sequel::Database#remove_transaction
# File lib/sequel/adapters/oracle.rb, line 249
def remove_transaction(conn, committed)
  conn.autocommit = true
ensure
  super
end
rollback_transaction(conn, opts=OPTS) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 255
def rollback_transaction(conn, opts=OPTS)
  log_connection_yield(TRANSACTION_ROLLBACK, conn){conn.rollback}
end
schema_parse_table(table, opts=OPTS) click to toggle source
# File lib/sequel/adapters/oracle.rb, line 259
def schema_parse_table(table, opts=OPTS)
  schema, table = schema_and_table(table)
  schema ||= opts[:schema]
  schema_and_table = if ds = opts[:dataset]
    ds.literal(schema ? SQL::QualifiedIdentifier.new(schema, table) : SQL::Identifier.new(table))
  else
    "#{"#{quote_identifier(schema)}." if schema}#{quote_identifier(table)}"
  end
  table_schema = []
  m = output_identifier_meth(ds)
  im = input_identifier_meth(ds)

  # Primary Keys
  ds = metadata_dataset.
    from{[all_constraints.as(:cons), all_cons_columns.as(:cols)]}.
    where{{
     cols[:table_name]=>im.call(table),
     cons[:constraint_type]=>'P',
     cons[:constraint_name]=>cols[:constraint_name],
     cons[:owner]=>cols[:owner]}}
  ds = ds.where{{cons[:owner]=>im.call(schema)}} if schema
  pks = ds.select_map{cols[:column_name]}

  # Default values
  defaults = begin
    metadata_dataset.from(:all_tab_cols).
      where(:table_name=>im.call(table)).
      to_hash(:column_name, :data_default)
  rescue DatabaseError
    {}
  end

  metadata = synchronize(opts[:server]) do |conn|
    begin
      log_connection_yield("Connection.describe_table", conn){conn.describe_table(schema_and_table)}
    rescue OCIError => e
      raise_error(e)
    end
  end
  metadata.columns.each do |column|
    h = {
        :primary_key => pks.include?(column.name),
        :default => defaults[column.name],
        :oci8_type => column.data_type,
        :db_type => column.type_string,
        :type_string => column.type_string,
        :charset_form => column.charset_form,
        :char_used => column.char_used?,
        :char_size => column.char_size,
        :data_size => column.data_size,
        :precision => column.precision,
        :scale => column.scale,
        :fsprecision => column.fsprecision,
        :lfprecision => column.lfprecision,
        :allow_null => column.nullable?
    }
    h[:type] = oracle_column_type(h)
    h[:auto_increment] = h[:type] == :integer if h[:primary_key]
    h[:max_length] = h[:char_size] if h[:type] == :string
    table_schema << [m.call(column.name), h]
  end
  table_schema
end