Class: Og::OracleAdapter

Inherits:
SqlStore show all
Extended by:
OracleUtils
Includes:
OracleUtils
Defined in:
lib/og/adapter/oracle.rb,
lib/og/adapter/oracle.old.rb

Overview

The Oracle adapter. This adapter communicates with an Oracle rdbms. For extra documentation see lib/og/adapter.rb

Instance Attribute Summary

Attributes inherited from SqlStore

#conn, #typemap

Attributes inherited from Store

#ogmanager

Instance Method Summary collapse

Methods included from SqlUtils

#blob, #build_join_name, #create_join_table_sql, #date, #escape, #join_class_ordering, #join_object_ordering, #join_table, #join_table_index, #join_table_info, #join_table_key, #join_table_keys, #ordered_join_table_keys, #parse_blob, #parse_boolean, #parse_date, #parse_float, #parse_int, #parse_timestamp, #quote, #quote_array, #table, #tableize, #timestamp

Methods inherited from SqlStore

#aggregate, #count, #delete_all, #destroy_db, #eval_og_allocate, #eval_og_create_schema, #eval_og_delete, #eval_og_insert, #eval_og_read, #eval_og_update, #exec, #field_for_attribute, #field_sql_for_attribute, #fields_for_class, #find, #find_one, #force_primary_key, #handle_sql_exception, #join, #load, #pk_field, #prepare_statement, #query, #read_all, #read_field, #read_join_relations, #read_one, #read_row, #reload, #resolve_limit_options, #resolve_options, #select, #select_one, #serializable_attributes_for_class, #sql_indices_for_class, #sql_type_for_class, #table_exists?, #type_cast, #unjoin, #update, #update_by_sql, #update_condition, #write_attr

Methods inherited from Store

#count, #delete, #delete_all, #find, #force_save!, #insert, #load, #reload, #save, #transaction, #update, #update_attributes

Constructor Details

#initializeOracleAdapter

Returns a new instance of OracleAdapter.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/og/adapter/oracle.rb', line 25

def initialize(config)
  super
  
  @typemap.update(
    Integer => 'number',
    Fixnum => 'number',
    String => 'varchar2(1024)', # max might be 4000 (Oracle 8)
    TrueClass => 'char(1)',
    Numeric => 'number',
    Object => 'varchar2(1024)',
    Array => 'varchar2(1024)',
    Hash => 'varchar2(1024)'
  )
  
  # TODO: how to pass address etc?
  @conn = OCI8.new(
    config[:user],
    config[:password],
    config[:database], 
    config[:privilege]
  )

  # gmosx: does this work?
  @conn.autocommit = true
rescue OCIException => ex
  #---
  # mcb:
    # Oracle will raise a ORA-01017 if username, password, or 
  # SID aren't valid. I verified this for all three.
  # irb(main):002:0> conn = Oracle.new('keebler', 'dfdfd', 'kbsid')
  # /usr/local/lib/ruby/site_ruby/1.8/oracle.rb:27:in `logon': ORA-01017:
  # invalid username/password; logon denied (OCIError)
  #+++
  if database_does_not_exist_exception? ex
    Logger.info "Database '#{options[:name]}' not found!"
    create_db(options)
    retry
  end
  raise
end

Instance Method Details

#closeObject



66
67
68
69
# File 'lib/og/adapter/oracle.rb', line 66

def close
  @conn.logoff
  super
end

#commitObject

Commit a transaction.



169
170
171
172
173
174
# File 'lib/og/adapter/oracle.rb', line 169

def commit
  @transaction_nesting -= 1
  @conn.commit if @transaction_nesting < 1
ensure
  @conn.autocommit = true
end

#create_db(database, user = nil, password = nil) ⇒ Object

– mcb: Unlike MySQL or Postgres, Oracle database/schema creation is a big deal. I don’t know how to do it from the command line. I use Oracle’s Database Configuration Assistant utility (dbca). I takes 30min - 1hr to create a full blown schema. So, your FIXME comments are fine. I’m thinking you won’t be able to do this via Og, but once created, Og will be able to create tables, indexes, and other objects. ++

Raises:

  • (NotImplementedError)


81
82
83
84
85
86
# File 'lib/og/adapter/oracle.rb', line 81

def create_db(database, user = nil, password = nil)
  # FIXME: what is appropriate for oracle?
  # `createdb #{database} -U #{user}`
  super
  raise NotImplementedError, "Oracle Database/Schema creation n/a"
end

#create_field_map(klass) ⇒ Object

Get the fields from the database table. Also handles the change of ordering of the fields in the table.

To ignore a database field use the ignore_fields annotation ie,

class Article

ann self, :ignore_fields => [ :tsearch_idx, :ext_field ]

end

other aliases for ignore_fiels: ignore_field, ignore_column. – Even though great care has been taken to make this method reusable, oveeride if needed in your adapter. ++



259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/og/adapter/oracle.rb', line 259

