activerecord-oracle_enhanced-adapter 1.4.0 → 1.4.1

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.
data/Gemfile CHANGED
@@ -21,20 +21,31 @@ group :development do
21
21
  gem 'railties', "=#{ENV['RAILS_GEM_VERSION']}"
22
22
  end
23
23
  else
24
- # uses local copy of Rails 3 and Arel gems
25
- ENV['RAILS_GEM_PATH'] ||= File.expand_path('../../rails', __FILE__)
26
24
  %w(activerecord activemodel activesupport actionpack railties).each do |gem_name|
27
- gem gem_name, :path => File.join(ENV['RAILS_GEM_PATH'], gem_name)
25
+ if ENV['RAILS_GEM_PATH']
26
+ gem gem_name, :path => File.join(ENV['RAILS_GEM_PATH'], gem_name)
27
+ else
28
+ gem gem_name, :git => "git://github.com/rails/rails"
29
+ end
28
30
  end
29
31
 
30
- ENV['AREL_GEM_PATH'] ||= File.expand_path('../../arel', __FILE__)
31
- gem 'arel', :path => ENV['AREL_GEM_PATH']
32
+ if ENV['AREL_GEM_PATH']
33
+ gem 'arel', :path => ENV['AREL_GEM_PATH']
34
+ else
35
+ gem 'arel', :git => "git://github.com/rails/arel"
36
+ end
37
+
38
+ if ENV['JOURNEY_GEM_PATH']
39
+ gem 'journey', :path => ENV['JOURNEY_GEM_PATH']
40
+ else
41
+ gem "journey", :git => "git://github.com/rails/journey"
42
+ end
32
43
  end
33
44
 
34
45
  gem 'ruby-plsql', '>=0.4.4'
35
46
 
36
47
  platforms :ruby do
37
- gem 'ruby-oci8', '~> 2.0.4'
48
+ gem 'ruby-oci8', '>=2.0.4'
38
49
  end
39
50
 
40
51
  end
@@ -1,4 +1,21 @@
1
- == 1.4.0 2011-08-09
1
+ ### 1.4.1 / 2011-01-27
2
+
3
+ * Enhancements:
4
+ * Support for Rails 3.2
5
+ * Support for ActiveRecord 3.2 explain plans [#116]
6
+ * Support for ActiveRecord 3.1 statement pool, to avoid `ORA-01000` maximum open cursors exceeded (default `statement_limit` is 250 and can be changed in `database.yml`) [#100]
7
+ * Added error handling for `rename_table` method in migrations [#137]
8
+ * Bug fixes:
9
+ * Store primary key as `nil` in cache at first time for table without primary key [#84]
10
+ * Fixed inserting records with decimal type columns (`ORA-01722` invalid number exceptions) [#130]
11
+ * Check virtual columns only in models that are using `oracle-enhanced` adapter, to avoid problems when using multiple database adapters [#85]
12
+ * Don't drop the user in rake `db:create` and `db:drop` tasks [#103]
13
+ * Don't add `db:create` and `db:drop` when ActiveRecord is not used as the primary datastore [#128]
14
+ * Quote column names in LOB statements to avoid `ORA-00936` errors [#91]
15
+ * Don't add the `RETURNING` clause if using `composite_primary_keys` gem [#132]
16
+ * Added `join_to_update` method that is necessary for ActiveRecord 3.1 to ensure that correct UPDATE statement is generated using `WHERE ... IN` subquery with offset condition
17
+
18
+ ### 1.4.0 / 2011-08-09
2
19
 
3
20
  * Enhancements:
4
21
  * Support for Rails 3.1
@@ -17,7 +34,7 @@
17
34
  * Fixed schema dump not to conflict with other database adapters that are used in the same application
18
35
  * Allow $ in table name prefix or suffix
19
36
 
20
- == 1.3.2 2011-01-05
37
+ ### 1.3.2 / 2011-01-05
21
38
 
22
39
  * Enhancements:
23
40
  * If no :host or :port is provided then connect with :database name (do not default :host to localhost)
@@ -31,7 +48,7 @@
31
48
  * Quote NCHAR and NVARCHAR2 type values with N'...'
32
49
  * Numeric username and/or password in database.yml will be automatically converted to string
33
50
 
34
- == 1.3.1 2010-09-09
51
+ ### 1.3.1 / 2010-09-09
35
52
 
36
53
  * Enhancements:
37
54
  * Tested with Rails 3.0.0 release
@@ -48,7 +65,7 @@
48
65
  * removed String.mb_chars upcase and downcase methods for Ruby 1.9 as Rails 3.0.0 already includes Unicode aware upcase and downcase methods for Ruby 1.9
49
66
  * Fixes for latest ActiveRecord unit tests
50
67
 
51
- == 1.3.0 2010-06-21
68
+ ### 1.3.0 / 2010-06-21
52
69
 
53
70
  * Enhancements:
54
71
  * Rails 3.0.0.beta4 and Rails 2.3.x compatible
@@ -68,7 +85,7 @@
68
85
  * Fixes for schema dump and structure dump (use correct statement separator)
69
86
  * Only use Oracle specific schema dump for Oracle connections
70
87
 
71
- == 1.2.4 2010-02-23
88
+ ### 1.2.4 / 2010-02-23
72
89
 
73
90
  * Enhancements:
74
91
  * rake db:test:purge will drop all schema objects from test schema (including views, synonyms, packages, functions, procedures) -
@@ -85,7 +102,7 @@
85
102
  (to avoid issues with _before_type_cast values for id attributes because _before_type_cast is used in form helpers)
86
103
  * clear table columns cache after columns definition change in migrations
87
104
 
88
- == 1.2.3 2009-12-09
105
+ ### 1.2.3 / 2009-12-09
89
106
 
90
107
  * Enhancements
91
108
  * support fractional seconds in TIMESTAMP values
@@ -105,7 +122,7 @@
105
122
  * fixed custom create/update/delete methods with ActiveRecord 2.3+ and timestamps
106
123
  * do not call oracle_enhanced specific schema dump methods when using other database adapters
107
124
 
108
- == 1.2.2 2009-09-28
125
+ ### 1.2.2 / 2009-09-28
109
126
 
110
127
  * Enhancements
111
128
  * improved RDoc documentation of public methods
@@ -139,7 +156,7 @@
139
156
  * ignore :limit option for :text and :binary columns in migrations
140
157
  * patches for ActiveRecord schema dumper to remove table prefixes and suffixes from schema.rb
141
158
 
142
- == 1.2.1 2009-06-07
159
+ ### 1.2.1 / 2009-06-07
143
160
 
144
161
  * Enhancements
145
162
  * caching of table indexes query which makes schema dump much faster
@@ -150,7 +167,7 @@
150
167
  * Made test tasks respect RAILS_ENV
151
168
  * fixed support for composite primary keys for tables with LOBs
152
169
 
153
- == 1.2.0 2009-03-22
170
+ ### 1.2.0 / 2009-03-22
154
171
 
155
172
  * Enhancements
156
173
  * support for JRuby and JDBC
@@ -161,7 +178,7 @@
161
178
  * Bug fixes:
162
179
  * several bug fixes that were identified during running of ActiveRecord unit tests
163
180
 
164
- == 1.1.9 2009-01-02
181
+ ### 1.1.9 / 2009-01-02
165
182
 
166
183
  * Enhancements
167
184
  * Added support for table and column comments in migrations
@@ -171,7 +188,7 @@
171
188
  * Do not mark empty decimals, strings and texts (stored as NULL in database) as changed when reassigning them (starting from Rails 2.1)
172
189
  * Create booleans as VARCHAR2(1) columns if emulate_booleans_from_strings is true
173
190
 
174
- == 1.1.8 2008-10-10
191
+ ### 1.1.8 / 2008-10-10
175
192
 
176
193
  * Bug fixes:
177
194
  * Fixed storing of serialized LOB columns
@@ -185,12 +202,12 @@
185
202
  * Fixed bug when ActiveRecord::Base.allow_concurrency = true
186
203
  (see http://dev.rubyonrails.org/ticket/11134)
187
204
 
188
- == 1.1.7 2008-08-20
205
+ ### 1.1.7 / 2008-08-20
189
206
 
190
207
  * Bug fixes:
191
208
  * Fixed that adapter works without ruby-plsql gem (in this case just custom create/update/delete methods are not available)
192
209
 
193
- == 1.1.6 2008-08-19
210
+ ### 1.1.6 / 2008-08-19
194
211
 
195
212
  * Enhancements:
196
213
  * Added support for set_date_columns and set_datetime_columns
@@ -200,7 +217,7 @@
200
217
  * Bug fixes:
201
218
  * Do not call write_lobs callback when custom create or update methods are defined
202
219
 
203
- == 1.1.5 2008-07-27
220
+ ### 1.1.5 / 2008-07-27
204
221
 
205
222
  * Bug fixes:
206
223
  * Fixed that write_lobs callback works with partial_updates enabled (added additional record lock before writing BLOB data to database)
@@ -208,26 +225,26 @@
208
225
  * Changed SQL SELECT in indexes method so that it will execute faster on some large data dictionaries
209
226
  * Support for other date and time formats when assigning string to :date or :datetime column
210
227
 
211
- == 1.1.4 2008-07-14
228
+ ### 1.1.4 / 2008-07-14
212
229
 
213
230
  * Enhancements:
214
231
  * Date/Time quoting changes to support composite_primary_keys
215
232
  * Added additional methods that are used by composite_primary_keys
216
233
 
217
- == 1.1.3 2008-07-10
234
+ ### 1.1.3 / 2008-07-10
218
235
 
219
236
  * Enhancements:
220
237
  * Added support for custom create, update and delete methods when working with legacy databases where
221
238
  PL/SQL API should be used for create, update and delete operations
222
239
 
223
- == 1.1.2 2008-07-08
240
+ ### 1.1.2 / 2008-07-08
224
241
 
225
242
  * Bug fixes:
226
243
  * Fixed after_save callback addition for session store in ActiveRecord version 2.0.2
227
244
  * Changed date column name recognition - now should match regex /(^|_)date(_|$)/i
228
245
  (previously "updated_at" was recognized as :date column and not as :datetime)
229
246
 
230
- == 1.1.1 2008-06-28
247
+ ### 1.1.1 / 2008-06-28
231
248
 
232
249
  * Enhancements:
233
250
  * Added ignore_table_columns option
@@ -237,7 +254,7 @@
237
254
  * Checks if CGI::Session::ActiveRecordStore::Session does not have enhanced_write_lobs callback before adding it
238
255
  (Rails 2.0 does not add this callback, Rails 2.1 does)
239
256
 
240
- == 1.1.0 2008-05-05
257
+ ### 1.1.0 / 2008-05-05
241
258
 
242
259
  * Forked from original activerecord-oracle-adapter-1.0.0.9216
243
260
  * Renamed oracle adapter to oracle_enhanced adapter
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.0
1
+ 1.4.1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{activerecord-oracle_enhanced-adapter}
8
- s.version = "1.4.0"
8
+ s.version = "1.4.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Raimonds Simanovskis"]
12
- s.date = %q{2011-08-09}
11
+ s.authors = [%q{Raimonds Simanovskis}]
12
+ s.date = %q{2012-01-27}
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
  }
@@ -20,7 +20,7 @@ This adapter is superset of original ActiveRecord Oracle adapter.
20
20
  s.files = [
21
21
  ".rspec",
22
22
  "Gemfile",
23
- "History.txt",
23
+ "History.md",
24
24
  "License.txt",
25
25
  "README.md",
26
26
  "RUNNING_TESTS.md",
@@ -65,8 +65,8 @@ This adapter is superset of original ActiveRecord Oracle adapter.
65
65
  "spec/spec_helper.rb"
66
66
  ]
67
67
  s.homepage = %q{http://github.com/rsim/oracle-enhanced}
68
- s.require_paths = ["lib"]
69
- s.rubygems_version = %q{1.6.2}
68
+ s.require_paths = [%q{lib}]
69
+ s.rubygems_version = %q{1.8.6}
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,8 +97,9 @@ 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<journey>, [">= 0"])
100
101
  s.add_development_dependency(%q<ruby-plsql>, [">= 0.4.4"])
101
- s.add_development_dependency(%q<ruby-oci8>, ["~> 2.0.4"])
102
+ s.add_development_dependency(%q<ruby-oci8>, [">= 2.0.4"])
102
103
  else
103
104
  s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
104
105
  s.add_dependency(%q<rspec>, ["~> 2.4"])
@@ -108,8 +109,9 @@ This adapter is superset of original ActiveRecord Oracle adapter.
108
109
  s.add_dependency(%q<actionpack>, [">= 0"])
109
110
  s.add_dependency(%q<railties>, [">= 0"])
110
111
  s.add_dependency(%q<arel>, [">= 0"])
112
+ s.add_dependency(%q<journey>, [">= 0"])
111
113
  s.add_dependency(%q<ruby-plsql>, [">= 0.4.4"])
112
- s.add_dependency(%q<ruby-oci8>, ["~> 2.0.4"])
114
+ s.add_dependency(%q<ruby-oci8>, [">= 2.0.4"])
113
115
  end
114
116
  else
115
117
  s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
@@ -120,8 +122,9 @@ This adapter is superset of original ActiveRecord Oracle adapter.
120
122
  s.add_dependency(%q<actionpack>, [">= 0"])
121
123
  s.add_dependency(%q<railties>, [">= 0"])
122
124
  s.add_dependency(%q<arel>, [">= 0"])
125
+ s.add_dependency(%q<journey>, [">= 0"])
123
126
  s.add_dependency(%q<ruby-plsql>, [">= 0.4.4"])
124
- s.add_dependency(%q<ruby-oci8>, ["~> 2.0.4"])
127
+ s.add_dependency(%q<ruby-oci8>, [">= 2.0.4"])
125
128
  end
126
129
  end
127
130
 
@@ -16,37 +16,46 @@ def redefine_task(*args, &block)
16
16
  end
17
17
 
18
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)
19
+ if defined?(create_database) == 'method'
20
+ def create_database_with_oracle_enhanced(config)
21
+ if config['adapter'] == 'oracle_enhanced'
22
+ print "Please provide the SYSTEM password for your oracle installation\n>"
23
+ system_password = $stdin.gets.strip
24
+ ActiveRecord::Base.establish_connection(config.merge('username' => 'SYSTEM', 'password' => system_password))
25
+ begin
26
+ ActiveRecord::Base.connection.execute "CREATE USER #{config['username']} IDENTIFIED BY #{config['password']}"
27
+ rescue => e
28
+ if e.message =~ /ORA-01920/ # user name conflicts with another user or role name
29
+ ActiveRecord::Base.connection.execute "ALTER USER #{config['username']} IDENTIFIED BY #{config['password']}"
30
+ else
31
+ raise e
32
+ end
33
+ end
34
+ ActiveRecord::Base.connection.execute "GRANT unlimited tablespace TO #{config['username']}"
35
+ ActiveRecord::Base.connection.execute "GRANT create session TO #{config['username']}"
36
+ ActiveRecord::Base.connection.execute "GRANT create table TO #{config['username']}"
37
+ ActiveRecord::Base.connection.execute "GRANT create sequence TO #{config['username']}"
38
+ else
39
+ create_database_without_oracle_enhanced(config)
40
+ end
32
41
  end
42
+ alias :create_database_without_oracle_enhanced :create_database
43
+ alias :create_database :create_database_with_oracle_enhanced
33
44
  end
34
- alias :create_database_without_oracle_enhanced :create_database
35
- alias :create_database :create_database_with_oracle_enhanced
36
45
 
37
46
  # 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)
47
+ if defined?(drop_database) == 'method'
48
+ def drop_database_with_oracle_enhanced(config)
49
+ if config['adapter'] == 'oracle_enhanced'
50
+ ActiveRecord::Base.establish_connection(config)
51
+ ActiveRecord::Base.connection.execute_structure_dump(ActiveRecord::Base.connection.full_drop)
52
+ else
53
+ drop_database_without_oracle_enhanced(config)
54
+ end
46
55
  end
56
+ alias :drop_database_without_oracle_enhanced :drop_database
57
+ alias :drop_database :drop_database_with_oracle_enhanced
47
58
  end
48
- alias :drop_database_without_oracle_enhanced :drop_database
49
- alias :drop_database :drop_database_with_oracle_enhanced
50
59
 
51
60
  namespace :db do
52
61
 
@@ -7,7 +7,7 @@
7
7
  #
8
8
  #########################################################################
9
9
  #
10
- # See History.txt for changes added to original oracle_adapter.rb
10
+ # See History.md for changes added to original oracle_adapter.rb
11
11
  #
12
12
  #########################################################################
13
13
  #
@@ -235,11 +235,43 @@ module ActiveRecord
235
235
  cattr_accessor :string_to_time_format
236
236
  self.string_to_time_format = nil
237
237
 
238
- def initialize(connection, logger = nil) #:nodoc:
239
- super
238
+ class StatementPool
239
+ include Enumerable
240
+
241
+ def initialize(connection, max = 300)
242
+ @connection = connection
243
+ @max = max
244
+ @cache = {}
245
+ end
246
+
247
+ def each(&block); @cache.each(&block); end
248
+ def key?(key); @cache.key?(key); end
249
+ def [](key); @cache[key]; end
250
+ def length; @cache.length; end
251
+ def delete(key); @cache.delete(key); end
252
+
253
+ def []=(sql, key)
254
+ while @max <= @cache.size
255
+ @cache.shift.last.close
256
+ end
257
+ @cache[sql] = key
258
+ end
259
+
260
+ def clear
261
+ @cache.values.each do |cursor|
262
+ cursor.close
263
+ end
264
+ @cache.clear
265
+ end
266
+ end
267
+
268
+ def initialize(connection, logger, config) #:nodoc:
269
+ super(connection, logger)
240
270
  @quoted_column_names, @quoted_table_names = {}, {}
241
- @statements = {}
271
+ @config = config
272
+ @statements = StatementPool.new(connection, config.fetch(:statement_limit) { 250 })
242
273
  @enable_dbms_output = false
274
+ @visitor = Arel::Visitors::Oracle.new self if defined?(Arel::Visitors::Oracle)
243
275
  end
244
276
 
245
277
  def self.visitor_for(pool) # :nodoc:
@@ -337,6 +369,11 @@ module ActiveRecord
337
369
  IDENTIFIER_MAX_LENGTH
338
370
  end
339
371
 
372
+ # the maximum length of a sequence name
373
+ def sequence_name_length
374
+ IDENTIFIER_MAX_LENGTH
375
+ end
376
+
340
377
  # To avoid ORA-01795: maximum number of expressions in a list is 1000
341
378
  # tell ActiveRecord to limit us to 1000 ids at a time
342
379
  def in_clause_length
@@ -563,9 +600,6 @@ module ActiveRecord
563
600
  end
564
601
 
565
602
  def clear_cache!
566
- @statements.each_value do |cursor|
567
- cursor.close
568
- end
569
603
  @statements.clear
570
604
  end
571
605
 
@@ -591,15 +625,21 @@ module ActiveRecord
591
625
  end
592
626
 
593
627
  cursor.exec
594
- columns = cursor.get_col_names.map do |col_name|
595
- @connection.oracle_downcase(col_name)
596
- end
597
- rows = []
598
- fetch_options = {:get_lob_value => (name != 'Writable Large Object')}
599
- while row = cursor.fetch(fetch_options)
600
- rows << row
628
+
629
+ if name == 'EXPLAIN'
630
+ res = true
631
+ else
632
+ columns = cursor.get_col_names.map do |col_name|
633
+ @connection.oracle_downcase(col_name)
634
+ end
635
+ rows = []
636
+ fetch_options = {:get_lob_value => (name != 'Writable Large Object')}
637
+ while row = cursor.fetch(fetch_options)
638
+ rows << row
639
+ end
640
+ res = ActiveRecord::Result.new(columns, rows)
601
641
  end
602
- res = ActiveRecord::Result.new(columns, rows)
642
+
603
643
  cursor.close unless cached
604
644
  res
605
645
  end
@@ -609,6 +649,17 @@ module ActiveRecord
609
649
  true
610
650
  end
611
651
 
652
+ def supports_explain?
653
+ true
654
+ end
655
+
656
+ def explain(arel, binds = [])
657
+ sql = "EXPLAIN PLAN FOR #{to_sql(arel)}"
658
+ return if sql =~ /FROM all_/
659
+ exec_query(sql, 'EXPLAIN', binds)
660
+ select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)", 'EXPLAIN').join("\n")
661
+ end
662
+
612
663
  # Returns an array of arrays containing the field values.
613
664
  # Order is the same as that returned by #columns.
614
665
  def select_rows(sql, name = nil)
@@ -639,7 +690,7 @@ module ActiveRecord
639
690
  # New method in ActiveRecord 3.1
640
691
  # Will add RETURNING clause in case of trigger generated primary keys
641
692
  def sql_for_insert(sql, pk, id_value, sequence_name, binds)
642
- unless id_value || pk.nil?
693
+ unless id_value || pk.nil? || (defined?(CompositePrimaryKeys) && pk.kind_of?(CompositePrimaryKeys::CompositeKeys))
643
694
  sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO :returning_id"
644
695
  (binds = binds.dup) << [:returning_id, nil]
645
696
  end
@@ -682,18 +733,26 @@ module ActiveRecord
682
733
  # New method in ActiveRecord 3.1
683
734
  def exec_update(sql, name, binds)
684
735
  log(sql, name, binds) do
685
- cursor = if @statements.key?(sql)
686
- @statements[sql]
736
+ cached = false
737
+ if binds.empty?
738
+ cursor = @connection.prepare(sql)
687
739
  else
688
- @statements[sql] = @connection.prepare(sql)
689
- end
740
+ cursor = if @statements.key?(sql)
741
+ @statements[sql]
742
+ else
743
+ @statements[sql] = @connection.prepare(sql)
744
+ end
690
745
 
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)
746
+ binds.each_with_index do |bind, i|
747
+ col, val = bind
748
+ cursor.bind_param(i + 1, type_cast(val, col), col && col.type)
749
+ end
750
+ cached = true
694
751
  end
695
752
 
696
- cursor.exec_update
753
+ res = cursor.exec_update
754
+ cursor.close unless cached
755
+ res
697
756
  end
698
757
  end
699
758
 
@@ -1078,7 +1137,11 @@ module ActiveRecord
1078
1137
  def pk_and_sequence_for(table_name, owner=nil, desc_table_name=nil, db_link=nil) #:nodoc:
1079
1138
  if @@cache_columns
1080
1139
  @@pk_and_sequence_for_cache ||= {}
1081
- @@pk_and_sequence_for_cache[table_name] ||= pk_and_sequence_for_without_cache(table_name, owner, desc_table_name, db_link)
1140
+ if @@pk_and_sequence_for_cache.key?(table_name)
1141
+ @@pk_and_sequence_for_cache[table_name]
1142
+ else
1143
+ @@pk_and_sequence_for_cache[table_name] = pk_and_sequence_for_without_cache(table_name, owner, desc_table_name, db_link)
1144
+ end
1082
1145
  else
1083
1146
  pk_and_sequence_for_without_cache(table_name, owner, desc_table_name, db_link)
1084
1147
  end
@@ -1160,6 +1223,23 @@ module ActiveRecord
1160
1223
  sql << " ORDER BY #{order}"
1161
1224
  end
1162
1225
 
1226
+ # construct additional wrapper subquery if select.offset is used to avoid generation of invalid subquery
1227
+ # ... IN ( SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM ( ... ) raw_sql_ ) WHERE raw_rnum_ > ... )
1228
+ def join_to_update(update, select) #:nodoc:
1229
+ if select.offset
1230
+ subsubselect = select.clone
1231
+ subsubselect.projections = [update.key]
1232
+
1233
+ subselect = Arel::SelectManager.new(select.engine)
1234
+ subselect.project Arel.sql(quote_column_name update.key.name)
1235
+ subselect.from subsubselect.as('alias_join_to_update')
1236
+
1237
+ update.where update.key.in(subselect)
1238
+ else
1239
+ super
1240
+ end
1241
+ end
1242
+
1163
1243
  protected
1164
1244
 
1165
1245
  def translate_exception(exception, message) #:nodoc: