activerecord-oracle_enhanced-adapter 1.3.0 → 1.3.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.
Files changed (32) hide show
  1. data/.gitignore +3 -1
  2. data/Gemfile +37 -0
  3. data/History.txt +17 -0
  4. data/README.rdoc +9 -4
  5. data/RUNNING_TESTS.rdoc +28 -0
  6. data/VERSION +1 -1
  7. data/activerecord-oracle_enhanced-adapter.gemspec +13 -6
  8. data/lib/active_record/connection_adapters/oracle_enhanced.rake +32 -24
  9. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +19 -793
  10. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +79 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +106 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +32 -2
  13. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +3 -44
  14. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +2 -2
  15. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +4 -2
  16. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +19 -3
  17. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +14 -6
  18. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +331 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +46 -14
  20. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +290 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +15 -10
  22. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  23. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +51 -19
  24. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +1 -1
  25. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +31 -2
  26. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +152 -11
  27. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +27 -0
  28. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +19 -1
  29. data/spec/active_record/connection_adapters/{oracle_enhanced_schema_spec.rb → oracle_enhanced_schema_statements_spec.rb} +44 -1
  30. data/spec/active_record/connection_adapters/{oracle_enhanced_adapter_structure_dumper_spec.rb → oracle_enhanced_structure_dump_spec.rb} +49 -1
  31. data/spec/spec_helper.rb +60 -53
  32. metadata +15 -8
@@ -35,6 +35,7 @@ end
35
35
 
36
36
  describe "OracleEnhancedAdapter" do
37
37
  include LoggerSpecHelper
38
+ include SchemaSpecHelper
38
39
 
39
40
  before(:all) do
40
41
  ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
@@ -187,12 +188,18 @@ describe "OracleEnhancedAdapter" do
187
188
  )
188
189
  SQL
189
190
  @column_names = ['id', 'first_name', 'last_name', 'hire_date']
191
+ @column_sql_types = ["NUMBER", "VARCHAR2(20)", "VARCHAR2(25)", "DATE"]
190
192
  class ::TestEmployee < ActiveRecord::Base
191
193
  end
194
+ # Another class using the same table
195
+ class ::TestEmployee2 < ActiveRecord::Base
196
+ set_table_name "test_employees"
197
+ end
192
198
  end
193
199
 
194
200
  after(:all) do
195
201
  Object.send(:remove_const, "TestEmployee")
202
+ Object.send(:remove_const, "TestEmployee2")
196
203
  @conn.execute "DROP TABLE test_employees"
197
204
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = nil
198
205
  end
@@ -237,6 +244,13 @@ describe "OracleEnhancedAdapter" do
237
244
  @logger.logged(:debug).last.should =~ /select .* from all_constraints/im
238
245
  end
239
246
 
247
+ it "should have correct sql types when 2 models are using the same table and AR query cache is enabled" do
248
+ @conn.cache do
249
+ TestEmployee.columns.map(&:sql_type).should == @column_sql_types
250
+ TestEmployee2.columns.map(&:sql_type).should == @column_sql_types
251
+ end
252
+ end
253
+
240
254
  end
241
255
 
242
256
  describe "with column caching" do
@@ -305,38 +319,54 @@ describe "OracleEnhancedAdapter" do
305
319
  end
306
320
 
307
321
 
308
- describe "column quoting" do
322
+ describe "reserved words column quoting" do
309
323
 
310
- def create_test_reserved_words_table
311
- ActiveRecord::Schema.define do
312
- suppress_messages do
313
- create_table :test_reserved_words do |t|
314
- t.string :varchar2
315
- t.integer :integer
316
- end
324
+ before(:all) do
325
+ schema_define do
326
+ create_table :test_reserved_words do |t|
327
+ t.string :varchar2
328
+ t.integer :integer
329
+ t.text :comment
317
330
  end
318
331
  end
332
+ class ::TestReservedWord < ActiveRecord::Base; end
319
333
  end
320
334
 
321
- after(:each) do
322
- ActiveRecord::Schema.define do
323
- suppress_messages do
324
- drop_table :test_reserved_words
325
- end
335
+ after(:all) do
336
+ schema_define do
337
+ drop_table :test_reserved_words
326
338
  end
327
339
  Object.send(:remove_const, "TestReservedWord")
328
340
  ActiveRecord::Base.table_name_prefix = nil
329
341
  end
330
342
 
331
- it "should allow creation of a table with oracle reserved words as column names" do
332
- create_test_reserved_words_table
333
- class ::TestReservedWord < ActiveRecord::Base; end
343
+ before(:each) do
344
+ set_logger
345
+ end
334
346
 
335
- [:varchar2, :integer].each do |attr|
347
+ after(:each) do
348
+ clear_logger
349
+ end
350
+
351
+ it "should create table" do
352
+ [:varchar2, :integer, :comment].each do |attr|
336
353
  TestReservedWord.columns_hash[attr.to_s].name.should == attr.to_s
337
354
  end
338
355
  end
339
356
 
357
+ it "should create record" do
358
+ attrs = {
359
+ :varchar2 => 'dummy',
360
+ :integer => 1,
361
+ :comment => 'dummy'
362
+ }
363
+ record = TestReservedWord.create!(attrs)
364
+ record.reload
365
+ attrs.each do |k, v|
366
+ record.send(k).should == v
367
+ end
368
+ end
369
+
340
370
  end
341
371
 
342
372
  describe "valid table names" do
@@ -508,11 +538,13 @@ describe "OracleEnhancedAdapter" do
508
538
 
509
539
  describe "session information" do
510
540
  it "should get current database name" do
511
- @conn.current_database.should == CONNECTION_PARAMS[:database]
541
+ # get database name if using //host:port/database connection string
542
+ database_name = CONNECTION_PARAMS[:database].split('/').last
543
+ @conn.current_database.upcase.should == database_name.upcase
512
544
  end
513
545
 
514
546
  it "should get current database session user" do
515
- @conn.current_user.should == CONNECTION_PARAMS[:username].upcase
547
+ @conn.current_user.upcase.should == CONNECTION_PARAMS[:username].upcase
516
548
  end
517
549
  end
518
550
 
@@ -47,7 +47,7 @@ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
47
47
 
48
48
  it "should create new connection using :url" do
49
49
  params = CONNECTION_PARAMS.dup
50
- params[:url] = "jdbc:oracle:thin:@#{DATABASE_HOST}:#{DATABASE_PORT}:#{DATABASE_NAME}"
50
+ params[:url] = "jdbc:oracle:thin:@#{DATABASE_HOST && "#{DATABASE_HOST}:"}#{DATABASE_PORT && "#{DATABASE_PORT}:"}#{DATABASE_NAME}"
51
51
  params[:host] = nil
52
52
  params[:database] = nil
53
53
  @conn = ActiveRecord::ConnectionAdapters::OracleEnhancedConnection.create(params)
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
4
 
3
5
  describe "OracleEnhancedAdapter context index" do
@@ -45,8 +47,16 @@ describe "OracleEnhancedAdapter context index" do
45
47
  drop_table_posts
46
48
  end
47
49
 
50
+ # Try to grant CTXAPP role to be able to set CONTEXT index parameters.
51
+ def grant_ctxapp
52
+ @sys_conn = ActiveRecord::ConnectionAdapters::OracleEnhancedConnection.create(SYS_CONNECTION_PARAMS)
53
+ @sys_conn.exec "GRANT CTXAPP TO #{DATABASE_USER}"
54
+ rescue
55
+ nil
56
+ end
57
+
48
58
  before(:all) do
49
- # database user should have CTXAPP role to be able to set CONTEXT index parameters
59
+ grant_ctxapp
50
60
  ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
51
61
  @conn = ActiveRecord::Base.connection
52
62
  end
@@ -62,6 +72,8 @@ describe "OracleEnhancedAdapter context index" do
62
72
  @post0 = Post.create(:title => "dummy title", :body => "dummy body")
63
73
  @post1 = Post.create(:title => @title_words.join(' '), :body => @body_words.join(' '))
64
74
  @post2 = Post.create(:title => (@title_words*2).join(' '), :body => (@body_words*2).join(' '))
75
+ @post_with_null_body = Post.create(:title => "withnull", :body => nil)
76
+ @post_with_null_title = Post.create(:title => nil, :body => "withnull")
65
77
  end
66
78
 
67
79
  after(:all) do
@@ -103,6 +115,12 @@ describe "OracleEnhancedAdapter context index" do
103
115
  @conn.remove_context_index :posts, [:title, :body]
