activerecord-oracle_enhanced-adapter 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. data/Gemfile +0 -2
  2. data/History.txt +19 -0
  3. data/README.md +378 -0
  4. data/RUNNING_TESTS.md +45 -0
  5. data/Rakefile +1 -1
  6. data/VERSION +1 -1
  7. data/activerecord-oracle_enhanced-adapter.gemspec +6 -9
  8. data/lib/active_record/connection_adapters/oracle_enhanced.rake +34 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +209 -57
  10. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +22 -1
  11. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +17 -3
  12. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +19 -3
  13. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +75 -17
  14. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +41 -2
  15. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +3 -3
  16. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +40 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +10 -3
  18. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +49 -10
  19. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +1 -1
  20. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +54 -54
  21. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +33 -5
  22. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +66 -5
  23. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +162 -13
  24. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +1 -0
  25. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +1 -0
  26. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +43 -0
  27. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +150 -1
  28. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +5 -4
  29. data/spec/spec_helper.rb +3 -1
  30. metadata +38 -52
  31. data/README.rdoc +0 -89
  32. data/RUNNING_TESTS.rdoc +0 -28
@@ -105,6 +105,12 @@ module ActiveRecord #:nodoc:
105
105
  end
106
106
 
107
107
  def indexes_with_oracle_enhanced(table, stream)
108
+ # return original method if not using oracle_enhanced
109
+ if (rails_env = defined?(Rails.env) ? Rails.env : (defined?(RAILS_ENV) ? RAILS_ENV : nil)) &&
110
+ ActiveRecord::Base.configurations[rails_env] &&
111
+ ActiveRecord::Base.configurations[rails_env]['adapter'] != 'oracle_enhanced'
112
+ return indexes_without_oracle_enhanced(table, stream)
113
+ end
108
114
  if (indexes = @connection.indexes(table)).any?
109
115
  add_index_statements = indexes.map do |index|
110
116
  case index.type
@@ -169,12 +175,13 @@ module ActiveRecord #:nodoc:
169
175
  next if column.name == pk
170
176
  spec = {}
171
177
  spec[:name] = column.name.inspect
172
- spec[:type] = column.type.to_s
178
+ spec[:type] = column.virtual? ? 'virtual' : column.type.to_s
173
179
  spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
174
180
  spec[:precision] = column.precision.inspect if !column.precision.nil?
175
181
  spec[:scale] = column.scale.inspect if !column.scale.nil?
176
182
  spec[:null] = 'false' if !column.null
177
- spec[:default] = default_string(column.default) if column.has_default?
183
+ spec[:default] = column.virtual_column_data_default if column.virtual?
184
+ spec[:default] ||= default_string(column.default) if column.has_default?
178
185
  (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
179
186
  spec
180
187
  end.compact
@@ -228,7 +235,7 @@ module ActiveRecord #:nodoc:
228
235
 
229
236
  private
230
237
  def remove_prefix_and_suffix(table_name)
231
- if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix}(.*)#{ActiveRecord::Base.table_name_suffix}\Z/
238
+ if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix.to_s.gsub('$','\$')}(.*)#{ActiveRecord::Base.table_name_suffix.to_s.gsub('$','\$')}\Z/
232
239
  "\"#{$1}\""
233
240
  else
234
241
  "\"#{table_name}\""
@@ -71,16 +71,21 @@ module ActiveRecord
71
71
  result = block.call(table_definition) if block
72
72
  create_sequence = create_sequence || table_definition.create_sequence
73
73
  column_comments = table_definition.column_comments if table_definition.column_comments
74
- tablespace = options[:tablespace] ? " TABLESPACE #{options[:tablespace]}" : ""
74
+ tablespace = tablespace_for(:table, options[:tablespace])
75
75
 
76
76
  if options[:force] && table_exists?(name)
77
77
  drop_table(name, options)
78
78
  end
79
79
 
