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.
@@ -7,10 +7,10 @@ module ActiveRecord
7
7
  # conditionals in the rails activerecord test suite
8
8
  require 'active_record/connection_adapters/emulation/oracle_adapter'
9
9
  ConnectionAdapters::OracleAdapter.new(
10
- ConnectionAdapters::OracleEnhancedConnection.create(config), logger)
10
+ ConnectionAdapters::OracleEnhancedConnection.create(config), logger, config)
11
11
  else
12
12
  ConnectionAdapters::OracleEnhancedAdapter.new(
13
- ConnectionAdapters::OracleEnhancedConnection.create(config), logger)
13
+ ConnectionAdapters::OracleEnhancedConnection.create(config), logger, config)
14
14
  end
15
15
  end
16
16
 
@@ -78,18 +78,24 @@ module ActiveRecord
78
78
  def self.table_comment
79
79
  connection.table_comment(self.table_name)
80
80
  end
81
-
81
+
82
+ def self.virtual_columns
83
+ columns.select do |column|
84
+ column.respond_to?(:virtual?) && column.virtual?
85
+ end
86
+ end
87
+
82
88
  if ActiveRecord::VERSION::MAJOR < 3
83
89
  def attributes_with_quotes_with_virtual_columns(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
84
- virtual_columns = self.class.columns.select(& :virtual?).map(&:name)
85
- attributes_with_quotes_without_virtual_columns(include_primary_key, include_readonly_attributes, attribute_names - virtual_columns)
90
+ virtual_column_names = self.class.virtual_columns.map(&:name)
91
+ attributes_with_quotes_without_virtual_columns(include_primary_key, include_readonly_attributes, attribute_names - virtual_column_names)
86
92
  end
87
93
 
88
94
  alias_method_chain :attributes_with_quotes, :virtual_columns
89
95
  else
90
96
  def arel_attributes_values_with_virtual_columns(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
91
- virtual_columns = self.class.columns.select(& :virtual?).map(&:name)
92
- arel_attributes_values_without_virtual_columns(include_primary_key, include_readonly_attributes, attribute_names - virtual_columns)
97
+ virtual_column_names = self.class.virtual_columns.map(&:name)
98
+ arel_attributes_values_without_virtual_columns(include_primary_key, include_readonly_attributes, attribute_names - virtual_column_names)
93
99
  end
94
100
 
95
101
  alias_method_chain :arel_attributes_values, :virtual_columns
@@ -93,8 +93,8 @@ module ActiveRecord
93
93
 
94
94
  # Returns an array of the values of the first column in a select:
95
95
  # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
96
- def select_values(sql)
97
- result = select(sql)
96
+ def select_values(sql, name = nil)
97
+ result = select(sql, name = nil)
98
98
  result.map { |r| r.values.first }
99
99
  end
100
100
 
@@ -1,5 +1,6 @@
1
1
  require "bigdecimal"
2
- if (BigDecimal.instance_methods & ["to_d", :to_d]).empty?
2
+
3
+ unless BigDecimal.method_defined?(:to_d)
3
4
  BigDecimal.class_eval do
4
5
  def to_d #:nodoc:
5
6
  self
@@ -7,7 +8,7 @@ if (BigDecimal.instance_methods & ["to_d", :to_d]).empty?
7
8
  end
8
9
  end
9
10
 
10
- if (Bignum.instance_methods & ["to_d", :to_d]).empty?
11
+ unless Bignum.method_defined?(:to_d)
11
12
  Bignum.class_eval do
12
13
  def to_d #:nodoc:
13
14
  BigDecimal.new(self.to_s)
@@ -15,7 +16,7 @@ if (Bignum.instance_methods & ["to_d", :to_d]).empty?
15
16
  end
16
17
  end
17
18
 
18
- if (Fixnum.instance_methods & ["to_d", :to_d]).empty?
19
+ unless Fixnum.method_defined?(:to_d)
19
20
  Fixnum.class_eval do
20
21
  def to_d #:nodoc:
21
22
  BigDecimal.new(self.to_s)
@@ -314,6 +314,8 @@ module ActiveRecord
314
314
  @raw_statement.setBlob(position, java_value)
315
315
  when :raw
316
316
  @raw_statement.setString(position, OracleEnhancedAdapter.encode_raw(java_value))
317
+ when :decimal
318
+ @raw_statement.setBigDecimal(position, java_value)
317
319
  else
318
320
  @raw_statement.setString(position, java_value)
319
321
  end
@@ -341,7 +343,6 @@ module ActiveRecord
341
343
 
342
344
  def exec
343
345
  @raw_result_set = @raw_statement.executeQuery
344
- get_metadata
345
346
  true
346
347
  end
347
348
 
@@ -349,22 +350,24 @@ module ActiveRecord
349
350
  @raw_statement.executeUpdate
350
351
  end
351
352
 
352
- def get_metadata
353
- metadata = @raw_result_set.getMetaData
354
- column_count = metadata.getColumnCount
355
- @column_names = (1..column_count).map{|i| metadata.getColumnName(i)}
356
- @column_types = (1..column_count).map{|i| metadata.getColumnTypeName(i).to_sym}
353
+ def metadata
354
+ @metadata ||= @raw_result_set.getMetaData
357
355
  end
358
356
 
359
- def get_col_names
360
- @column_names
357
+ def column_types
358
+ @column_types ||= (1..metadata.getColumnCount).map{|i| metadata.getColumnTypeName(i).to_sym}
361
359
  end
362
360
 
361
+ def column_names
362
+ @column_names ||= (1..metadata.getColumnCount).map{|i| metadata.getColumnName(i)}
363
+ end
364
+ alias :get_col_names :column_names
365
+
363
366
  def fetch(options={})
364
367
  if @raw_result_set.next
365
368
  get_lob_value = options[:get_lob_value]
366
369
  row_values = []
367
- @column_types.each_with_index do |column_type, i|
370
+ column_types.each_with_index do |column_type, i|
368
371
  row_values <<
369
372
  @connection.get_ruby_value_from_result_set(@raw_result_set, i+1, column_type, get_lob_value)
370
373
  end
@@ -407,6 +410,8 @@ module ActiveRecord
407
410
  blob = Java::OracleSql::BLOB.createTemporary(@connection.raw_connection, false, Java::OracleSql::BLOB::DURATION_SESSION)
408
411
  blob.setBytes(1, value.to_java_bytes)
409
412
  blob
413
+ when :decimal
414
+ java.math.BigDecimal.new(value.to_s)
410
415
  else
411
416
  value
412
417
  end
@@ -127,6 +127,8 @@ module ActiveRecord
127
127
  @raw_cursor.bind_param(position, ora_value)
128
128
  when :raw
129
129
  @raw_cursor.bind_param(position, OracleEnhancedAdapter.encode_raw(value))
130
+ when :decimal
131
+ @raw_cursor.bind_param(position, BigDecimal.new(value.to_s))
130
132
  else
131
133
  @raw_cursor.bind_param(position, value)
132
134
  end
@@ -98,8 +98,14 @@ module ActiveRecord
98
98
  end
99
99
 
100
100
  def rename_table(name, new_name) #:nodoc:
101
+ if new_name.to_s.length > table_name_length
102
+ raise ArgumentError, "New table name '#{new_name}' is too long; the limit is #{table_name_length} characters"
103
+ end
104
+ if "#{new_name}_seq".to_s.length > sequence_name_length
105
+ raise ArgumentError, "New sequence name '#{new_name}_seq' is too long; the limit is #{sequence_name_length} characters"
106
+ end
101
107
  execute "RENAME #{quote_table_name(name)} TO #{quote_table_name(new_name)}"
102
- execute "RENAME #{quote_table_name("#{name}_seq")} TO #{quote_table_name("#{new_name}_seq")}" rescue nil
108
+ execute "RENAME #{quote_table_name("#{name}_seq")} TO #{quote_table_name("#{new_name}_seq")}"
103
109
  end
104
110
 
105
111
  def drop_table(name, options = {}) #:nodoc:
@@ -308,7 +314,7 @@ module ActiveRecord
308
314
  tablespace_sql = ''
309
315
  if tablespace = (tablespace_option || default_tablespace_for(obj_type))
310
316
  tablespace_sql << if [:blob, :clob].include?(obj_type.to_sym)
311
- " LOB (#{column_name}) STORE AS #{column_name.to_s[0..10]}_#{table_name.to_s[0..14]}_ls (TABLESPACE #{tablespace})"
317
+ " LOB (#{quote_column_name(column_name)}) STORE AS #{column_name.to_s[0..10]}_#{table_name.to_s[0..14]}_ls (TABLESPACE #{tablespace})"
312
318
  else
313
319
  " TABLESPACE #{tablespace}"
314
320
  end
@@ -196,6 +196,13 @@ describe "OracleEnhancedAdapter" do
196
196
  hire_date DATE
197
197
  )
198
198
  SQL
199
+ @conn.execute <<-SQL
200
+ CREATE TABLE test_employees_without_pk (
201
+ first_name VARCHAR2(20),
202
+ last_name VARCHAR2(25),
203
+ hire_date DATE
204
+ )
205
+ SQL
199
206
  @column_names = ['id', 'first_name', 'last_name', 'full_name', 'hire_date']
200
207
  @column_sql_types = ["NUMBER", "VARCHAR2(20)", "VARCHAR2(25)", "VARCHAR2(46)", "DATE"]
201
208
  class ::TestEmployee < ActiveRecord::Base
@@ -211,6 +218,7 @@ describe "OracleEnhancedAdapter" do
211
218
  Object.send(:remove_const, "TestEmployee")
212
219
  Object.send(:remove_const, "TestEmployee2")
213
220
  @conn.execute "DROP TABLE test_employees"
221
+ @conn.execute "DROP TABLE test_employees_without_pk"
214
222
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = nil
215
223
  ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
216
224
  end
@@ -300,6 +308,13 @@ describe "OracleEnhancedAdapter" do
300
308
  @logger.logged(:debug).last.should be_blank
301
309
  end
302
310
 
311
+ it "should store primary key as nil in cache at first time for table without primary key" do
312
+ TestEmployee.connection.pk_and_sequence_for('test_employees_without_pk').should == nil
313
+ @logger.clear(:debug)
314
+ TestEmployee.connection.pk_and_sequence_for('test_employees_without_pk').should == nil
315
+ @logger.logged(:debug).last.should be_blank
316
+ end
317
+
303
318
  end
304
319
 
305
320
  end
@@ -653,4 +668,82 @@ describe "OracleEnhancedAdapter" do
653
668
 
654
669
  end if ENV['RAILS_GEM_VERSION'] >= '3.1'
655
670
 
671
+ describe "with statement pool" do
672
+ before(:all) do
673
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS.merge(:statement_limit => 3))
674
+ @conn = ActiveRecord::Base.connection
675
+ schema_define do
676
+ drop_table :test_posts rescue nil
677
+ create_table :test_posts
678
+ end
679
+ class ::TestPost < ActiveRecord::Base
680
+ end
681
+ @statements = @conn.instance_variable_get(:@statements)
682
+ end
683
+
684
+ before(:each) do
685
+ @conn.clear_cache!
686
+ end
687
+
688
+ after(:all) do
689
+ schema_define do
690
+ drop_table :test_posts
691
+ end
692
+ Object.send(:remove_const, "TestPost")
693
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
694
+ end
695
+
696
+ it "should clear older cursors when statement limit is reached" do
697
+ pk = TestPost.columns.find { |c| c.primary }
698
+ sub = @conn.substitute_at(pk, 0)
699
+ binds = [[pk, 1]]
700
+
701
+ lambda {
702
+ 4.times do |i|
703
+ @conn.exec_query("SELECT * FROM test_posts WHERE #{i}=#{i} AND id = #{sub}", "SQL", binds)
704
+ end
705
+ }.should change(@statements, :length).by(+3)
706
+ end
707
+
708
+ it "should cache UPDATE statements with bind variables" do
709
+ lambda {
710
+ pk = TestPost.columns.find { |c| c.primary }
711
+ sub = @conn.substitute_at(pk, 0)
712
+ binds = [[pk, 1]]
713
+ @conn.exec_update("UPDATE test_posts SET id = #{sub}", "SQL", binds)
714
+ }.should change(@statements, :length).by(+1)
715
+ end
716
+
717
+ it "should not cache UPDATE statements without bind variables" do
718
+ lambda {
719
+ binds = []
720
+ @conn.exec_update("UPDATE test_posts SET id = 1", "SQL", binds)
721
+ }.should_not change(@statements, :length)
722
+ end
723
+ end if ENV['RAILS_GEM_VERSION'] >= '3.1'
724
+
725
+ describe "explain" do
726
+ before(:all) do
727
+ schema_define do
728
+ drop_table :test_posts rescue nil
729
+ create_table :test_posts
730
+ end
731
+ class ::TestPost < ActiveRecord::Base
732
+ end
733
+ end
734
+
735
+ after(:all) do
736
+ schema_define do
737
+ drop_table :test_posts
738
+ end
739
+ Object.send(:remove_const, "TestPost")
740
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
741
+ end
742
+
743
+ it "should explain query" do
744
+ explain = TestPost.where(:id => 1).explain
745
+ explain.should include("Cost")
746
+ explain.should include("INDEX UNIQUE SCAN")
747
+ end
748
+ end if ENV['RAILS_GEM_VERSION'] >= '3.2'
656
749
  end
@@ -188,7 +188,30 @@ describe "OracleEnhancedConnection" do
188
188
  cursor.fetch.should be_nil
189
189
  cursor.close
190
190
  end
191
+ end
191
192
 
193
+ describe "SQL with bind parameters when NLS_NUMERIC_CHARACTERS is set to ', '" do
194
+ before(:all) do
195
+ ENV['NLS_NUMERIC_CHARACTERS'] = ", "
196
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhancedConnection.create(CONNECTION_PARAMS)
197
+ @conn.exec "CREATE TABLE test_employees (age NUMBER(10,2))"
198
+ end
199
+
200
+ after(:all) do
201
+ ENV['NLS_NUMERIC_CHARACTERS'] = nil
202
+ @conn.exec "DROP TABLE test_employees" rescue nil
203
+ end
204
+
205
+ it "should execute prepared statement with decimal bind parameter " do
206
+ cursor = @conn.prepare("INSERT INTO test_employees VALUES(:1)")
207
+ cursor.bind_param(1, "1.5", :decimal)
208
+ cursor.exec
209
+ cursor.close
210
+ cursor = @conn.prepare("SELECT age FROM test_employees")
211
+ cursor.exec
212
+ cursor.fetch.should == [1.5]
213
+ cursor.close
214
+ end
192
215
  end
193
216
 
194
217
  describe "auto reconnection" do
@@ -17,23 +17,3 @@ describe "OracleEnhancedAdapter to_d method" do
17
17
  n.to_d.should == BigDecimal.new(n.to_s)
18
18
  end
19
19
  end
20
-
21
- if ENV['RAILS_GEM_VERSION'] >= '2.3'
22
-
23
- describe "OracleEnhancedAdapter Unicode aware upcase and downcase" do
24
- before(:all) do
25
- @down = "āčēģīķļņšūž"
26
- @up = "ĀČĒĢĪĶĻŅŠŪŽ"
27
- end
28
-
29
- it "should translate Unicode string to upcase" do
30
- @down.mb_chars.upcase.to_s.should == @up
31
- end
32
-
33
- it "should translate Unicode string to downcase" do
34
- @up.mb_chars.downcase.to_s.should == @down
35
- end
36
-
37
- end
38
-
39
- end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- if ActiveRecord::Base.instance_methods.include?('changed?')
3
+ if ActiveRecord::Base.method_defined?(:changed?)
4
4
 
5
5
  describe "OracleEnhancedAdapter dirty object tracking" do
6
6
 
@@ -347,11 +347,12 @@ describe "OracleEnhancedAdapter schema dump" do
347
347
 
348
348
  describe 'virtual columns' do
349
349
  before(:all) do
350
+ oracle11g = @oracle11g
350
351
  schema_define do
351
352
  create_table :test_names, :force => true do |t|
352
353
  t.string :first_name
353
354
  t.string :last_name
354
- t.virtual :full_name, :default=>"first_name || ', ' || last_name" if @oracle11g
355
+ t.virtual :full_name, :default=>"first_name || ', ' || last_name" if oracle11g
355
356
  end
356
357
  end
357
358
  end
@@ -346,6 +346,46 @@ describe "OracleEnhancedAdapter schema definition" do
346
346
 
347
347
  end
348
348
 
349
+ describe "rename tables and sequences" do
350
+ before(:each) do
351
+ @conn = ActiveRecord::Base.connection
352
+ schema_define do
353
+ drop_table :test_employees rescue nil
354
+ drop_table :new_test_employees rescue nil
355
+ create_table :test_employees do |t|
356
+ t.string :first_name
357
+ t.string :last_name
358
+ end
359
+ end
360
+ end
361
+
362
+ after(:each) do
363
+ schema_define do
364
+ drop_table :test_employees rescue nil
365
+ drop_table :new_test_employees rescue nil
366
+ end
367
+ end
368
+
369
+ it "should rename table name with new one" do
370
+ lambda do
371
+ @conn.rename_table("test_employees","new_test_employees")
372
+ end.should_not raise_error
373
+ end
374
+
375
+ it "should raise error when new table name length is too long" do
376
+ lambda do
377
+ @conn.rename_table("test_employees","a"*31)
378
+ end.should raise_error
379
+ end
380
+
381
+ it "should raise error when new sequence name length is too long" do
382
+ lambda do
383
+ @conn.rename_table("test_employees","a"*27)
384
+ end.should raise_error
385
+ end
386
+
387
+ end
388
+
349
389
  describe "create triggers" do
350
390
 
351
391
  before(:all) do
@@ -864,10 +904,14 @@ end
864
904
 
865
905
  before(:all) do
866
906
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = true
907
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:clob)
908
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:blob)
867
909
  end
868
910
 
869
911
  after(:all) do
870
912
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = nil
913
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:clob)
914
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:blob)
871
915
  end
872
916
 
873
917
  before(:each) do
@@ -903,7 +947,6 @@ end
903
947
  end
904
948
 
905
949
  it "should add lob column with non_default tablespace" do
906
- ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:clob)
907
950
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = DATABASE_NON_DEFAULT_TABLESPACE
908
951
  schema_define do
909
952
  add_column :test_posts, :body, :text
@@ -912,7 +955,6 @@ end
912
955
  end
913
956
 
914
957
  it "should add blob column with non_default tablespace" do
915
- ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:blob)
916
958
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:blob] = DATABASE_NON_DEFAULT_TABLESPACE
917
959
  schema_define do
918
960
  add_column :test_posts, :attachment, :binary
@@ -941,12 +983,13 @@ end
941
983
 
942
984
  describe 'virtual columns' do
943
985
  before(:all) do
986
+ oracle11g = @oracle11g
944
987
  schema_define do
945
- @expr = "( numerator/NULLIF(denominator,0) )*100"
988
+ expr = "( numerator/NULLIF(denominator,0) )*100"
946
989
  create_table :test_fractions, :force => true do |t|
947
990
  t.integer :numerator, :default=>0
948
991
  t.integer :denominator, :default=>0
949
- t.virtual :percent, :default=>@expr if @oracle11g
992
+ t.virtual :percent, :default=>expr if oracle11g
950
993
  end
951
994
  end
952
995
  end