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.
@@ -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