activerecord-oracle_enhanced-adapter 1.4.3 → 1.5.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -14
  3. data/History.md +51 -0
  4. data/README.md +32 -1
  5. data/VERSION +1 -1
  6. data/activerecord-oracle_enhanced-adapter.gemspec +2 -4
  7. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +315 -57
  8. data/lib/active_record/connection_adapters/oracle_enhanced_column_dumper.rb +55 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +4 -13
  10. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +5 -6
  11. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +19 -11
  12. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +163 -232
  13. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +18 -10
  14. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +20 -32
  15. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +54 -35
  16. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +5 -74
  17. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +3 -2
  18. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +98 -98
  19. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +5 -1
  20. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +3 -3
  21. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +11 -5
  22. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +56 -55
  23. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +15 -8
  24. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +4 -3
  25. data/spec/spec_helper.rb +25 -54
  26. metadata +32 -20
  27. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +0 -41
  28. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +0 -121
  29. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 884d43f2d9c1a11b888e5030903457d3ded3affe
4
- data.tar.gz: 326b24f0cc5cdc842c4eba64c9c79d90cd74ef35
3
+ metadata.gz: a74f5a066c9c346da43e6a9d740a3aff47e59ef2
4
+ data.tar.gz: af9745bc4a32f6d765a5d536d2e13d8a5962eed3
5
5
  SHA512:
6
- metadata.gz: e7b653d6e585e61b3e81c8c5e71ea690b7c1d0467835953a60a2775d0be8e076b6bf8a2913d6df73bfbb33d3cbdacea1b89a5f4d554515059b0fa98073504091
7
- data.tar.gz: f73bf37bc3bd0b58f346ae2a4e18ab4338b093ac24ee7b96f06846810093b6afb145f85009735538d00b375ceedb3de922faf2b1f9ac77fcdeae979667f5b0a5
6
+ metadata.gz: 4307827c8682b9654fad38a2cdca95d0a93a864401a09f9e88bc0db787faa825605631c7867635ae26d6e58796a846c9cefa35b2a18a11c2ab5a79cff6ec9b56
7
+ data.tar.gz: 78cd7ef1859e4a8ac0d2915a66971ff8a45282c8c90284259e39d4d832682876cb1b4f06d9a32135a68652bc3456c6b45f03c243afb675dc029900287d09611d
data/Gemfile CHANGED
@@ -9,18 +9,7 @@ group :development do
9
9
  gem 'activerecord', "=#{ENV['RAILS_GEM_VERSION']}"
10
10
  gem 'actionpack', "=#{ENV['RAILS_GEM_VERSION']}"
11
11
  gem 'activesupport', "=#{ENV['RAILS_GEM_VERSION']}"
12
- case ENV['RAILS_GEM_VERSION']
13
- when /^2.0/
14
- gem 'composite_primary_keys', '=0.9.93'
15
- when /^2.1/
16
- gem 'composite_primary_keys', '=1.0.8'
17
- when /^2.2/
18
- gem 'composite_primary_keys', '=2.2.2'
19
- when /^2.3.3/
20
- gem 'composite_primary_keys', '=2.3.2'
21
- when /^3/
22
- gem 'railties', "=#{ENV['RAILS_GEM_VERSION']}"
23
- end
12
+ gem 'railties', "=#{ENV['RAILS_GEM_VERSION']}"
24
13
  else
25
14
  %w(activerecord activemodel activesupport actionpack railties).each do |gem_name|
26
15
  if ENV['RAILS_GEM_PATH']
@@ -43,10 +32,11 @@ group :development do
43
32
  end
44
33
  end
45
34
 
46
- gem 'ruby-plsql', '>=0.4.4'
35
+ gem "activerecord-deprecated_finders"
36
+ gem 'ruby-plsql', '>=0.5.0'
47
37
 
48
38
  platforms :ruby do
49
- gem 'ruby-oci8', '>=2.0.4'
39
+ gem 'ruby-oci8', '>=2.1.2'
50
40
  end
51
41
 
52
42
  end
data/History.md CHANGED
@@ -1,3 +1,54 @@
1
+ ## 1.5.0.rc1 / 2013-10-28
2
+
3
+ * Enhancements and major changes
4
+ * Support Rails 4.0
5
+ * Desupport Rails 3.2 and lower version. To support Rails 3.2, use Version 1.4.3
6
+ * Drop session store support [#219]
7
+ * Create indexes automatically for references and belongs_to [#183]
8
+ * Use the index name explicitly provided in a migration when reverting [#296]
9
+ * Rename indexes when a table or column is renamed [#286]
10
+ * Support refactored remove_column [#172]
11
+ * Support allowed_index_name_length method [#285]
12
+ * Remove schema prefix from sequence name if present before truncating [#155]
13
+ * Bumped jeweler, ruby-plsql and ruby-oci8 version [#176]
14
+ * Support also ojdbc6.jar for Java 1.7 [#350]
15
+ * Support "activerecord-deprecated_finders" [#210]
16
+ * Prepared statements can be disabled [#295]
17
+ * Ensure disconnecting or reconnecting resets the transaction state [#220]
18
+ * Support for specifying transaction isolation level [#226]
19
+ * Rename the partial_updates config to partial_writes [#234]
20
+ * Deprecate passing a string as third argument of add_index [#242]
21
+ * Rename update method to update_record, create method to create_record [#273]
22
+ * Deprecate #connection in favour of accessing it via the class [#297]
23
+ * Support SchemaCreation [#298]
24
+ * Add support for foreign key creation in create_table [#317]
25
+ * Add virtual columns support for rail4 branch [#329]
26
+ * Support columns_for_distinct method [#340]
27
+ * Clear index cache when any table dropped [#200]
28
+ * Clear index cache when remove_column executed [#269]
29
+ * Dump schema uses ruby 1.9 style hash [#229]
30
+ * Support _field_changed? and drop field_changed? [#182 #254]
31
+ * Use arel nodes instead of raw sql [#198]
32
+ * Raise an ArgumentError when passing an invalid option to add_index [#242]
33
+ * Split OracleEnhancedColumnDumper from OracleEnhancedSchemaDumper [#292]
34
+ * Unit test sets default_timezone = :local [#184]
35
+ * Support reset_pk_sequence! [#287]
36
+
37
+ * Bug Fix
38
+ * Address ArgumentError: wrong number of arguments (5 for 3) [#166]
39
+ * Address NoMethodError: undefined method `column_types' [#173]
40
+ * Schema dumper removes table_name_prefix and table_name_suffix [#191]
41
+ * Add clear_logger to address ArgumentError: wrong number of arguments (1 for 2) [#193]
42
+ * Use Relation#to_a as Relation#all is deprecated in Rails [#203]
43
+ * Address Address test_integer_zero_to_integer_zero_not_marked_as_changed failure [#207]
44
+ * Address NoMethodError undefined method `default_string' [#221]
45
+ * Address you can't redefine the primary key column 'id'. To define a custom primary key, pass { id: false } to create_table [#238]
46
+ * Remove unnecessary DEPRECATION WARNING [#255]
47
+ * Assigning "0.0" to a nullable numeric column does not make it dirty [#293]
48
+
49
+ * Known Issues
50
+ * Oracle Text features are not fully supported with Oracle 12c [#331]
51
+
1
52
  ### 1.4.3 / 2013-10-24
2
53
 
3
54
  * No changes since 1.4.3.rc2
data/README.md CHANGED
@@ -6,11 +6,42 @@ Oracle enhanced adapter for ActiveRecord
6
6
  DESCRIPTION
7
7
  -----------
8
8
 
9
- Oracle enhanced ActiveRecord adapter provides Oracle database access from Ruby on Rails applications. Oracle enhanced adapter can be used from Ruby on Rails versions 2.3.x and 3.x and it is working with Oracle database versions 10g and 11g.
9
+ Oracle enhanced ActiveRecord adapter provides Oracle database access from Ruby on Rails applications. Oracle enhanced adapter can be used from Ruby on Rails versions between 2.3.x and 4.0 and it is working with Oracle database versions from 10g to 12c.
10
10
 
11
11
  INSTALLATION
12
12
  ------------
13
13
 
14
+ ### Rails 4
15
+
16
+ Oracle enhanced adapter version 1.5 just supports Rails 4 and does not support Rails 3.2 or lower version of Rails.
17
+
18
+ When using Ruby on Rails version 4 then in Gemfile include
19
+
20
+ gem 'activerecord-oracle_enhanced-adapter', '~> 1.5.0'
21
+
22
+ where instead of 1.5.0 you can specify any other desired version. It is recommended to specify version with `~>` which means that use specified version or later patch versions (in this example any later 1.5.x version but not 1.6.x version). Oracle enhanced adapter maintains API backwards compatibility during patch version upgrades and therefore it is safe to always upgrade to latest patch version.
23
+
24
+ If you would like to use latest adapter version from github then specify
25
+
26
+ gem 'activerecord-oracle_enhanced-adapter', :git => 'git://github.com/rsim/oracle-enhanced.git'
27
+
28
+ If you are using CRuby 1.9.3 or 2.0 then you need to install ruby-oci8 gem as well as Oracle client, e.g. [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html). Include in Gemfile also ruby-oci8:
29
+
30
+ gem 'ruby-oci8', '~> 2.1.0'
31
+
32
+ If you are using JRuby then you need to download latest [Oracle JDBC driver](http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html) - either ojdbc7.jar or ojdbc6.jar for Java 7, ojdbc6.jar for Java 6 or ojdbc5.jar for Java 5. And copy this file to one of these locations:
33
+
34
+ * in `./lib` directory of Rails application
35
+ * in some directory which is in `PATH`
36
+ * in `JRUBY_HOME/lib` directory
37
+ * or include path to JDBC driver jar file in Java `CLASSPATH`
38
+
39
+ After specifying necessary gems in Gemfile run
40
+
41
+ bundle install
42
+
43
+ to install the adapter (or later run `bundle update` to force updating to latest version).
44
+
14
45
  ### Rails 3
15
46
 
16
47
  When using Ruby on Rails version 3 then in Gemfile include
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.3
1
+ 1.5.0.beta1
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{activerecord-oracle_enhanced-adapter}
8
- s.version = "1.4.3"
8
+ s.version = "1.5.0.beta1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = [%q{Raimonds Simanovskis}]
@@ -29,10 +29,9 @@ This adapter is superset of original ActiveRecord Oracle adapter.
29
29
  "activerecord-oracle_enhanced-adapter.gemspec",
30
30
  "lib/active_record/connection_adapters/emulation/oracle_adapter.rb",
31
31
  "lib/active_record/connection_adapters/oracle_enhanced.rake",
32
- "lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb",
33
32
  "lib/active_record/connection_adapters/oracle_enhanced_adapter.rb",
34
- "lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb",
35
33
  "lib/active_record/connection_adapters/oracle_enhanced_column.rb",
34
+ "lib/active_record/connection_adapters/oracle_enhanced_column_dumper.rb",
36
35
  "lib/active_record/connection_adapters/oracle_enhanced_connection.rb",
37
36
  "lib/active_record/connection_adapters/oracle_enhanced_context_index.rb",
38
37
  "lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb",
@@ -46,7 +45,6 @@ This adapter is superset of original ActiveRecord Oracle adapter.
46
45
  "lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb",
47
46
  "lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb",
48
47
  "lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb",
49
- "lib/active_record/connection_adapters/oracle_enhanced_tasks.rb",
50
48
  "lib/active_record/connection_adapters/oracle_enhanced_version.rb",
51
49
  "lib/activerecord-oracle_enhanced-adapter.rb",
52
50
  "spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb",
@@ -29,18 +29,132 @@
29
29
  # contribution.
30
30
  # portions Copyright 2005 Graham Jenkins
31
31
 
32
- # ActiveRecord 2.2 does not load version file automatically
33
- require 'active_record/version' unless defined?(ActiveRecord::VERSION)
34
-
35
32
  require 'active_record/connection_adapters/abstract_adapter'
36
33
  require 'active_record/connection_adapters/oracle_enhanced_connection'
37
34
 
38
- require 'active_record/connection_adapters/oracle_enhanced_base_ext'
39
35
  require 'active_record/connection_adapters/oracle_enhanced_column'
40
36
 
41
37
  require 'digest/sha1'
42
38
 
39
+ require 'arel/visitors/bind_visitor'
40
+
41
+ ActiveRecord::Base.class_eval do
42
+ class_attribute :custom_create_method, :custom_update_method, :custom_delete_method
43
+ end
44
+
45
+ module ActiveRecord
46
+ class Base
47
+
48
+ # Specify table columns which should be ignored by ActiveRecord, e.g.:
49
+ #
50
+ # ignore_table_columns :attribute1, :attribute2
51
+ def self.ignore_table_columns(*args)
52
+ connection.ignore_table_columns(table_name,*args)
53
+ end
54
+
55
+ # Specify which table columns should be typecasted to Date (without time), e.g.:
56
+ #
57
+ # set_date_columns :created_on, :updated_on
58
+ def self.set_date_columns(*args)
59
+ connection.set_type_for_columns(table_name,:date,*args)
60
+ end
61
+
62
+ # Specify which table columns should be typecasted to Time (or DateTime), e.g.:
63
+ #
64
+ # set_datetime_columns :created_date, :updated_date
65
+ def self.set_datetime_columns(*args)
66
+ connection.set_type_for_columns(table_name,:datetime,*args)
67
+ end
68
+
69
+ # Specify which table columns should be typecasted to boolean values +true+ or +false+, e.g.:
70
+ #
71
+ # set_boolean_columns :is_valid, :is_completed
72
+ def self.set_boolean_columns(*args)
73
+ connection.set_type_for_columns(table_name,:boolean,*args)
74
+ end
75
+
76
+ # Specify which table columns should be typecasted to integer values.
77
+ # Might be useful to force NUMBER(1) column to be integer and not boolean, or force NUMBER column without
78
+ # scale to be retrieved as integer and not decimal. Example:
79
+ #
80
+ # set_integer_columns :version_number, :object_identifier
81
+ def self.set_integer_columns(*args)
82
+ connection.set_type_for_columns(table_name,:integer,*args)
83
+ end
84
+
85
+ # Specify which table columns should be typecasted to string values.
86
+ # Might be useful to specify that columns should be string even if its name matches boolean column criteria.
87
+ #
88
+ # set_string_columns :active_flag
89
+ def self.set_string_columns(*args)
90
+ connection.set_type_for_columns(table_name,:string,*args)
91
+ end
92
+
93
+ # Get table comment from schema definition.
94
+ def self.table_comment
95
+ connection.table_comment(self.table_name)
96
+ end
97
+
98
+ def self.lob_columns
99
+ columns.select do |column|
100
+ column.respond_to?(:lob?) && column.lob?
101
+ end
102
+ end
103
+
104
+ def self.virtual_columns
105
+ columns.select do |column|
106
+ column.respond_to?(:virtual?) && column.virtual?
107
+ end
108
+ end
109
+
110
+ def arel_attributes_with_values(attribute_names)
111
+ virtual_column_names = self.class.virtual_columns.map(&:name)
112
+ super(attribute_names - virtual_column_names)
113
+ end
114
+
115
+ # After setting large objects to empty, select the OCI8::LOB
116
+ # and write back the data.
117
+ before_update :record_changed_lobs
118
+ after_update :enhanced_write_lobs
119
+
120
+ private
121
+
122
+ def enhanced_write_lobs
123
+ if self.class.connection.is_a?(ConnectionAdapters::OracleEnhancedAdapter) &&
124
+ !(
125
+ (self.class.custom_create_method || self.class.custom_create_method) ||
126
+ (self.class.custom_update_method || self.class.custom_update_method)
127
+ )
128
+ self.class.connection.write_lobs(self.class.table_name, self.class, attributes, @changed_lob_columns || self.class.lob_columns)
129
+ end
130
+ end
131
+
132
+ def record_changed_lobs
133
+ @changed_lob_columns = self.class.lob_columns.select do |col|
134
+ self.class.serialized_attributes.keys.include?(col.name) ||
135
+ (self.send(:"#{col.name}_changed?") && !self.class.readonly_attributes.to_a.include?(col.name))
136
+ end
137
+ end
138
+ end
139
+ end
140
+
43
141
  module ActiveRecord
142
+ module ConnectionHandling #:nodoc:
143
+ # Establishes a connection to the database that's used by all Active Record objects.
144
+ def oracle_enhanced_connection(config) #:nodoc:
145
+ if config[:emulate_oracle_adapter] == true
146
+ # allows the enhanced adapter to look like the OracleAdapter. Useful to pick up
147
+ # conditionals in the rails activerecord test suite
148
+ require 'active_record/connection_adapters/emulation/oracle_adapter'
149
+ ConnectionAdapters::OracleAdapter.new(
150
+ ConnectionAdapters::OracleEnhancedConnection.create(config), logger, config)
151
+ else
152
+ ConnectionAdapters::OracleEnhancedAdapter.new(
153
+ ConnectionAdapters::OracleEnhancedConnection.create(config), logger, config)
154
+ end
155
+ end
156
+ end
157
+
44
158
  module ConnectionAdapters #:nodoc:
45
159
 
46
160
  # Oracle enhanced adapter will work with both
@@ -263,13 +377,21 @@ module ActiveRecord
263
377
  end
264
378
  end
265
379
 
380
+ class BindSubstitution < Arel::Visitors::Oracle #:nodoc:
381
+ include Arel::Visitors::BindVisitor
382
+ end
383
+
266
384
  def initialize(connection, logger, config) #:nodoc:
267
385
  super(connection, logger)
268
386
  @quoted_column_names, @quoted_table_names = {}, {}
269
387
  @config = config
270
388
  @statements = StatementPool.new(connection, config.fetch(:statement_limit) { 250 })
271
389
  @enable_dbms_output = false
272
- @visitor = Arel::Visitors::Oracle.new self if defined?(Arel::Visitors::Oracle)
390
+ if config.fetch(:prepared_statements) { true }
391
+ @visitor = Arel::Visitors::Oracle.new self
392
+ else
393
+ @visitor = unprepared_visitor
394
+ end
273
395
  end
274
396
 
275
397
  def self.visitor_for(pool) # :nodoc:
@@ -294,6 +416,10 @@ module ActiveRecord
294
416
  true
295
417
  end
296
418
 
419
+ def supports_transaction_isolation? #:nodoc:
420
+ true
421
+ end
422
+
297
423
  #:stopdoc:
298
424
  DEFAULT_NLS_PARAMETERS = {
299
425
  :nls_calendar => nil,
@@ -360,7 +486,17 @@ module ActiveRecord
360
486
  IDENTIFIER_MAX_LENGTH
361
487
  end
362
488
 
363
- # the maximum length of an index name
489
+ # Returns the maximum allowed length for an index name. This
490
+ # limit is enforced by rails and Is less than or equal to
491
+ # <tt>index_name_length</tt>. The gap between
492
+ # <tt>index_name_length</tt> is to allow internal rails
493
+ # opreations to use prefixes in temporary opreations.
494
+ def allowed_index_name_length
495
+ index_name_length
496
+ end
497
+
498
+ # the maximum length of an index name
499
+ # supported by this database
364
500
  def index_name_length
365
501
  IDENTIFIER_MAX_LENGTH
366
502
  end
@@ -451,7 +587,7 @@ module ActiveRecord
451
587
  if value && column
452
588
  case column.type
453
589
  when :text, :binary
454
- %Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
590
+ %Q{empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'blob' }()}
455
591
  # NLS_DATE_FORMAT independent TIMESTAMP support
456
592
  when :timestamp
457
593
  quote_timestamp_with_to_timestamp(value)
@@ -565,7 +701,7 @@ module ActiveRecord
565
701
 
566
702
  # Reconnects to the database.
567
703
  def reconnect! #:nodoc:
568
- clear_cache!
704
+ super
569
705
  @connection.reset!
570
706
  rescue OracleEnhancedConnectionException => e
571
707
  @logger.warn "#{adapter_name} automatic reconnection failed: #{e.message}" if @logger
@@ -578,7 +714,7 @@ module ActiveRecord
578
714
 
579
715
  # Disconnects from the database.
580
716
  def disconnect! #:nodoc:
581
- clear_cache!
717
+ super
582
718
  @connection.logoff rescue nil
583
719
  end
584
720
 
@@ -650,7 +786,7 @@ module ActiveRecord
650
786
  end
651
787
 
652
788
  def explain(arel, binds = [])
653
- sql = "EXPLAIN PLAN FOR #{to_sql(arel)}"
789
+ sql = "EXPLAIN PLAN FOR #{to_sql(arel, binds)}"
654
790
  return if sql =~ /FROM all_/
655
791
  if ORACLE_ENHANCED_CONNECTION == :jdbc
656
792
  exec_query(sql, 'EXPLAIN', binds)
@@ -699,7 +835,7 @@ module ActiveRecord
699
835
  end
700
836
 
701
837
  # New method in ActiveRecord 3.1
702
- def exec_insert(sql, name, binds)
838
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
703
839
  log(sql, name, binds) do
704
840
  returning_id_col = returning_id_index = nil
705
841
  cursor = if @statements.key?(sql)
@@ -775,6 +911,21 @@ module ActiveRecord
775
911
  @connection.autocommit = false
776
912
  end
777
913
 
914
+ def transaction_isolation_levels
915
+ # Oracle database supports `READ COMMITTED` and `SERIALIZABLE`
916
+ # No read uncommitted nor repeatable read supppoted
917
+ # http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_10005.htm#SQLRF55422
918
+ {
919
+ read_committed: "READ COMMITTED",
920
+ serializable: "SERIALIZABLE"
921
+ }
922
+ end
923
+
924
+ def begin_isolated_db_transaction(isolation)
925
+ begin_db_transaction
926
+ execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
927
+ end
928
+
778
929
  def commit_db_transaction #:nodoc:
779
930
  @connection.commit
780
931
  ensure
@@ -838,9 +989,36 @@ module ActiveRecord
838
989
  # Returns default sequence name for table.
839
990
  # Will take all or first 26 characters of table name and append _seq suffix
840
991
  def default_sequence_name(table_name, primary_key = nil)
841
- # TODO: remove schema prefix if present before truncating
842
- # truncate table name if necessary to fit in max length of identifier
843
- "#{table_name.to_s[0,IDENTIFIER_MAX_LENGTH-4]}_seq"
992
+ table_name.to_s.gsub /(^|\.)([\w$-]{1,#{sequence_name_length-4}})([\w$-]*)$/, '\1\2_seq'
993
+ end
994
+
995
+ def reset_pk_sequence!(table_name, primary_key = nil, sequence_name = nil) #:nodoc:
996
+ return nil unless table_exists?(table_name)
997
+ unless primary_key and sequence_name
998
+ # *Note*: Only primary key is implemented - sequence will be nil.
999
+ primary_key, sequence_name = pk_and_sequence_for(table_name)
1000
+ # TODO This sequence_name implemantation is just enough
1001
+ # to satisty fixures. To get correct sequence_name always
1002
+ # pk_and_sequence_for method needs some work.
1003
+ begin
1004
+ sequence_name = table_name.classify.constantize.sequence_name
1005
+ rescue
1006
+ sequence_name = default_sequence_name(table_name)
1007
+ end
1008
+ end
1009
+
1010
+ if @logger && primary_key && !sequence_name
1011
+ @logger.warn "#{table_name} has primary key #{primary_key} with no default sequence"
1012
+ end
1013
+
1014
+ if primary_key && sequence_name
1015
+ new_start_value = select_value("
1016
+ select NVL(max(#{quote_column_name(primary_key)}),0) + 1 from #{quote_table_name(table_name)}
1017
+ ", new_start_value)
1018
+
1019
+ execute ("DROP SEQUENCE #{quote_table_name(sequence_name)}")
1020
+ execute ("CREATE SEQUENCE #{quote_table_name(sequence_name)} START WITH #{new_start_value}")
1021
+ end
844
1022
  end
845
1023
 
846
1024
  # Inserts the given fixture into the table. Overridden to properly handle lobs.
@@ -848,9 +1026,9 @@ module ActiveRecord
848
1026
  super
849
1027
 
850
1028
  if ActiveRecord::Base.pluralize_table_names
851
- klass = table_name.singularize.camelize
1029
+ klass = table_name.to_s.singularize.camelize
852
1030
  else
853
- klass = table_name.camelize
1031
+ klass = table_name.to_s.camelize
854
1032
  end
855
1033
 
856
1034
  klass = klass.constantize rescue nil
@@ -1093,7 +1271,7 @@ module ActiveRecord
1093
1271
  SQL
1094
1272
 
1095
1273
  # added deletion of ignored columns
1096
- select_all(table_cols, name).delete_if do |row|
1274
+ select_all(table_cols, name).to_a.delete_if do |row|
1097
1275
  ignored_columns && ignored_columns.include?(row['name'].downcase)
1098
1276
  end.map do |row|
1099
1277
  limit, scale = row['limit'], row['scale']
@@ -1203,23 +1381,37 @@ module ActiveRecord
1203
1381
  # making every row the same.
1204
1382
  #
1205
1383
  # distinct("posts.id", "posts.created_at desc")
1206
- def distinct(columns, order_by) #:nodoc:
1207
- return "DISTINCT #{columns}" if order_by.blank?
1208
-
1209
- # construct a valid DISTINCT clause, ie. one that includes the ORDER BY columns, using
1210
- # FIRST_VALUE such that the inclusion of these columns doesn't invalidate the DISTINCT
1211
- order_columns = if order_by.is_a?(String)
1212
- order_by.split(',').map { |s| s.strip }.reject(&:blank?)
1213
- else # in latest ActiveRecord versions order_by is already Array
1214
- order_by
1384
+ def distinct(columns, orders) #:nodoc:
1385
+ # To support Rails 4.0.0 and future releases
1386
+ # because `columns_for_distinct method introduced after Rails 4.0.0 released
1387
+ if super.respond_to?(:columns_for_distinct)
1388
+ super
1389
+ else
1390
+ order_columns = orders.map { |c|
1391
+ c = c.to_sql unless c.is_a?(String)
1392
+ # remove any ASC/DESC modifiers
1393
+ c.gsub(/\s+(ASC|DESC)\s*?/i, '')
1394
+ }.reject(&:blank?).map.with_index { |c,i|
1395
+ "FIRST_VALUE(#{c}) OVER (PARTITION BY #{columns} ORDER BY #{c}) AS alias_#{i}__"
1396
+ }
1397
+ [super].concat(order_columns).join(', ')
1215
1398
  end
1216
- order_columns = order_columns.zip((0...order_columns.size).to_a).map do |c, i|
1399
+ end
1400
+
1401
+ def columns_for_distinct(columns, orders) #:nodoc:
1402
+ # construct a valid columns name for DISTINCT clause,
1403
+ # ie. one that includes the ORDER BY columns, using FIRST_VALUE such that
1404
+ # the inclusion of these columns doesn't invalidate the DISTINCT
1405
+ #
1406
+ # It does not construct DISTINCT clause. Just return column names for distinct.
1407
+ order_columns = orders.reject(&:blank?).map{ |s|
1408
+ s = s.to_sql unless s.is_a?(String)
1217
1409
  # remove any ASC/DESC modifiers
1218
- value = c =~ /^(.+)\s+(ASC|DESC)\s*$/i ? $1 : c
1219
- "FIRST_VALUE(#{value}) OVER (PARTITION BY #{columns} ORDER BY #{c}) AS alias_#{i}__"
1220
- end
1221
- sql = "DISTINCT #{columns}, "
1222
- sql << order_columns * ", "
1410
+ s.gsub(/\s+(ASC|DESC)\s*?/i, '')
1411
+ }.reject(&:blank?).map.with_index { |column,i|
1412
+ "FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns} ORDER BY #{column}) AS alias_#{i}__"
1413
+ }
1414
+ [super, *order_columns].join(', ')
1223
1415
  end
1224
1416
 
1225
1417
  def temporary_table?(table_name) #:nodoc:
@@ -1275,7 +1467,7 @@ module ActiveRecord
1275
1467
 
1276
1468
  def select(sql, name = nil, binds = [])
1277
1469
  if ActiveRecord.const_defined?(:Result)
1278
- exec_query(sql, name, binds).to_a
1470
+ exec_query(sql, name, binds)
1279
1471
  else
1280
1472
  log(sql, name) do
1281
1473
  @connection.select(sql, name, false)
@@ -1351,19 +1543,6 @@ module ActiveRecord
1351
1543
  end
1352
1544
  end
1353
1545
 
1354
- # Added LOB writing callback for sessions stored in database
1355
- # Otherwise it is not working as Session class is defined before OracleAdapter is loaded in Rails 2.0
1356
- if defined?(CGI::Session::ActiveRecordStore::Session)
1357
- if !CGI::Session::ActiveRecordStore::Session.respond_to?(:after_save_callback_chain) ||
1358
- CGI::Session::ActiveRecordStore::Session.after_save_callback_chain.detect{|cb| cb.method == :enhanced_write_lobs}.nil?
1359
- #:stopdoc:
1360
- class CGI::Session::ActiveRecordStore::Session
1361
- after_save :enhanced_write_lobs
1362
- end
1363
- #:startdoc:
1364
- end
1365
- end
1366
-
1367
1546
  # Implementation of standard schema definition statements and extensions for schema definition
1368
1547
  require 'active_record/connection_adapters/oracle_enhanced_schema_statements'
1369
1548
  require 'active_record/connection_adapters/oracle_enhanced_schema_statements_ext'
@@ -1374,21 +1553,12 @@ require 'active_record/connection_adapters/oracle_enhanced_schema_definitions'
1374
1553
  # Extensions for context index definition
1375
1554
  require 'active_record/connection_adapters/oracle_enhanced_context_index'
1376
1555
 
1377
- # Load custom create, update, delete methods functionality
1378
- require 'active_record/connection_adapters/oracle_enhanced_procedures'
1379
-
1380
1556
  # Load additional methods for composite_primary_keys support
1381
1557
  require 'active_record/connection_adapters/oracle_enhanced_cpk'
1382
1558
 
1383
1559
  # Load patch for dirty tracking methods
1384
1560
  require 'active_record/connection_adapters/oracle_enhanced_dirty'
1385
1561
 
1386
- # Load rake tasks definitions
1387
- begin
1388
- require 'active_record/connection_adapters/oracle_enhanced_tasks'
1389
- rescue LoadError
1390
- end if defined?(Rails) || defined?(RAILS_ROOT)
1391
-
1392
1562
  # Patches and enhancements for schema dumper
1393
1563
  require 'active_record/connection_adapters/oracle_enhanced_schema_dumper'
1394
1564
 
@@ -1398,6 +1568,94 @@ require 'active_record/connection_adapters/oracle_enhanced_structure_dump'
1398
1568
  # Add BigDecimal#to_d, Fixnum#to_d and Bignum#to_d methods if not already present
1399
1569
  require 'active_record/connection_adapters/oracle_enhanced_core_ext'
1400
1570
 
1401
- require 'active_record/connection_adapters/oracle_enhanced_activerecord_patches'
1402
-
1403
1571
  require 'active_record/connection_adapters/oracle_enhanced_version'
1572
+
1573
+ module ActiveRecord
1574
+ autoload :OracleEnhancedProcedures, 'active_record/connection_adapters/oracle_enhanced_procedures'
1575
+ end
1576
+
1577
+ # Patches and enhancements for column dumper
1578
+ require 'active_record/connection_adapters/oracle_enhanced_column_dumper'
1579
+
1580
+ module ActiveRecord
1581
+ module ConnectionAdapters
1582
+ class OracleEnhancedAdapter < AbstractAdapter
1583
+ class SchemaCreation < AbstractAdapter::SchemaCreation
1584
+ private
1585
+
1586
+ def visit_ColumnDefinition(o)
1587
+ if o.type.to_sym == :virtual
1588
+ sql_type = type_to_sql(o.default[:type], o.limit, o.precision, o.scale) if o.default[:type]
1589
+ "#{quote_column_name(o.name)} #{sql_type} AS (#{o.default[:as]})"
1590
+ else
1591
+ super
1592
+ end
1593
+ end
1594
+
1595
+ def visit_TableDefinition(o)
1596
+ tablespace = tablespace_for(:table, o.options[:tablespace])
1597
+ create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE "
1598
+ create_sql << "#{quote_table_name(o.name)} ("
1599
+ create_sql << o.columns.map { |c| accept c }.join(', ')
1600
+ create_sql << ")"
1601
+ unless o.temporary
1602
+ create_sql << " ORGANIZATION #{o.options[:organization]}" if o.options[:organization]
1603
+ create_sql << "#{tablespace}"
1604
+ end
1605
+ create_sql << " #{o.options[:options]}"
1606
+ create_sql
1607
+ end
1608
+
1609
+ def tablespace_for(obj_type, tablespace_option, table_name=nil, column_name=nil)
1610
+ tablespace_sql = ''
1611
+ if tablespace = (tablespace_option || default_tablespace_for(obj_type))
1612
+ tablespace_sql << if [:blob, :clob].include?(obj_type.to_sym)
1613
+ " LOB (#{quote_column_name(column_name)}) STORE AS #{column_name.to_s[0..10]}_#{table_name.to_s[0..14]}_ls (TABLESPACE #{tablespace})"
1614
+ else
1615
+ " TABLESPACE #{tablespace}"
1616
+ end
1617
+ end
1618
+ tablespace_sql
1619
+ end
1620
+
1621
+ def default_tablespace_for(type)
1622
+ (ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[type] ||
1623
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[native_database_types[type][:name]]) rescue nil
1624
+ end
1625
+
1626
+ def foreign_key_definition(to_table, options = {})
1627
+ @conn.foreign_key_definition(to_table, options)
1628
+ end
1629
+
1630
+ end
1631
+
1632
+ def schema_creation
1633
+ SchemaCreation.new self
1634
+ end
1635
+ end
1636
+
1637
+ def add_column_options!(sql, options)
1638
+ type = options[:type] || ((column = options[:column]) && column.type)
1639
+ type = type && type.to_sym
1640
+ # handle case of defaults for CLOB columns, which would otherwise get "quoted" incorrectly
1641
+ if options_include_default?(options)
1642
+ if type == :text
1643
+ sql << " DEFAULT #{quote(options[:default])}"
1644
+ else
1645
+ # from abstract adapter
1646
+ sql << " DEFAULT #{quote(options[:default], options[:column])}"
1647
+ end
1648
+ end
1649
+ # must explicitly add NULL or NOT NULL to allow change_column to work on migrations
1650
+ if options[:null] == false
1651
+ sql << " NOT NULL"
1652
+ elsif options[:null] == true
1653
+ sql << " NULL" unless type == :primary_key
1654
+ end
1655
+ # add AS expression for virtual columns
1656
+ if options[:as].present?
1657
+ sql << " AS (#{options[:as]})"
1658
+ end
1659
+ end
1660
+ end
1661
+ end