activerecord-oracle_enhanced-adapter 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
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: