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
data/Rakefile CHANGED
@@ -21,7 +21,7 @@ EOS
21
21
  gem.email = "raimonds.simanovskis@gmail.com"
22
22
  gem.homepage = "http://github.com/rsim/oracle-enhanced"
23
23
  gem.authors = ["Raimonds Simanovskis"]
24
- gem.extra_rdoc_files = ['README.rdoc']
24
+ gem.extra_rdoc_files = ['README.md']
25
25
  end
26
26
  Jeweler::RubygemsDotOrgTasks.new
27
27
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.2
1
+ 1.4.0
@@ -5,25 +5,25 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{activerecord-oracle_enhanced-adapter}
8
- s.version = "1.3.2"
8
+ s.version = "1.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Raimonds Simanovskis"]
12
- s.date = %q{2011-01-05}
12
+ s.date = %q{2011-08-09}
13
13
  s.description = %q{Oracle "enhanced" ActiveRecord adapter contains useful additional methods for working with new and legacy Oracle databases.
14
14
  This adapter is superset of original ActiveRecord Oracle adapter.
15
15
  }
16
16
  s.email = %q{raimonds.simanovskis@gmail.com}
17
17
  s.extra_rdoc_files = [
18
- "README.rdoc"
18
+ "README.md"
19
19
  ]
20
20
  s.files = [
21
21
  ".rspec",
22
22
  "Gemfile",
23
23
  "History.txt",
24
24
  "License.txt",
25
- "README.rdoc",
26
- "RUNNING_TESTS.rdoc",
25
+ "README.md",
26
+ "RUNNING_TESTS.md",
27
27
  "Rakefile",
28
28
  "VERSION",
29
29
  "activerecord-oracle_enhanced-adapter.gemspec",
@@ -66,7 +66,7 @@ This adapter is superset of original ActiveRecord Oracle adapter.
66
66
  ]