80
80
  create_sql = "CREATE#{' GLOBAL TEMPORARY' if options[:temporary]} TABLE "
81
- create_sql << "#{quote_table_name(name)} ("
82
- create_sql << table_definition.to_sql
83
- create_sql << ")#{tablespace} #{options[:options]}"
81
+ create_sql << quote_table_name(name)
82
+ create_sql << " (#{table_definition.to_sql})"
83
+ unless options[:temporary]
84
+ create_sql << " ORGANIZATION #{options[:organization]}" if options[:organization]
85
+ create_sql << tablespace
86
+ table_definition.lob_columns.each{|cd| create_sql << tablespace_for(cd.sql_type.downcase.to_sym, nil, name, cd.name)}
87
+ end
88
+ create_sql << " #{options[:options]}"
84
89
  execute create_sql
85
90
 
86
91
  create_sequence_and_trigger(name, options) if create_sequence
@@ -113,7 +118,7 @@ module ActiveRecord
113
118
  if Hash === options # legacy support, since this param was a string
114
119
  index_type = options[:unique] ? "UNIQUE" : ""
115
120
  index_name = options[:name].to_s if options.key?(:name)
116
- tablespace = options[:tablespace] ? " TABLESPACE #{options[:tablespace]}" : ""
121
+ tablespace = tablespace_for(:index, options[:tablespace])
117
122
  else
118
123
  index_type = options
119
124
  end
@@ -124,7 +129,7 @@ module ActiveRecord
124
129
  if index_name_exists?(table_name, index_name, false)
125
130
  raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
126
131
  end
127
- quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
132
+ quoted_column_names = column_names.map { |e| quote_column_name_or_expression(e) }.join(", ")
128
133
 
129
134
  execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})#{tablespace} #{options[:options]}"
130
135
  ensure
@@ -189,10 +194,19 @@ module ActiveRecord
189
194
  result == 1
190
195
  end
191
196
 
197
+ def rename_index(table_name, index_name, new_index_name) #:nodoc:
198
+ unless index_name_exists?(table_name, index_name, true)
199
+ raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
200
+ end
201
+ execute "ALTER INDEX #{quote_column_name(index_name)} rename to #{quote_column_name(new_index_name)}"
202
+ ensure
203
+ self.all_schema_indexes = nil
204
+ end
205
+
192
206
  def add_column(table_name, column_name, type, options = {}) #:nodoc:
193
207
  add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
194
- options[:type] = type
195
- add_column_options!(add_column_sql, options)
208
+ add_column_options!(add_column_sql, options.merge(:type=>type, :column_name=>column_name, :table_name=>table_name))
209
+ add_column_sql << tablespace_for((type_to_sql(type).downcase.to_sym), nil, table_name, column_name)
196
210
  execute(add_column_sql)
197
211
  ensure
198
212
  clear_table_columns_cache(table_name)
@@ -224,8 +238,8 @@ module ActiveRecord
224
238
  end
225
239
 
226
240
  change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
227
- options[:type] = type
228
- add_column_options!(change_column_sql, options)
241
+ add_column_options!(change_column_sql, options.merge(:type=>type, :column_name=>column_name, :table_name=>table_name))
242
+ change_column_sql << tablespace_for((type_to_sql(type).downcase.to_sym), nil, options[:table_name], options[:column_name])
229
243
  execute(change_column_sql)
230
244
  ensure
231
245
  clear_table_columns_cache(table_name)
@@ -280,8 +294,33 @@ module ActiveRecord
280
294
  super
281
295
  end
282
296
 
297
+ def tablespace(table_name)
298
+ select_value <<-SQL
299
+ SELECT tablespace_name
300
+ FROM user_tables
301
+ WHERE table_name='#{table_name.to_s.upcase}'
302
+ SQL
303
+ end
304
+
283
305
  private
284
306
 