104
116
  end
105
117
 
118
+ it "should index records with null values" do
119
+ @conn.add_context_index :posts, [:title, :body]
120
+ Post.contains(:title, "withnull").all.should == [@post_with_null_body, @post_with_null_title]
121
+ @conn.remove_context_index :posts, [:title, :body]
122
+ end
123
+
106
124
  it "should create multiple column index with specified main index column" do
107
125
  @conn.add_context_index :posts, [:title, :body],
108
126
  :index_column => :all_text, :sync => 'ON COMMIT'
@@ -131,6 +149,15 @@ describe "OracleEnhancedAdapter context index" do
131
149
  @conn.remove_context_index :posts, :index_column => :all_text
132
150
  end
133
151
 
152
+ it "should use base letter conversion with BASIC_LEXER" do
153
+ @post = Post.create!(:title => "āčē", :body => "dummy")
154
+ @conn.add_context_index :posts, :title,
155
+ :lexer => { :type => "BASIC_LEXER", :base_letter_type => 'GENERIC', :base_letter => true }
156
+ Post.contains(:title, "āčē").all.should == [@post]
157
+ Post.contains(:title, "ace").all.should == [@post]
158
+ Post.contains(:title, "ACE").all.should == [@post]
159
+ @conn.remove_context_index :posts, :title
160
+ end
134
161
  end
135
162
 
136
163
  describe "on multiple tables" do
@@ -315,6 +342,7 @@ describe "OracleEnhancedAdapter context index" do
315
342
  options = {
316
343
  :name => 'xxx_post_and_comments_i',
317
344
  :index_column => :all_text, :index_column_trigger_on => :updated_at,
345
+ :lexer => { :type => "BASIC_LEXER", :base_letter_type => 'GENERIC', :base_letter => true },
318
346
  :sync => 'ON COMMIT'
319
347
  }
320
348
  schema_define do
@@ -323,7 +351,8 @@ describe "OracleEnhancedAdapter context index" do
323
351
  "SELECT comments.author AS comment_author, comments.body AS comment_body FROM comments WHERE comments.post_id = :id"
324
352
  ], options
325
353
  end
326
- standard_dump.should =~ /add_context_index "posts", \[:title, :body, "SELECT comments.author AS comment_author, comments.body AS comment_body FROM comments WHERE comments.post_id = :id"\], #{options.inspect[1..-2]}$/
354
+ standard_dump.should =~ /add_context_index "posts", \[:title, :body, "SELECT comments.author AS comment_author, comments.body AS comment_body FROM comments WHERE comments.post_id = :id"\], #{
355
+ options.inspect[1..-2].gsub(/[{}]/){|s| '\\'<<s }}$/
327
356
  schema_define { remove_context_index :posts, :name => 'xxx_post_and_comments_i' }
328
357
  end
329
358
 
@@ -724,6 +724,17 @@ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
724
724
  class ::TestEmployee < ActiveRecord::Base
725
725
  set_primary_key :employee_id
726
726
  end
727
+ @today = Date.new(2008,6,28)
728
+ @today_iso = "2008-06-28"
729
+ @today_nls = "28.06.2008"
730
+ @nls_date_format = "%d.%m.%Y"
731
+ @now = Time.local(2008,6,28,13,34,33)
732
+ @now_iso = "2008-06-28 13:34:33"
733
+ @now_nls = "28.06.2008 13:34:33"
734
+ @nls_time_format = "%d.%m.%Y %H:%M:%S"
735
+ @now_nls_with_tz = "28.06.2008 13:34:33+05:00"
736
+ @nls_with_tz_time_format = "%d.%m.%Y %H:%M:%S%Z"
737
+ @now_with_tz = Time.parse @now_nls_with_tz
727
738
  end
728
739
 
729
740
  after(:all) do
@@ -733,14 +744,6 @@ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
733
744
  end
734
745
 
735
746
  before(:each) do
736
- @today = Date.new(2008,6,28)
737
- @today_iso = "2008-06-28"
738
- @today_nls = "28.06.2008"
739
- @nls_date_format = "%d.%m.%Y"
740
- @now = Time.local(2008,6,28,13,34,33)
741
- @now_iso = "2008-06-28 13:34:33"
742
- @now_nls = "28.06.2008 13:34:33"
743
- @nls_time_format = "%d.%m.%Y %H:%M:%S"
744
747
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
745
748
  end
746
749
 
@@ -803,7 +806,6 @@ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
803
806
  end
804
807
 
805
808
  it "should assign NLS time string to datetime column" do
806
- # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_date_format = @nls_date_format
807
809
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_time_format
808
810
  @employee = TestEmployee.create(
809
811
  :first_name => "First",
@@ -814,7 +816,19 @@ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
814
816
  @employee.reload
815
817
  @employee.last_login_at.should == @now
816
818
  end
817
-
819
+
820
+ it "should assign NLS time string with time zone to datetime column" do
821
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_with_tz_time_format
822
+ @employee = TestEmployee.create(
823
+ :first_name => "First",
824
+ :last_name => "Last",
825
+ :last_login_at => @now_nls_with_tz
826
+ )
827
+ @employee.last_login_at.should == @now_with_tz
828
+ @employee.reload
829
+ @employee.last_login_at.should == @now_with_tz
830
+ end
831
+
818
832
  it "should assign ISO date string to datetime column" do
819
833
  @employee = TestEmployee.create(
820
834
  :first_name => "First",
@@ -857,6 +871,8 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
857
871
  CREATE SEQUENCE test_employees_seq MINVALUE 1
858
872
  INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
859
873
  SQL
874
+ @char_data = (0..127).to_a.pack("C*") * 800
875
+ @char_data2 = ((1..127).to_a.pack("C*") + "\0") * 800
860
876
  end
861
877
 
862
878
  after(:all) do
@@ -890,6 +906,93 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
890
906
  @employee.should be_valid
891
907
  end
892
908
 
909
+ it "should create record with CLOB data" do
910
+ @employee = TestEmployee.create!(
911
+ :first_name => "First",
912
+ :last_name => "Last",
913
+ :comments => @char_data
914
+ )
915
+ @employee.reload
916
+ @employee.comments.should == @char_data
917
+ end
918
+
919
+ it "should update record with CLOB data" do
920
+ @employee = TestEmployee.create!(
921
+ :first_name => "First",
922
+ :last_name => "Last"
923
+ )
924
+ @employee.reload
925
+ @employee.comments.should be_nil
926
+ @employee.comments = @char_data
927
+ @employee.save!
928
+ @employee.reload
929
+ @employee.comments.should == @char_data
930
+ end
931
+
932
+ it "should update record with zero-length CLOB data" do
933
+ @employee = TestEmployee.create!(
934
+ :first_name => "First",
935
+ :last_name => "Last"
936
+ )
937
+ @employee.reload
938
+ @employee.comments.should be_nil
939
+ @employee.comments = ''
940
+ @employee.save!
941
+ @employee.reload
942
+ @employee.comments.should == ''
943
+ end
944
+
945
+ it "should update record that has existing CLOB data with different CLOB data" do
946
+ @employee = TestEmployee.create!(
947
+ :first_name => "First",
948
+ :last_name => "Last",
949
+ :comments => @char_data
950
+ )
951
+ @employee.reload
952
+ @employee.comments = @char_data2
953
+ @employee.save!
954
+ @employee.reload
955
+ @employee.comments.should == @char_data2
956
+ end
957
+
958
+ it "should update record that has existing CLOB data with nil" do
959
+ @employee = TestEmployee.create!(
960
+ :first_name => "First",
961
+ :last_name => "Last",
962
+ :comments => @char_data
963
+ )
964
+ @employee.reload
965
+ @employee.comments = nil
966
+ @employee.save!
967
+ @employee.reload
968
+ @employee.comments.should be_nil
969
+ end
970
+
971
+ it "should update record that has existing CLOB data with zero-length CLOB data" do
972
+ @employee = TestEmployee.create!(
973
+ :first_name => "First",
974
+ :last_name => "Last",
975
+ :comments => @char_data
976
+ )
977
+ @employee.reload
978
+ @employee.comments = ''
979
+ @employee.save!
980
+ @employee.reload
981
+ @employee.comments.should == ''
982
+ end
983
+
984
+ it "should update record that has zero-length CLOB data with non-empty CLOB data" do
985
+ @employee = TestEmployee.create!(
986
+ :first_name => "First",
987
+ :last_name => "Last",
988
+ :comments => ''
989
+ )
990
+ @employee.reload
991
+ @employee.comments = @char_data
992
+ @employee.save!
993
+ @employee.reload
994
+ @employee.comments.should == @char_data
995
+ end
893
996
  end
894
997
 
895
998
  describe "OracleEnhancedAdapter handling of BLOB columns" do
@@ -950,6 +1053,19 @@ describe "OracleEnhancedAdapter handling of BLOB columns" do
950
1053
  @employee.binary_data.should == @binary_data
951
1054
  end
952
1055
 
1056
+ it "should update record with zero-length BLOB data" do
1057
+ @employee = TestEmployee.create!(
1058
+ :first_name => "First",
1059
+ :last_name => "Last"
1060
+ )
1061
+ @employee.reload
1062
+ @employee.binary_data.should be_nil
1063
+ @employee.binary_data = ''
1064
+ @employee.save!
1065
+ @employee.reload
1066
+ @employee.binary_data.should == ''
1067
+ end
1068
+
953
1069
  it "should update record that has existing BLOB data with different BLOB data" do
954
1070
  @employee = TestEmployee.create!(
955
1071
  :first_name => "First",
@@ -975,6 +1091,31 @@ describe "OracleEnhancedAdapter handling of BLOB columns" do
975
1091
  @employee.reload
976
1092
  @employee.binary_data.should be_nil
977
1093
  end
978
-
1094
+
1095
+ it "should update record that has existing BLOB data with zero-length BLOB data" do
1096
+ @employee = TestEmployee.create!(
1097
+ :first_name => "First",
1098
+ :last_name => "Last",
1099
+ :binary_data => @binary_data
1100
+ )
1101
+ @employee.reload
1102
+ @employee.binary_data = ''
1103
+ @employee.save!
1104
+ @employee.reload
1105
+ @employee.binary_data.should == ''
1106
+ end
1107
+
1108
+ it "should update record that has zero-length BLOB data with non-empty BLOB data" do
1109
+ @employee = TestEmployee.create!(
1110
+ :first_name => "First",
1111
+ :last_name => "Last",
1112
+ :binary_data => ''
1113
+ )
1114
+ @employee.reload
1115
+ @employee.binary_data = @binary_data
1116
+ @employee.save!
1117
+ @employee.reload
1118
+ @employee.binary_data.should == @binary_data
1119
+ end
979
1120
  end
980
1121
 
@@ -60,6 +60,15 @@ if ActiveRecord::Base.instance_methods.include?('changed?')
60
60
  end
61
61
 
62
62
  it "should not mark empty text (stored as NULL) as changed when reassigning it" do
63
+ @employee = TestEmployee.create!(:comments => nil)
64
+ @employee.comments = nil
65
+ @employee.should_not be_changed
66
+ @employee.reload
67
+ @employee.comments = nil
68
+ @employee.should_not be_changed
69
+ end
70
+
71
+ it "should not mark empty text (stored as empty_clob()) as changed when reassigning it" do
63
72
  @employee = TestEmployee.create!(:comments => '')
64
73
  @employee.comments = ''
65
74
  @employee.should_not be_changed
@@ -68,6 +77,24 @@ if ActiveRecord::Base.instance_methods.include?('changed?')
68
77
  @employee.should_not be_changed
69
78
  end
70
79
 
80
+ it "should mark empty text (stored as empty_clob()) as changed when assigning nil to it" do
81
+ @employee = TestEmployee.create!(:comments => '')
82
+ @employee.comments = nil
83
+ @employee.should be_changed
84
+ @employee.reload
85
+ @employee.comments = nil
86
+ @employee.should be_changed
87
+ end
88
+
89
+ it "should mark empty text (stored as NULL) as changed when assigning '' to it" do
90
+ @employee = TestEmployee.create!(:comments => nil)
91
+ @employee.comments = ''
92
+ @employee.should be_changed
93
+ @employee.reload
94
+ @employee.comments = ''
95
+ @employee.should be_changed
96
+ end
97
+
71
98
  it "should not mark empty date (stored as NULL) as changed when reassigning it" do
72
99
  @employee = TestEmployee.create!(:hire_date => '')
73
100
  @employee.hire_date = ''