67
67
  s.homepage = %q{http://github.com/rsim/oracle-enhanced}
68
68
  s.require_paths = ["lib"]
69
- s.rubygems_version = %q{1.4.1}
69
+ s.rubygems_version = %q{1.6.2}
70
70
  s.summary = %q{Oracle enhanced adapter for ActiveRecord}
71
71
  s.test_files = [
72
72
  "spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb",
@@ -97,7 +97,6 @@ This adapter is superset of original ActiveRecord Oracle adapter.
97
97
  s.add_development_dependency(%q<actionpack>, [">= 0"])
98
98
  s.add_development_dependency(%q<railties>, [">= 0"])
99
99
  s.add_development_dependency(%q<arel>, [">= 0"])
100
- s.add_development_dependency(%q<rack>, [">= 0"])
101
100
  s.add_development_dependency(%q<ruby-plsql>, [">= 0.4.4"])
102
101
  s.add_development_dependency(%q<ruby-oci8>, ["~> 2.0.4"])
103
102
  else
@@ -109,7 +108,6 @@ This adapter is superset of original ActiveRecord Oracle adapter.
109
108
  s.add_dependency(%q<actionpack>, [">= 0"])
110
109
  s.add_dependency(%q<railties>, [">= 0"])
111
110
  s.add_dependency(%q<arel>, [">= 0"])
112
- s.add_dependency(%q<rack>, [">= 0"])
113
111
  s.add_dependency(%q<ruby-plsql>, [">= 0.4.4"])
114
112
  s.add_dependency(%q<ruby-oci8>, ["~> 2.0.4"])
115
113
  end
@@ -122,7 +120,6 @@ This adapter is superset of original ActiveRecord Oracle adapter.
122
120
  s.add_dependency(%q<actionpack>, [">= 0"])
123
121
  s.add_dependency(%q<railties>, [">= 0"])
124
122
  s.add_dependency(%q<arel>, [">= 0"])
125
- s.add_dependency(%q<rack>, [">= 0"])
126
123
  s.add_dependency(%q<ruby-plsql>, [">= 0.4.4"])
127
124
  s.add_dependency(%q<ruby-oci8>, ["~> 2.0.4"])
128
125
  end
@@ -15,6 +15,39 @@ def redefine_task(*args, &block)
15
15
  end
16
16
  end
17
17
 
18
+ # Creates database user with db:create
19
+ def create_database_with_oracle_enhanced(config)
20
+ if config['adapter'] == 'oracle_enhanced'
21
+ print "Please provide the SYSTEM password for your oracle installation\n>"
22
+ system_password = $stdin.gets.strip
23
+ ActiveRecord::Base.establish_connection(config.merge('username' => 'SYSTEM', 'password' => system_password))
24
+ ActiveRecord::Base.connection.execute "DROP USER #{config['username']} CASCADE" rescue nil
25
+ ActiveRecord::Base.connection.execute "CREATE USER #{config['username']} IDENTIFIED BY #{config['password']}"
26
+ ActiveRecord::Base.connection.execute "GRANT unlimited tablespace TO #{config['username']}"
27
+ ActiveRecord::Base.connection.execute "GRANT create session TO #{config['username']}"
28
+ ActiveRecord::Base.connection.execute "GRANT create table TO #{config['username']}"
29
+ ActiveRecord::Base.connection.execute "GRANT create sequence TO #{config['username']}"
30
+ else
31
+ create_database_without_oracle_enhanced(config)
32
+ end
33
+ end
34
+ alias :create_database_without_oracle_enhanced :create_database
35
+ alias :create_database :create_database_with_oracle_enhanced
36
+
37
+ # Drops database user with db:drop
38
+ def drop_database_with_oracle_enhanced(config)
39
+ if config['adapter'] == 'oracle_enhanced'
40
+ print "Please provide the SYSTEM password for your oracle installation\n>"
41
+ system_password = $stdin.gets.strip
42
+ ActiveRecord::Base.establish_connection(config.merge('username' => 'SYSTEM', 'password' => system_password))
43
+ ActiveRecord::Base.connection.execute "DROP USER #{config['username']} CASCADE"
44
+ else
45
+ drop_database_without_oracle_enhanced(config)
46
+ end
47
+ end
48
+ alias :drop_database_without_oracle_enhanced :drop_database
49
+ alias :drop_database :drop_database_with_oracle_enhanced
50
+
18
51
  namespace :db do
19
52
 
20
53
  namespace :structure do
@@ -53,6 +86,7 @@ namespace :db do
53
86
  if abcs['test']['adapter'] == 'oracle_enhanced'
54
87
  ActiveRecord::Base.establish_connection(:test)
55
88
  ActiveRecord::Base.connection.execute_structure_dump(ActiveRecord::Base.connection.full_drop)
89
+ ActiveRecord::Base.connection.execute("PURGE RECYCLEBIN") rescue nil
56
90
  else
57
91
  Array(existing_actions).each{|action| action.call}
58
92
  end
@@ -131,6 +131,19 @@ module ActiveRecord
131
131
  # that Date columns are explicily defined with +set_date_columns+ method.
132
132
  cattr_accessor :emulate_dates
133
133
  self.emulate_dates = false
134
+
135
+ ##
136
+ # :singleton-method:
137
+ # OracleEnhancedAdapter will use the default tablespace, but if you want specific types of
138
+ # objects to go into specific tablespaces, specify them like this in an initializer:
139
+ #
140
+ # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
141
+ # {:clob => 'TS_LOB', :blob => 'TS_LOB', :index => 'TS_INDEX', :table => 'TS_DATA'}
142
+ #
143
+ # Using the :tablespace option where available (e.g create_table) will take precedence
144
+ # over these settings.
145
+ cattr_accessor :default_tablespaces
146
+ self.default_tablespaces={}
134
147
 
135
148
  ##
136
149
  # :singleton-method:
@@ -229,6 +242,10 @@ module ActiveRecord
229
242
  @enable_dbms_output = false
230
243
  end
231
244
 
245
+ def self.visitor_for(pool) # :nodoc:
246
+ Arel::Visitors::Oracle.new(pool)
247
+ end
248
+
232
249
  ADAPTER_NAME = 'OracleEnhanced'.freeze
233
250
 
234
251
  def adapter_name #:nodoc:
@@ -285,7 +302,8 @@ module ActiveRecord
285
302
  :time => { :name => "DATE" },
286
303
  :date => { :name => "DATE" },
287
304
  :binary => { :name => "BLOB" },
288
- :boolean => { :name => "NUMBER", :limit => 1 }
305
+ :boolean => { :name => "NUMBER", :limit => 1 },
306
+ :raw => { :name => "RAW", :limit => 2000 }
289
307
  }
290
308
  # if emulate_booleans_from_strings then store booleans in VARCHAR2
291
309
  NATIVE_DATABASE_TYPES_BOOLEAN_STRINGS = NATIVE_DATABASE_TYPES.dup.merge(
@@ -324,30 +342,42 @@ module ActiveRecord
324
342
  def in_clause_length
325
343
  1000
326
344
  end
345
+ alias ids_in_list_limit in_clause_length
327
346
 
328
347
  # QUOTING ==================================================
329
348
  #
330
349
  # see: abstract/quoting.rb
331
350
 
332
351
  def quote_column_name(name) #:nodoc:
333
- # camelCase column names need to be quoted; not that anyone using Oracle
334
- # would really do this, but handling this case means we pass the test...
335
352
  name = name.to_s
336
353
  @quoted_column_names[name] ||= begin
337
- case name
338
- # if only valid column characters in name
339
- when /^[a-z][a-z_0-9\$#]*$/
354
+ # if only valid lowercase column characters in name
355
+ if name =~ /\A[a-z][a-z_0-9\$#]*\Z/
340
356
  "\"#{name.upcase}\""
341
- when /^[a-z][a-z_0-9\$#\-]*$/i
342
- "\"#{name}\""
343
- # if other characters present then assume that it is expression
344
- # which should not be quoted
345
357
  else
346
- name
358
+ # remove double quotes which cannot be used inside quoted identifier
359
+ "\"#{name.gsub('"', '')}\""
347
360
  end
348
361
  end
349
362
  end
350
363
 
364
+ # This method is used in add_index to identify either column name (which is quoted)
365
+ # or function based index (in which case function expression is not quoted)
366
+ def quote_column_name_or_expression(name) #:nodoc:
367
+ name = name.to_s
368
+ case name
369
+ # if only valid lowercase column characters in name
370
+ when /^[a-z][a-z_0-9\$#]*$/
371
+ "\"#{name.upcase}\""
372
+ when /^[a-z][a-z_0-9\$#\-]*$/i
373
+ "\"#{name}\""
374
+ # if other characters present then assume that it is expression
375
+ # which should not be quoted
376
+ else
377
+ name
378
+ end
379
+ end
380
+
351
381
  # Names must be from 1 to 30 bytes long with these exceptions:
352
382
  # * Names of databases are limited to 8 bytes.
353
383
  # * Names of database links can be as long as 128 bytes.
@@ -395,6 +425,8 @@ module ActiveRecord
395
425
  # NLS_DATE_FORMAT independent DATE support
396
426
  when :date, :time, :datetime
397
427
  quote_date_with_to_date(value)
428
+ when :raw
429
+ quote_raw(value)
398
430
  when :string
399
431
  # NCHAR and NVARCHAR2 literals should be quoted with N'...'.
400
432
  # Read directly instance variable as otherwise migrations with table column default values are failing
@@ -429,12 +461,45 @@ module ActiveRecord
429
461
  "TO_DATE('#{value}','YYYY-MM-DD HH24:MI:SS')"
430
462
  end
431
463
 
464
+ # Encode a string or byte array as string of hex codes
465
+ def self.encode_raw(value)
466
+ # When given a string, convert to a byte array.
467
+ value = value.unpack('C*') if value.is_a?(String)
468
+ value.map { |x| "%02X" % x }.join
469
+ end
470
+
471
+ # quote encoded raw value
472
+ def quote_raw(value) #:nodoc:
473
+ "'#{self.class.encode_raw(value)}'"
474
+ end
475
+
432
476
  def quote_timestamp_with_to_timestamp(value) #:nodoc:
433
477
  # add up to 9 digits of fractional seconds to inserted time
434
478
  value = "#{quoted_date(value)}:#{("%.6f"%value.to_f).split('.')[1]}" if value.acts_like?(:time)
435
479
  "TO_TIMESTAMP('#{value}','YYYY-MM-DD HH24:MI:SS:FF6')"
436
480
  end
437
481
 
482
+ # Cast a +value+ to a type that the database understands.
483
+ def type_cast(value, column)
484
+ case value
485
+ when true, false
486
+ if emulate_booleans_from_strings || column && column.type == :string
487
+ self.class.boolean_to_string(value)
488
+ else
489
+ value ? 1 : 0
490
+ end
491
+ when Date, Time
492
+ if value.acts_like?(:time)
493
+ zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
494
+ value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
495
+ else
496
+ value
497
+ end
498
+ else
499
+ super
500
+ end
501
+ end
502
+
438
503
  # CONNECTION MANAGEMENT ====================================
439
504
  #
440
505
 
@@ -493,8 +558,8 @@ module ActiveRecord
493
558
  log(sql, name) { @connection.exec(sql) }
494
559
  end
495
560
 
496
- def substitute_for(column, current_values)
497
- Arel.sql(":a#{current_values.length + 1}")
561
+ def substitute_at(column, index)
562
+ Arel.sql(":a#{index + 1}")
498
563
  end
499
564
 
500
565
  def clear_cache!
@@ -505,7 +570,7 @@ module ActiveRecord
505
570
  end
506
571
 
507
572
  def exec_query(sql, name = 'SQL', binds = [])
508
- log(sql, name) do
573
+ log(sql, name, binds) do
509
574
  cursor = nil
510
575
  cached = false
511
576
  if binds.empty?
@@ -517,10 +582,11 @@ module ActiveRecord
517
582
 
518
583
  cursor = @statements[sql]
519
584
 
520
- binds = binds.map do |col, val|
521
- col ? col.type_cast(val) : val
585
+ binds.each_with_index do |bind, i|
586
+ col, val = bind
587
+ cursor.bind_param(i + 1, type_cast(val, col), col && col.type)
522
588
  end
523
- binds.each_with_index { |val, i| cursor.bind_param(i + 1, val) }
589
+
524
590
  cached = true
525
591
  end
526
592
 
@@ -570,6 +636,69 @@ module ActiveRecord
570
636
  end
571
637
  protected :insert_sql
572
638
 
639
+ # New method in ActiveRecord 3.1
640
+ # Will add RETURNING clause in case of trigger generated primary keys
641
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
642
+ unless id_value || pk.nil?
643
+ sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO :returning_id"
644
+ (binds = binds.dup) << [:returning_id, nil]
645
+ end
646
+ [sql, binds]
647
+ end
648
+
649
+ EXEC_INSERT_RESULT_COLUMNS = %w(returning_id) #:nodoc:
650
+
651
+ # New method in ActiveRecord 3.1
652
+ def exec_insert(sql, name, binds)
653
+ log(sql, name, binds) do
654
+ returning_id_index = nil
655
+ cursor = if @statements.key?(sql)
656
+ @statements[sql]
657
+ else
658
+ @statements[sql] = @connection.prepare(sql)
659
+ end
660
+
661
+ binds.each_with_index do |bind, i|
662
+ col, val = bind
663
+ if col == :returning_id
664
+ returning_id_index = i + 1
665
+ cursor.bind_returning_param(returning_id_index, Integer)
666
+ else
667
+ cursor.bind_param(i + 1, type_cast(val, col), col && col.type)
668
+ end
669
+ end
670
+
671
+ cursor.exec_update
672
+
673
+ rows = []
674
+ if returning_id_index
675
+ returning_id = cursor.get_returning_param(returning_id_index, Integer)
676
+ rows << [returning_id]
677
+ end
678
+ ActiveRecord::Result.new(EXEC_INSERT_RESULT_COLUMNS, rows)
679
+ end
680
+ end
681
+
682
+ # New method in ActiveRecord 3.1
683
+ def exec_update(sql, name, binds)
684
+ log(sql, name, binds) do
685
+ cursor = if @statements.key?(sql)
686
+ @statements[sql]
687
+ else
688
+ @statements[sql] = @connection.prepare(sql)
689
+ end
690
+
691
+ binds.each_with_index do |bind, i|
692
+ col, val = bind
693
+ cursor.bind_param(i + 1, type_cast(val, col), col && col.type)
694
+ end
695
+
696
+ cursor.exec_update
697
+ end
698
+ end
699
+
700
+ alias :exec_delete :exec_update
701
+
573
702
  # use in set_sequence_name to avoid fetching primary key value from sequence
574
703
  AUTOGENERATED_SEQUENCE_NAME = 'autogenerated'.freeze
575
704
 
@@ -617,11 +746,11 @@ module ActiveRecord
617
746
  limit = options[:limit]
618
747
  limit = limit.is_a?(String) && limit.blank? ? nil : limit && limit.to_i
619
748
  if limit && offset > 0
620
- sql.replace "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_ where rownum <= #{offset+limit}) where raw_rnum_ > #{offset}"
749
+ sql.replace "SELECT * FROM (SELECT raw_sql_.*, ROWNUM raw_rnum_ FROM (#{sql}) raw_sql_ WHERE ROWNUM <= #{offset+limit}) WHERE raw_rnum_ > #{offset}"
621
750
  elsif limit
622
- sql.replace "select * from (#{sql}) where rownum <= #{limit}"
751
+ sql.replace "SELECT * FROM (#{sql}) WHERE ROWNUM <= #{limit}"
623
752
  elsif offset > 0
624
- sql.replace "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_) where raw_rnum_ > #{offset}"
753
+ sql.replace "SELECT * FROM (SELECT raw_sql_.*, ROWNUM raw_rnum_ FROM (#{sql}) raw_sql_) WHERE raw_rnum_ > #{offset}"
625
754
  end
626
755
  end
627
756
 
@@ -630,7 +759,16 @@ module ActiveRecord
630
759
  # Returns true for Oracle adapter (since Oracle requires primary key
631
760
  # values to be pre-fetched before insert). See also #next_sequence_value.
632
761
  def prefetch_primary_key?(table_name = nil)
633
- ! @@do_not_prefetch_primary_key[table_name.to_s]
762
+ return true if table_name.nil?
763
+ table_name = table_name.to_s
764
+ do_not_prefetch = @@do_not_prefetch_primary_key[table_name]
765
+ if do_not_prefetch.nil?
766
+ owner, desc_table_name, db_link = @connection.describe(table_name)
767
+ @@do_not_prefetch_primary_key[table_name] = do_not_prefetch =
768
+ !has_primary_key?(table_name, owner, desc_table_name, db_link) ||
769
+ has_primary_key_trigger?(table_name, owner, desc_table_name, db_link)
770
+ end
771
+ !do_not_prefetch
634
772
  end
635
773
 
636
774
  # used just in tests to clear prefetch primary key flag for all tables
@@ -650,7 +788,13 @@ module ActiveRecord
650
788
  def insert_fixture(fixture, table_name) #:nodoc:
651
789
  super
652
790
 
653
- klass = fixture.class_name.constantize rescue nil
791
+ if ActiveRecord::Base.pluralize_table_names
792
+ klass = table_name.singularize.camelize
793
+ else
794
+ klass = table_name.camelize
795
+ end
796
+
797
+ klass = klass.constantize rescue nil
654
798
  if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base)
655
799
  write_lobs(table_name, klass, fixture)
656
800
  end
@@ -684,22 +828,22 @@ module ActiveRecord
684
828
 
685
829
  # Current database name
686
830
  def current_database
687
- select_value("select sys_context('userenv','db_name') from dual")
831
+ select_value("SELECT SYS_CONTEXT('userenv', 'db_name') FROM dual")
688
832
  end
689
833
 
690
834
  # Current database session user
691
835
  def current_user
692
- select_value("select sys_context('userenv','session_user') from dual")
836
+ select_value("SELECT SYS_CONTEXT('userenv', 'session_user') FROM dual")
693
837
  end
694
838
 
695
839
  # Default tablespace name of current user
696
840
  def default_tablespace
697
- select_value("select lower(default_tablespace) from user_users where username = sys_context('userenv','session_user')")
841
+ select_value("SELECT LOWER(default_tablespace) FROM user_users WHERE username = SYS_CONTEXT('userenv', 'session_user')")
698
842
  end
699
843
 
700
844
  def tables(name = nil) #:nodoc:
701
845
  select_values(
702
- "select decode(table_name,upper(table_name),lower(table_name),table_name) from all_tables where owner = sys_context('userenv','session_user') and secondary='N'",
846
+ "SELECT DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name) FROM all_tables WHERE owner = SYS_CONTEXT('userenv', 'session_user') AND secondary = 'N'",
703
847
  name)
704
848
  end
705
849
 
@@ -712,7 +856,7 @@ module ActiveRecord
712
856
  end
713
857
 
714
858
  def materialized_views #:nodoc:
715
- select_values("select lower(mview_name) from all_mviews where owner = sys_context('userenv','session_user')")
859
+ select_values("SELECT LOWER(mview_name) FROM all_mviews WHERE owner = SYS_CONTEXT('userenv', 'session_user')")
716
860
  end
717
861
 
718
862
  cattr_accessor :all_schema_indexes #:nodoc:
@@ -723,7 +867,7 @@ module ActiveRecord
723
867
  (owner, table_name, db_link) = @connection.describe(table_name)
724
868
  unless all_schema_indexes
725
869
  default_tablespace_name = default_tablespace
726
- result = select_all(<<-SQL)
870
+ result = select_all(<<-SQL.strip.gsub(/\s+/, ' '))
727
871
  SELECT LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
728
872
  i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
729
873
  LOWER(i.tablespace_name) AS tablespace_name,
@@ -749,13 +893,16 @@ module ActiveRecord
749
893
  statement_parameters = nil
750
894
  if row['index_type'] == 'DOMAIN' && row['ityp_owner'] == 'CTXSYS' && row['ityp_name'] == 'CONTEXT'
751
895
  procedure_name = default_datastore_procedure(row['index_name'])
752
- statement_parameters = select_value(<<-SQL)
753
- SELECT SUBSTR(text,LENGTH('-- add_context_index_parameters ')+1)
896
+ source = select_values(<<-SQL).join
897
+ SELECT text
754
898
  FROM all_source#{db_link}
755
899
  WHERE owner = '#{owner}'
756
900
  AND name = '#{procedure_name.upcase}'
757
- AND text LIKE '-- add_context_index_parameters %'
901
+ ORDER BY line
758
902
  SQL
903
+ if source =~ /-- add_context_index_parameters (.+)\n/
904
+ statement_parameters = $1
905
+ end
759
906
  end
760
907
  all_schema_indexes << OracleEnhancedIndexDefinition.new(row['table_name'], row['index_name'],
761
908
  row['uniqueness'] == "UNIQUE", row['index_type'] == 'DOMAIN' ? "#{row['ityp_owner']}.#{row['ityp_name']}" : nil,
@@ -855,22 +1002,23 @@ module ActiveRecord
855
1002
 
856
1003
  (owner, desc_table_name, db_link) = @connection.describe(table_name)
857
1004
 
858
- @@do_not_prefetch_primary_key[table_name] =
859
- !has_primary_key?(table_name, owner, desc_table_name, db_link) ||
860
- has_primary_key_trigger?(table_name, owner, desc_table_name, db_link)
1005
+ # reset do_not_prefetch_primary_key cache for this table
1006
+ @@do_not_prefetch_primary_key[table_name] = nil
861
1007
 
862
- table_cols = <<-SQL
863
- select column_name as name, data_type as sql_type, data_default, nullable,
864
- decode(data_type, 'NUMBER', data_precision,
1008
+ table_cols = <<-SQL.strip.gsub(/\s+/, ' ')
1009
+ SELECT column_name AS name, data_type AS sql_type, data_default, nullable, virtual_column, hidden_column,
1010
+ DECODE(data_type, 'NUMBER', data_precision,
865
1011
  'FLOAT', data_precision,
866
- 'VARCHAR2', decode(char_used, 'C', char_length, data_length),
867
- 'CHAR', decode(char_used, 'C', char_length, data_length),
868
- null) as limit,
869
- decode(data_type, 'NUMBER', data_scale, null) as scale
870
- from all_tab_columns#{db_link}
871
- where owner = '#{owner}'
872
- and table_name = '#{desc_table_name}'
873
- order by column_id
1012
+ 'VARCHAR2', DECODE(char_used, 'C', char_length, data_length),
1013
+ 'RAW', DECODE(char_used, 'C', char_length, data_length),
1014
+ 'CHAR', DECODE(char_used, 'C', char_length, data_length),
1015
+ NULL) AS limit,
1016
+ DECODE(data_type, 'NUMBER', data_scale, NULL) AS scale
1017
+ FROM all_tab_cols#{db_link}
1018
+ WHERE owner = '#{owner}'
1019
+ AND table_name = '#{desc_table_name}'
1020
+ AND hidden_column = 'NO'
1021
+ ORDER BY column_id
874
1022
  SQL
875
1023
 
876
1024
  # added deletion of ignored columns
@@ -899,7 +1047,7 @@ module ActiveRecord
899
1047
  # pass table name for table specific column definitions
900
1048
  table_name,
901
1049
  # pass column type if specified in class definition
902
- get_type_for_column(table_name, oracle_downcase(row['name'])))
1050
+ get_type_for_column(table_name, oracle_downcase(row['name'])), row['virtual_column']=='YES')
903
1051
  end
904
1052
  end
905
1053
 
@@ -940,14 +1088,14 @@ module ActiveRecord
940
1088
  (owner, desc_table_name, db_link) = @connection.describe(table_name) unless owner
941
1089
 
942
1090
  # changed back from user_constraints to all_constraints for consistency
943
- pks = select_values(<<-SQL, 'Primary Key')
944
- select cc.column_name
945
- from all_constraints#{db_link} c, all_cons_columns#{db_link} cc
946
- where c.owner = '#{owner}'
947
- and c.table_name = '#{desc_table_name}'
948
- and c.constraint_type = 'P'
949
- and cc.owner = c.owner
950
- and cc.constraint_name = c.constraint_name
1091
+ pks = select_values(<<-SQL.strip.gsub(/\s+/, ' '), 'Primary Key')
1092
+ SELECT cc.column_name
1093
+ FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc
1094
+ WHERE c.owner = '#{owner}'
1095
+ AND c.table_name = '#{desc_table_name}'
1096
+ AND c.constraint_type = 'P'
1097
+ AND cc.owner = c.owner
1098
+ AND cc.constraint_name = c.constraint_name
951
1099
  SQL
952
1100
 
953
1101
  # only support single column keys
@@ -994,7 +1142,7 @@ module ActiveRecord
994
1142
  end
995
1143
 
996
1144
  def temporary_table?(table_name) #:nodoc:
997
- select_value("select temporary from user_tables where table_name = '#{table_name.upcase}'") == 'Y'
1145
+ select_value("SELECT temporary FROM user_tables WHERE table_name = '#{table_name.upcase}'") == 'Y'
998
1146
  end
999
1147
 
1000
1148
  # ORDER BY clause for the passed order option.
@@ -1073,8 +1221,12 @@ module ActiveRecord
1073
1221
  end
1074
1222
 
1075
1223
  protected
1076
- def log(sql, name) #:nodoc:
1077
- super sql, name
1224
+ def log(sql, name, binds = nil) #:nodoc:
1225
+ if binds
1226
+ super sql, name, binds
1227
+ else
1228
+ super sql, name
1229
+ end
1078
1230
  ensure
1079
1231
  log_dbms_output if dbms_output_enabled?
1080
1232
  end