307
+ def tablespace_for(obj_type, tablespace_option, table_name=nil, column_name=nil)
308
+ tablespace_sql = ''
309
+ if tablespace = (tablespace_option || default_tablespace_for(obj_type))
310
+ tablespace_sql << if [:blob, :clob].include?(obj_type.to_sym)
311
+ " LOB (#{column_name}) STORE AS #{column_name.to_s[0..10]}_#{table_name.to_s[0..14]}_ls (TABLESPACE #{tablespace})"
312
+ else
313
+ " TABLESPACE #{tablespace}"
314
+ end
315
+ end
316
+ tablespace_sql
317
+ end
318
+
319
+ def default_tablespace_for(type)
320
+ (default_tablespaces[type] || default_tablespaces[native_database_types[type][:name]]) rescue nil
321
+ end
322
+
323
+
285
324
  def column_for(table_name, column_name)
286
325
  unless column = columns(table_name).find { |c| c.name == column_name.to_s }
287
326
  raise "No such column: #{table_name}.#{column_name}"
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # # ...
22
22
  # end
23
23
  #
24
- def add_primary_key_trigger(table_name, options)
24
+ def add_primary_key_trigger(table_name, options={})
25
25
  # call the same private method that is used for create_table :primary_key_trigger => true
26
26
  create_primary_key_trigger(table_name, options)
27
27
  end
@@ -6,21 +6,21 @@ module ActiveRecord #:nodoc:
6
6
  STATEMENT_TOKEN = "\n\n/\n\n"
7
7
 
8
8
  def structure_dump #:nodoc:
9
- structure = select_values("select sequence_name from user_sequences order by 1").map do |seq|
9
+ structure = select_values("SELECT sequence_name FROM user_sequences ORDER BY 1").map do |seq|
10
10
  "CREATE SEQUENCE \"#{seq}\""
11
11
  end