def create_field_map(klass)
  # gmosx: This is incredible!!! argh!
  # res = db.query "SELECT * FROM #{klass::DBTABLE} # LIMIT 1"
  res = query "SELECT * FROM (SELECT * FROM #{table(klass)}) WHERE ROWNUM <= 1"
  map = {}
  
  # Check if the field should be ignored.
  
  ignore = klass.ann.self[:ignore_field] || klass.ann.self[:ignore_fields] || klass.ann.self[:ignore_columns]   

  res.get_col_names.each_with_index do |f, i|
    field_name = f.to_sym
    unless (ignore and ignore.include?(field_name))
      map[field_name] = i
    end
  end

  return map
end

#create_table(klass) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/og/adapter/oracle.rb', line 186

def create_table(klass)
  super
  
  seq = klass.ann[klass.primary_key][:sequence]
  # Create the sequence for this table. 
  begin
    exec_statement("CREATE SEQUENCE #{seq} INCREMENT BY 1 START WITH 1 NOMAXVALUE NOMINVALUE NOCYCLE")
    Logger.info "Created sequence '#{seq}'."       
  rescue OCIError => ex
    if table_already_exists_exception?(ex)
      Logger.debug "Sequence #{seq} already exists" if $DBG
    else
      raise
    end
  end
  
end

#drop_db(database, user = nil, password = nil) ⇒ Object

Raises:

  • (NotImplementedError)


88
89
90
91
92
93
# File 'lib/og/adapter/oracle.rb', line 88

def drop_db(database, user = nil, password = nil)
  # FIXME: what is appropriate for oracle?
  # `dropdb #{database} -U #{user}`
  super
  raise NotImplementedError, "Oracle Database/Schema dropping n/a"
end

#drop_table(klass) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/og/adapter/oracle.rb', line 204

def drop_table(klass)
  super
  
  seq = klass.ann[klass.primary_key][:sequence]
  # Create the sequence for this table. 
  begin
    exec_statement("DROP SEQUENCE #{seq}")
    Logger.info "Dropped sequence '#{seq}'."       
  rescue OCIError => ex
    if sequence_does_not_exist_exception?(ex)
      Logger.debug "Sequence #{seq} didn't exist" if $DBG
    else
      raise
    end
  end
  
end

#enchant(klass, manager) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/og/adapter/oracle.rb', line 101

def enchant(klass, manager)
  pk = klass.primary_key
  
  seq = if klass.schema_inheritance_child?
    "#{table(klass.schema_inheritance_root_class)}_#{pk}_seq"
  else
    "#{table(klass)}_#{pk}_seq"
  end
  
  pkann = klass.ann[pk]
  
  pkann[:sequence] = seq unless pkann[:sequence] == false
  
  super
end

#exec_statement(sql) ⇒ Object



121
122
123
# File 'lib/og/adapter/oracle.rb', line 121

def exec_statement(sql)
  @conn.exec(sql)
end

#insert_sql(sql, klass) ⇒ Object

The insert sql statements.



145
146
147
148
149
150
151
152
153
154
155
# File 'lib/og/adapter/oracle.rb', line 145

def insert_sql(sql, klass)
  str = ''
  
  if klass.ann[klass.primary_key][:sequence]
    str << "@#{klass.primary_key} = store.last_insert_id(#{klass})\n"
  end
  
  str << "store.exec \"#{sql}\""
  
  return str
end

#last_insert_id(klass) ⇒ Object

Return the last inserted row id.



133
134
135
136
137
138
139
140
141
# File 'lib/og/adapter/oracle.rb', line 133

def last_insert_id(klass)
  seq = klass.ann[klass.primary_key][:sequence]
  
  res = query_statement("SELECT #{seq}.nextval FROM DUAL")
  lid = Integer(res.first_value)
  res.close
  
  return lid
end

#primary_key_typeObject

The type used for default primary keys.



97
98
99
# File 'lib/og/adapter/oracle.rb', line 97

def primary_key_type
  'integer PRIMARY KEY'
end

#query_statement(sql) ⇒ Object



117
118
119
# File 'lib/og/adapter/oracle.rb', line 117

def query_statement(sql)
  @conn.exec(sql)
end

#read_attr(s, a, col) ⇒ Object



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/og/adapter/oracle.rb', line 222

def read_attr(s, a, col)
  store = self.class
  {
    String    => nil,
    Integer   => :parse_int,
    Float     => :parse_float,
    Time      => :parse_timestamp,
    Date      => :parse_date,
    TrueClass => :parse_boolean,
    Og::Blob  => :parse_blob
  }.each do |klass, meth|
    if a.class.ancestor? klass
      return meth ? 
        "#{store}.#{meth}(res[#{col} + offset])" : "res[#{col} + offset]"
    end
  end

  # else try to load it via YAML
  "YAML::load(res[#{col} + offset])"
end

#rollbackObject

Rollback a transaction.



178
179
180
181
182
183
# File 'lib/og/adapter/oracle.rb', line 178

def rollback
  @transaction_nesting -= 1
  @conn.rollbackif @transaction_nesting < 1
ensure
  @conn.autocommit = true
end

#sql_update(sql) ⇒ Object



125
126
127
128
129
# File 'lib/og/adapter/oracle.rb', line 125

def sql_update(sql)
  Logger.debug sql if $DBG  
  res = @conn.exec(sql)
  return res.to_i
end

#startObject

Start a new transaction.



161
162
163
164
165
# File 'lib/og/adapter/oracle.rb', line 161

def start  
  @conn.autocommit = false
  
  @transaction_nesting += 1
end