activerecord-oracle_enhanced-adapter 1.3.0 → 1.3.1

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