12
- select_values("select table_name from all_tables t
13
- where owner = sys_context('userenv','session_user') and secondary='N'
14
- and not exists (select mv.mview_name from all_mviews mv where mv.owner = t.owner and mv.mview_name = t.table_name)
15
- and not exists (select mvl.log_table from all_mview_logs mvl where mvl.log_owner = t.owner and mvl.log_table = t.table_name)
16
- order by 1").each do |table_name|
12
+ select_values("SELECT table_name FROM all_tables t
13
+ WHERE owner = SYS_CONTEXT('userenv', 'session_user') AND secondary = 'N'
14
+ AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
15
+ AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
16
+ ORDER BY 1").each do |table_name|
17
17
  virtual_columns = virtual_columns_for(table_name)
18
18
  ddl = "CREATE#{ ' GLOBAL TEMPORARY' if temporary_table?(table_name)} TABLE \"#{table_name}\" (\n"
19
19
  cols = select_all(%Q{
20
- select column_name, data_type, data_length, char_used, char_length, data_precision, data_scale, data_default, nullable
21
- from user_tab_columns
22
- where table_name = '#{table_name}'
23
- order by column_id
20
+ SELECT column_name, data_type, data_length, char_used, char_length, data_precision, data_scale, data_default, nullable
21
+ FROM user_tab_columns
22
+ WHERE table_name = '#{table_name}'
23
+ ORDER BY column_id
24
24
  }).map do |row|
25
25
  if(v = virtual_columns.find {|col| col['column_name'] == row['column_name']})
26
26
  structure_dump_virtual_column(row, v['data_default'])
@@ -71,13 +71,13 @@ module ActiveRecord #:nodoc:
71
71
  def structure_dump_primary_key(table) #:nodoc:
72
72
  opts = {:name => '', :cols => []}
73
73
  pks = select_all(<<-SQL, "Primary Keys")
74
- select a.constraint_name, a.column_name, a.position
75
- from user_cons_columns a
76
- join user_constraints c
77
- on a.constraint_name = c.constraint_name
78
- where c.table_name = '#{table.upcase}'
79
- and c.constraint_type = 'P'
80
- and c.owner = sys_context('userenv', 'session_user')
74
+ SELECT a.constraint_name, a.column_name, a.position
75
+ FROM user_cons_columns a
76
+ JOIN user_constraints c
77
+ ON a.constraint_name = c.constraint_name
78
+ WHERE c.table_name = '#{table.upcase}'
79
+ AND c.constraint_type = 'P'
80
+ AND c.owner = SYS_CONTEXT('userenv', 'session_user')
81
81
  SQL
82
82
  pks.each do |row|
83
83
  opts[:name] = row['constraint_name']
@@ -89,13 +89,13 @@ module ActiveRecord #:nodoc:
89
89
  def structure_dump_unique_keys(table) #:nodoc:
90
90
  keys = {}
91
91
  uks = select_all(<<-SQL, "Primary Keys")
92
- select a.constraint_name, a.column_name, a.position
93
- from user_cons_columns a
94
- join user_constraints c
95
- on a.constraint_name = c.constraint_name
96
- where c.table_name = '#{table.upcase}'
97
- and c.constraint_type = 'U'
98
- and c.owner = sys_context('userenv', 'session_user')
92
+ SELECT a.constraint_name, a.column_name, a.position
93
+ FROM user_cons_columns a
94
+ JOIN user_constraints c
95
+ ON a.constraint_name = c.constraint_name
96
+ WHERE c.table_name = '#{table.upcase}'
97
+ AND c.constraint_type = 'U'
98
+ AND c.owner = SYS_CONTEXT('userenv', 'session_user')
99
99
  SQL
100
100
  uks.each do |uk|
101
101
  keys[uk['constraint_name']] ||= []
@@ -123,7 +123,7 @@ module ActiveRecord #:nodoc:
123
123
  end
124
124
 
125
125
  def structure_dump_fk_constraints #:nodoc:
126
- fks = select_all("select table_name from all_tables where owner = sys_context('userenv','session_user') order by 1").map do |table|
126
+ fks = select_all("SELECT table_name FROM all_tables WHERE owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY 1").map do |table|
127
127
  if respond_to?(:foreign_keys) && (foreign_keys = foreign_keys(table["table_name"])).any?
128
128
  foreign_keys.map do |fk|
129
129
  sql = "ALTER TABLE #{quote_table_name(fk.from_table)} ADD CONSTRAINT #{quote_column_name(fk.options[:name])} "
@@ -143,19 +143,19 @@ module ActiveRecord #:nodoc:
143
143
  # Extract all stored procedures, packages, synonyms and views.
144
144
  def structure_dump_db_stored_code #:nodoc:
145
145
  structure = []
146
- select_all("select distinct name, type
147
- from all_source
148
- where type in ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TRIGGER', 'TYPE')
149
- and name not like 'BIN$%'
150
- and owner = sys_context('userenv','session_user') order by type").each do |source|
146
+ select_all("SELECT DISTINCT name, type
147
+ FROM all_source
148
+ WHERE type IN ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TRIGGER', 'TYPE')
149
+ AND name NOT LIKE 'BIN$%'
150
+ AND owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY type").each do |source|
151
151
  ddl = "CREATE OR REPLACE \n"
152
152
  lines = select_all(%Q{
153
- select text
154
- from all_source
155
- where name = '#{source['name']}'
156
- and type = '#{source['type']}'
157
- and owner = sys_context('userenv','session_user')
158
- order by line
153
+ SELECT text
154
+ FROM all_source
155
+ WHERE name = '#{source['name']}'
156
+ AND type = '#{source['type']}'
157
+ AND owner = SYS_CONTEXT('userenv', 'session_user')
158
+ ORDER BY line
159
159
  }).map do |row|
160
160
  ddl << row['text']
161
161
  end
@@ -164,14 +164,14 @@ module ActiveRecord #:nodoc:
164
164
  end
165
165
 
166
166
  # export views
167
- select_all("select view_name, text from user_views").each do |view|
167
+ select_all("SELECT view_name, text FROM user_views").each do |view|
168
168
  structure << "CREATE OR REPLACE VIEW #{view['view_name']} AS\n #{view['text']}"
169
169
  end
170
170
 
171
171
  # export synonyms
172
- select_all("select owner, synonym_name, table_name, table_owner
173
- from all_synonyms
174
- where owner = sys_context('userenv','session_user') ").each do |synonym|
172
+ select_all("SELECT owner, synonym_name, table_name, table_owner
173
+ FROM all_synonyms
174
+ WHERE owner = SYS_CONTEXT('userenv', 'session_user') ").each do |synonym|
175
175
  structure << "CREATE OR REPLACE #{synonym['owner'] == 'PUBLIC' ? 'PUBLIC' : '' } SYNONYM #{synonym['synonym_name']}"
176
176
  structure << " FOR #{synonym['table_owner']}.#{synonym['table_name']}"
177
177
  end
@@ -180,14 +180,14 @@ module ActiveRecord #:nodoc:
180
180
  end
181
181
 
182
182
  def structure_drop #:nodoc:
183
- statements = select_values("select sequence_name from user_sequences order by 1").map do |seq|
183
+ statements = select_values("SELECT sequence_name FROM user_sequences ORDER BY 1").map do |seq|
184
184
  "DROP SEQUENCE \"#{seq}\""
185
185
  end
186
- select_values("select table_name from all_tables t
187
- where owner = sys_context('userenv','session_user') and secondary='N'
188
- and not exists (select mv.mview_name from all_mviews mv where mv.owner = t.owner and mv.mview_name = t.table_name)
189
- and not exists (select mvl.log_table from all_mview_logs mvl where mvl.log_owner = t.owner and mvl.log_table = t.table_name)
190
- order by 1").each do |table|
186
+ select_values("SELECT table_name from all_tables t
187
+ WHERE owner = SYS_CONTEXT('userenv', 'session_user') AND secondary = 'N'
188
+ AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
189
+ AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
190
+ ORDER BY 1").each do |table|
191
191
  statements << "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
192
192
  end
193
193
  join_with_statement_token(statements)
@@ -195,8 +195,8 @@ module ActiveRecord #:nodoc:
195
195
 
196
196
  def temp_table_drop #:nodoc:
197
197
  join_with_statement_token(select_values(
198
- "select table_name from all_tables
199
- where owner = sys_context('userenv','session_user') and secondary='N' and temporary = 'Y' order by 1").map do |table|
198
+ "SELECT table_name FROM all_tables
199
+ WHERE owner = SYS_CONTEXT('userenv', 'session_user') AND secondary = 'N' AND temporary = 'Y' ORDER BY 1").map do |table|
200
200
  "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
201
201
  end)
202
202
  end
@@ -249,10 +249,10 @@ module ActiveRecord #:nodoc:
249
249
  def virtual_columns_for(table)
250
250
  begin
251
251
  select_all <<-SQL
252
- select column_name, data_default
253
- from user_tab_cols
254
- where virtual_column='YES'
255
- and table_name='#{table.upcase}'
252
+ SELECT column_name, data_default
253
+ FROM user_tab_cols
254
+ WHERE virtual_column = 'YES'
255
+ AND table_name = '#{table.upcase}'
256
256
  SQL
257
257
  # feature not supported previous to 11g
258
258
  rescue ActiveRecord::StatementInvalid => e
@@ -263,14 +263,14 @@ module ActiveRecord #:nodoc:
263
263
  def drop_sql_for_feature(type)
264
264
  short_type = type == 'materialized view' ? 'mview' : type
265
265
  join_with_statement_token(
266
- select_values("select #{short_type}_name from user_#{short_type.tableize}").map do |name|
266
+ select_values("SELECT #{short_type}_name FROM user_#{short_type.tableize}").map do |name|
267
267
  "DROP #{type.upcase} \"#{name}\""
268
268
  end)
269
269
  end
270
270
 
271
271
  def drop_sql_for_object(type)
272
272
  join_with_statement_token(
273
- select_values("select object_name from user_objects where object_type = '#{type.upcase}'").map do |name|
273
+ select_values("SELECT object_name FROM user_objects WHERE object_type = '#{type.upcase}'").map do |name|
274
274
  "DROP #{type.upcase} \"#{name}\""
275
275
  end)
276
276
  end
@@ -43,6 +43,8 @@ describe "OracleEnhancedAdapter" do
43
43
 
44
44
  describe "database session store" do
45
45
  before(:all) do
46
+ @conn.execute "DROP TABLE sessions" rescue nil
47
+ @conn.execute "DROP SEQUENCE sessions_seq" rescue nil
46
48
  @conn = ActiveRecord::Base.connection
47
49
  @conn.execute <<-SQL
48
50
  CREATE TABLE sessions (
@@ -112,6 +114,7 @@ describe "OracleEnhancedAdapter" do
112
114
  describe "ignore specified table columns" do
113
115
  before(:all) do
114
116
  @conn = ActiveRecord::Base.connection
117
+ @conn.execute "DROP TABLE test_employees" rescue nil
115
118
  @conn.execute <<-SQL
116
119
  CREATE TABLE test_employees (
117
120
  id NUMBER PRIMARY KEY,
@@ -128,6 +131,7 @@ describe "OracleEnhancedAdapter" do
128
131
  created_at DATE
129
132
  )
130
133
  SQL
134
+ @conn.execute "DROP SEQUENCE test_employees_seq" rescue nil
131
135
  @conn.execute <<-SQL
132
136
  CREATE SEQUENCE test_employees_seq MINVALUE 1
133
137
  INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE
@@ -142,6 +146,7 @@ describe "OracleEnhancedAdapter" do
142
146
  after(:each) do
143
147
  Object.send(:remove_const, "TestEmployee")
144
148
  ActiveRecord::Base.connection.clear_ignored_table_columns
149
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
145
150
  end
146
151
 
147
152
  it "should ignore specified table columns" do
@@ -181,16 +186,18 @@ describe "OracleEnhancedAdapter" do
181
186
  before(:all) do
182
187
  @conn = ActiveRecord::Base.connection
183
188
  @conn.execute "DROP TABLE test_employees" rescue nil
189
+ @oracle11g = !! @conn.select_value("SELECT * FROM v$version WHERE banner LIKE 'Oracle%11g%'")
184
190
  @conn.execute <<-SQL
185
191
  CREATE TABLE test_employees (
186
192
  id NUMBER PRIMARY KEY,
187
193
  first_name VARCHAR2(20),
188
194
  last_name VARCHAR2(25),
195
+ #{ @oracle11g ? "full_name AS (first_name || ' ' || last_name)," : "full_name VARCHAR2(46),"}
189
196
  hire_date DATE
190
197
  )
191
198
  SQL
192
- @column_names = ['id', 'first_name', 'last_name', 'hire_date']
193
- @column_sql_types = ["NUMBER", "VARCHAR2(20)", "VARCHAR2(25)", "DATE"]
199
+ @column_names = ['id', 'first_name', 'last_name', 'full_name', 'hire_date']
200
+ @column_sql_types = ["NUMBER", "VARCHAR2(20)", "VARCHAR2(25)", "VARCHAR2(46)", "DATE"]
194
201
  class ::TestEmployee < ActiveRecord::Base
195
202
  end
196
203
  # Another class using the same table
@@ -205,6 +212,7 @@ describe "OracleEnhancedAdapter" do
205
212
  Object.send(:remove_const, "TestEmployee2")
206
213
  @conn.execute "DROP TABLE test_employees"
207
214
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = nil
215
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
208
216
  end
209
217
 
210
218
  before(:each) do
@@ -223,16 +231,22 @@ describe "OracleEnhancedAdapter" do
223
231
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = false
224
232
  end
225
233
 
234
+ it 'should identify virtual columns as such' do
235
+ pending "Not supported in this database version" unless @oracle11g
236
+ te = TestEmployee.connection.columns('test_employees').detect(&:virtual?)
237
+ te.name.should == 'full_name'
238
+ end
239
+
226
240
  it "should get columns from database at first time" do
227
241
  TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
228
- @logger.logged(:debug).last.should =~ /select .* from all_tab_columns/im
242
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
229
243
  end
230
244
 
231
245
  it "should get columns from database at second time" do
232
246
  TestEmployee.connection.columns('test_employees')
233
247
  @logger.clear(:debug)
234
248
  TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
235
- @logger.logged(:debug).last.should =~ /select .* from all_tab_columns/im
249
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
236
250
  end
237
251
 
238
252
  it "should get primary key from database at first time" do
@@ -264,7 +278,7 @@ describe "OracleEnhancedAdapter" do
264
278
 
265
279
  it "should get columns from database at first time" do
266
280
  TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
267
- @logger.logged(:debug).last.should =~ /select .* from all_tab_columns/im
281
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
268
282
  end
269
283
 
270
284
  it "should get columns from cache at second time" do
@@ -310,6 +324,7 @@ describe "OracleEnhancedAdapter" do
310
324
  after(:all) do
311
325
  Object.send(:remove_const, "TestEmployee")
312
326
  @conn.execute "DROP TABLE test_employees"
327
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
313
328
  end
314
329
 
315
330
  it "should tell ActiveRecord that count distinct is supported" do
@@ -342,6 +357,7 @@ describe "OracleEnhancedAdapter" do
342
357
  end
343
358
  Object.send(:remove_const, "TestReservedWord")
344
359
  ActiveRecord::Base.table_name_prefix = nil
360
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
345
361
  end
346
362
 
347
363
  before(:each) do
@@ -371,6 +387,10 @@ describe "OracleEnhancedAdapter" do
371
387
  end
372
388
  end
373
389
 
390
+ it "should remove double quotes in column quoting" do
391
+ ActiveRecord::Base.connection.quote_column_name('aaa "bbb" ccc').should == '"aaa bbb ccc"'
392
+ end
393
+
374
394
  end
375
395
 
376
396
  describe "valid table names" do
@@ -527,6 +547,7 @@ describe "OracleEnhancedAdapter" do
527
547
  @conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
528
548
  @sys_conn.drop_table :test_posts rescue nil
529
549
  Object.send(:remove_const, "TestPost") rescue nil
550
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
530
551
  end
531
552
 
532
553
  it "should verify database link" do
@@ -563,8 +584,13 @@ describe "OracleEnhancedAdapter" do
563
584
 
564
585
  describe "temporary tables" do
565
586
  before(:all) do
587
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:table] = 'UNUSED'
588
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = 'UNUSED'
566
589
  @conn = ActiveRecord::Base.connection
567
590
  end
591
+ after(:all) do
592
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces={}
593
+ end
568
594
 
569
595
  after(:each) do
570
596
  @conn.drop_table :foos rescue nil
@@ -572,6 +598,7 @@ describe "OracleEnhancedAdapter" do
572
598
  it "should create ok" do
573
599
  @conn.create_table :foos, :temporary => true, :id => false do |t|
574
600
  t.integer :id
601
+ t.text :bar
575
602
  end
576
603
  end
577
604
  it "should show up as temporary" do
@@ -616,6 +643,7 @@ describe "OracleEnhancedAdapter" do
616
643
  end
617
644
  Object.send(:remove_const, "TestPost")
618
645
  Object.send(:remove_const, "TestComment")
646
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
619
647
  end
620
648
 
621
649
  it "should load included association with more than 1000 records" do