From 7e560d0b0d9414d5712f068f6eb5f8bde1980558 Mon Sep 17 00:00:00 2001 From: Rob Christie Date: Wed, 14 Jan 2009 01:14:02 -0500 Subject: [PATCH 01/22] Fixed adapter test cases that were failing in oracle because the asserts were looking for the presence of offset and limit which are not available in oracle. Changed the tests to check that the sql injection is not present in the output so that the tests are database adapter agnostic. --- activerecord/test/cases/adapter_test.rb | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 80530194ff455..65c5fc2fe943a 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -112,23 +112,14 @@ def test_reset_table_with_non_integer_pk def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas sql_inject = "1 select * from schema" - assert_equal " LIMIT 1", @connection.add_limit_offset!("", :limit=>sql_inject) - if current_adapter?(:MysqlAdapter) - assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) - else - assert_equal " LIMIT 1 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) - end + assert_no_match /schema/, @connection.add_limit_offset!("", :limit=>sql_inject) + assert_no_match /schema/, @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) end def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas sql_inject = "1, 7 procedure help()" - if current_adapter?(:MysqlAdapter) - assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) - assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=> '1 ; DROP TABLE USERS', :offset=>7) - else - assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) - assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) - end + assert_no_match /procedure/, @connection.add_limit_offset!("", :limit=>sql_inject) + assert_no_match /procedure/, @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) end def test_uniqueness_violations_are_translated_to_specific_exception From 04fea8a07ba94d381b03fae4a657077a7b966229 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sun, 15 Mar 2009 14:40:07 +0200 Subject: [PATCH 02/22] modified native_oracle/connection.rb to run it with oracle_enhanced adapter --- .../connections/native_oracle/connection.rb | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/activerecord/test/connections/native_oracle/connection.rb b/activerecord/test/connections/native_oracle/connection.rb index 0954b27f8728b..1be4e23b84dbf 100644 --- a/activerecord/test/connections/native_oracle/connection.rb +++ b/activerecord/test/connections/native_oracle/connection.rb @@ -1,25 +1,36 @@ +# gem "rsim-activerecord-oracle_enhanced-adapter" +# gem "activerecord-oracle_enhanced-adapter" +# uses local copy of oracle_enhanced adapter +$:.unshift("../../oracle-enhanced/lib") +require 'active_record/connection_adapters/oracle_enhanced_adapter' + print "Using Oracle\n" require_dependency 'models/course' require 'logger' -ActiveRecord::Base.logger = Logger.new STDOUT -ActiveRecord::Base.logger.level = Logger::WARN +# ActiveRecord::Base.logger = Logger.new STDOUT +# ActiveRecord::Base.logger.level = Logger::WARN +ActiveRecord::Base.logger = Logger.new("debug.log") # Set these to your database connection strings -db = ENV['ARUNIT_DB'] || 'activerecord_unittest' +db = ENV['ARUNIT_DB'] || 'XE' ActiveRecord::Base.configurations = { 'arunit' => { - :adapter => 'oracle', + :adapter => 'oracle_enhanced', + :database => db, + :host => "arunit", # used just by JRuby to construct JDBC connect string :username => 'arunit', :password => 'arunit', - :database => db, + :emulate_oracle_adapter => true }, 'arunit2' => { - :adapter => 'oracle', + :adapter => 'oracle_enhanced', + :database => db, + :host => "arunit", # used just by JRuby to construct JDBC connect string :username => 'arunit2', :password => 'arunit2', - :database => db + :emulate_oracle_adapter => true } } From 963570b51ce4d95b046a441dd1c413dc6fcec8b4 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sun, 22 Mar 2009 23:50:05 +0200 Subject: [PATCH 03/22] added additional objects necessary for OracleAdapter specific tests if OracleAdapter is used then use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in Oracle SELECT WHERE clause which causes many unit test failures --- .../test/schema/oracle_specific_schema.rb | 27 +++++++++++++++++++ activerecord/test/schema/schema.rb | 24 ++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/activerecord/test/schema/oracle_specific_schema.rb b/activerecord/test/schema/oracle_specific_schema.rb index 2d87f34625158..33146874456f6 100644 --- a/activerecord/test/schema/oracle_specific_schema.rb +++ b/activerecord/test/schema/oracle_specific_schema.rb @@ -2,6 +2,10 @@ execute "drop table test_oracle_defaults" rescue nil execute "drop sequence test_oracle_defaults_seq" rescue nil + execute "drop sequence companies_nonstd_seq" rescue nil + execute "drop synonym subjects" rescue nil + execute "drop table defaults" rescue nil + execute "drop sequence defaults_seq" rescue nil execute <<-SQL create table test_oracle_defaults ( @@ -16,4 +20,27 @@ create sequence test_oracle_defaults_seq minvalue 10000 SQL + execute "create sequence companies_nonstd_seq minvalue 10000" + + execute "create synonym subjects for topics" + + execute <<-SQL + CREATE TABLE defaults ( + id integer not null, + modified_date date default sysdate, + modified_date_function date default sysdate, + fixed_date date default to_date('2004-01-01', 'YYYY-MM-DD'), + modified_time date default sysdate, + modified_time_function date default sysdate, + fixed_time date default TO_DATE('2004-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), + char1 varchar2(1) default 'Y', + char2 varchar2(50) default 'a varchar field', + char3 clob default 'a text field', + positive_integer integer default 1, + negative_integer integer default -1, + decimal_number number(3,2) default 2.78 + ) + SQL + execute "create sequence defaults_seq minvalue 10000" + end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 1e47cdbaf6493..5752d6fa40017 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -104,7 +104,13 @@ def create_table(*args, &block) create_table :comments, :force => true do |t| t.integer :post_id, :null => false - t.text :body, :null => false + # use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in + # Oracle SELECT WHERE clause which causes many unit test failures + if current_adapter?(:OracleAdapter) + t.string :body, :null => false, :limit => 4000 + else + t.text :body, :null => false + end t.string :type end @@ -350,7 +356,13 @@ def create_table(*args, &block) create_table :posts, :force => true do |t| t.integer :author_id t.string :title, :null => false - t.text :body, :null => false + # use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in + # Oracle SELECT WHERE clause which causes many unit test failures + if current_adapter?(:OracleAdapter) + t.string :body, :null => false, :limit => 4000 + else + t.text :body, :null => false + end t.string :type t.integer :comments_count, :default => 0 t.integer :taggings_count, :default => 0 @@ -423,7 +435,13 @@ def create_table(*args, &block) t.datetime :written_on t.time :bonus_time t.date :last_read - t.text :content + # use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in + # Oracle SELECT WHERE clause which causes many unit test failures + if current_adapter?(:OracleAdapter) + t.string :content, :limit => 4000 + else + t.text :content + end t.boolean :approved, :default => true t.integer :replies_count, :default => 0 t.integer :parent_id From 5666a3ad065469f12e5b3a4de0be823c9ae4ff7d Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sun, 22 Mar 2009 23:57:24 +0200 Subject: [PATCH 04/22] added :order option to find :first methods and associations as otherwise Oracle tests were failing Oracle stores '' string as NULL Oracle cannot have identifiers larger than 30 characters added missing fixtures to test setup method --- .../belongs_to_associations_test.rb | 6 +- .../test/cases/associations/eager_test.rb | 7 +- ...s_and_belongs_to_many_associations_test.rb | 6 +- .../has_many_associations_test.rb | 80 ++++++++++--------- .../cases/associations/join_model_test.rb | 10 ++- activerecord/test/models/company.rb | 8 +- 6 files changed, 69 insertions(+), 48 deletions(-) diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index ab6f75224327a..784c4841786ad 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -293,7 +293,8 @@ def test_assignment_before_child_saved_with_primary_key def test_new_record_with_foreign_key_but_no_object c = Client.new("firm_id" => 1) - assert_equal Firm.find(:first), c.firm_with_basic_id + # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first + assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id end def test_forgetting_the_load_when_foreign_key_enters_late @@ -301,7 +302,8 @@ def test_forgetting_the_load_when_foreign_key_enters_late assert_nil c.firm_with_basic_id c.firm_id = 1 - assert_equal Firm.find(:first), c.firm_with_basic_id + # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first + assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id end def test_field_name_same_as_foreign_key diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 4cf49be66886b..811ebfbe3fccf 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -813,7 +813,12 @@ def test_preload_has_many_using_primary_key def test_include_has_many_using_primary_key expected = Firm.find(1).clients_using_primary_key.sort_by &:name - firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name' + # Oracle adapter truncates alias to 30 characters + if current_adapter?(:OracleAdapter) + firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies'[0,30]+'.name' + else + firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name' + end assert_no_queries do assert_equal expected, firm.clients_using_primary_key end diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 14b96caaae149..11a159686e064 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -284,12 +284,14 @@ def test_create_by_new_record end def test_creation_respects_hash_condition - post = categories(:general).post_with_conditions.build(:body => '') + # in Oracle '' is saved as null therefore need to save ' ' in not null column + post = categories(:general).post_with_conditions.build(:body => ' ') assert post.save assert_equal 'Yet Another Testing Title', post.title - another_post = categories(:general).post_with_conditions.create(:body => '') + # in Oracle '' is saved as null therefore need to save ' ' in not null column + another_post = categories(:general).post_with_conditions.create(:body => ' ') assert !another_post.new_record? assert_equal 'Yet Another Testing Title', another_post.title diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 15919e228957f..a3d92c3bdb798 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -24,28 +24,29 @@ def force_signal37_to_load_all_clients_of_firm companies(:first_firm).clients_of_firm.each {|f| } end + # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first def test_counting_with_counter_sql - assert_equal 2, Firm.find(:first).clients.count + assert_equal 2, Firm.find(:first, :order => "id").clients.count end def test_counting - assert_equal 2, Firm.find(:first).plain_clients.count + assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count end def test_counting_with_empty_hash_conditions - assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => {}) + assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count(:conditions => {}) end def test_counting_with_single_conditions - assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => ['name=?', "Microsoft"]) + assert_equal 1, Firm.find(:first, :order => "id").plain_clients.count(:conditions => ['name=?', "Microsoft"]) end def test_counting_with_single_hash - assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => {:name => "Microsoft"}) + assert_equal 1, Firm.find(:first, :order => "id").plain_clients.count(:conditions => {:name => "Microsoft"}) end def test_counting_with_column_name_and_hash - assert_equal 2, Firm.find(:first).plain_clients.count(:name) + assert_equal 2, Firm.find(:first, :order => "id").plain_clients.count(:name) end def test_counting_with_association_limit @@ -55,12 +56,12 @@ def test_counting_with_association_limit end def test_finding - assert_equal 2, Firm.find(:first).clients.length + assert_equal 2, Firm.find(:first, :order => "id").clients.length end def test_find_with_blank_conditions [[], {}, nil, ""].each do |blank| - assert_equal 2, Firm.find(:first).clients.find(:all, :conditions => blank).size + assert_equal 2, Firm.find(:first, :order => "id").clients.find(:all, :conditions => blank).size end end @@ -115,52 +116,53 @@ def test_cant_save_has_many_readonly_association end def test_triple_equality - assert !(Array === Firm.find(:first).clients) - assert Firm.find(:first).clients === Array + # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first + assert !(Array === Firm.find(:first, :order => "id").clients) + assert Firm.find(:first, :order => "id").clients === Array end def test_finding_default_orders - assert_equal "Summit", Firm.find(:first).clients.first.name + assert_equal "Summit", Firm.find(:first, :order => "id").clients.first.name end def test_finding_with_different_class_name_and_order - assert_equal "Microsoft", Firm.find(:first).clients_sorted_desc.first.name + assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_sorted_desc.first.name end def test_finding_with_foreign_key - assert_equal "Microsoft", Firm.find(:first).clients_of_firm.first.name + assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_of_firm.first.name end def test_finding_with_condition - assert_equal "Microsoft", Firm.find(:first).clients_like_ms.first.name + assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_like_ms.first.name end def test_finding_with_condition_hash - assert_equal "Microsoft", Firm.find(:first).clients_like_ms_with_hash_conditions.first.name + assert_equal "Microsoft", Firm.find(:first, :order => "id").clients_like_ms_with_hash_conditions.first.name end def test_finding_using_primary_key - assert_equal "Summit", Firm.find(:first).clients_using_primary_key.first.name + assert_equal "Summit", Firm.find(:first, :order => "id").clients_using_primary_key.first.name end def test_finding_using_sql - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") first_client = firm.clients_using_sql.first assert_not_nil first_client assert_equal "Microsoft", first_client.name assert_equal 1, firm.clients_using_sql.size - assert_equal 1, Firm.find(:first).clients_using_sql.size + assert_equal 1, Firm.find(:first, :order => "id").clients_using_sql.size end def test_counting_using_sql - assert_equal 1, Firm.find(:first).clients_using_counter_sql.size - assert Firm.find(:first).clients_using_counter_sql.any? - assert_equal 0, Firm.find(:first).clients_using_zero_counter_sql.size - assert !Firm.find(:first).clients_using_zero_counter_sql.any? + assert_equal 1, Firm.find(:first, :order => "id").clients_using_counter_sql.size + assert Firm.find(:first, :order => "id").clients_using_counter_sql.any? + assert_equal 0, Firm.find(:first, :order => "id").clients_using_zero_counter_sql.size + assert !Firm.find(:first, :order => "id").clients_using_zero_counter_sql.any? end def test_counting_non_existant_items_using_sql - assert_equal 0, Firm.find(:first).no_clients_using_counter_sql.size + assert_equal 0, Firm.find(:first, :order => "id").no_clients_using_counter_sql.size end def test_counting_using_finder_sql @@ -183,7 +185,7 @@ def test_belongs_to_sanity end def test_find_ids - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find } @@ -203,7 +205,7 @@ def test_find_ids end def test_find_string_ids_when_using_finder_sql - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") client = firm.clients_using_finder_sql.find("2") assert_kind_of Client, client @@ -219,7 +221,7 @@ def test_find_string_ids_when_using_finder_sql end def test_find_all - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") assert_equal 2, firm.clients.find(:all, :conditions => "#{QUOTED_TYPE} = 'Client'").length assert_equal 1, firm.clients.find(:all, :conditions => "name = 'Summit'").length end @@ -264,24 +266,25 @@ def test_find_in_batches end def test_find_all_sanitized - firm = Firm.find(:first) + # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first + firm = Firm.find(:first, :order => "id") summit = firm.clients.find(:all, :conditions => "name = 'Summit'") assert_equal summit, firm.clients.find(:all, :conditions => ["name = ?", "Summit"]) assert_equal summit, firm.clients.find(:all, :conditions => ["name = :name", { :name => "Summit" }]) end def test_find_first - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") client2 = Client.find(2) - assert_equal firm.clients.first, firm.clients.find(:first) - assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'") + assert_equal firm.clients.first, firm.clients.find(:first, :order => "id") + assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'", :order => "id") end def test_find_first_sanitized - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") client2 = Client.find(2) - assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client']) - assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }]) + assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client'], :order => "id") + assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }], :order => "id") end def test_find_in_collection @@ -341,7 +344,7 @@ def test_regular_create_on_has_many_when_parent_is_new_raises def test_create_with_bang_on_has_many_raises_when_record_not_saved assert_raise(ActiveRecord::RecordInvalid) do - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") firm.plain_clients.create! end end @@ -731,7 +734,8 @@ def test_dependence_for_associations_with_hash_condition end def test_destroy_dependent_when_deleted_from_association - firm = Firm.find(:first) + # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first + firm = Firm.find(:first, :order => "id") assert_equal 2, firm.clients.size client = firm.clients.first @@ -798,7 +802,7 @@ def test_find_all_without_conditions end def test_replace_with_less - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") firm.clients = [companies(:first_client)] assert firm.save, "Could not save firm" firm.reload @@ -812,7 +816,7 @@ def test_replace_with_less_and_dependent_nullify end def test_replace_with_new - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") firm.clients = [companies(:second_client), Client.new("name" => "New Client")] firm.save firm.reload @@ -1104,7 +1108,7 @@ def test_respond_to_private_class_methods end def test_creating_using_primary_key - firm = Firm.find(:first) + firm = Firm.find(:first, :order => "id") client = firm.clients_using_primary_key.create!(:name => 'test') assert_equal firm.name, client.firm_name end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index b1060d01af7ed..9da7fc2639f85 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -14,7 +14,9 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase self.use_transactional_fixtures = false - fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books + fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books, + # Reload edges table from fixtures as otherwise repeated test was failing + :edges def test_has_many assert authors(:david).categories.include?(categories(:general)) @@ -343,14 +345,16 @@ def test_has_many_polymorphic end def test_has_many_polymorphic_with_source_type - assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts + # added sort by ID as otherwise Oracle select sometimes returned rows in different order + assert_equal posts(:welcome, :thinking).sort_by(&:id), tags(:general).tagged_posts.sort_by(&:id) end def test_eager_has_many_polymorphic_with_source_type tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts) desired = posts(:welcome, :thinking) assert_no_queries do - assert_equal desired, tag_with_include.tagged_posts + # added sort by ID as otherwise test using JRuby was failing as array elements were in different order + assert_equal desired.sort_by(&:id), tag_with_include.tagged_posts.sort_by(&:id) end assert_equal 5, tag_with_include.taggings.length end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 22168468a6650..1c05e523e0c28 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -73,12 +73,16 @@ class Firm < Company has_one :unvalidated_account, :foreign_key => "firm_id", :class_name => 'Account', :validate => false has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account' has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true - has_one :account_using_primary_key, :primary_key => "firm_id", :class_name => "Account" + # added order by id as in fixtures there are two accounts for Rails Core + # Oracle tests were failing because of that as the second fixture was selected + has_one :account_using_primary_key, :primary_key => "firm_id", :class_name => "Account", :order => "id" has_one :deletable_account, :foreign_key => "firm_id", :class_name => "Account", :dependent => :delete end class DependentFirm < Company - has_one :account, :foreign_key => "firm_id", :dependent => :nullify + # added order by id as in fixtures there are two accounts for Rails Core + # Oracle tests were failing because of that as the second fixture was selected + has_one :account, :foreign_key => "firm_id", :dependent => :nullify, :order => "id" has_many :companies, :foreign_key => 'client_of', :order => "id", :dependent => :nullify end From 71c32d3cacb7b0c0f0828caa5555f279777364fa Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:03:34 +0200 Subject: [PATCH 05/22] 1=2 is invalid expression in Oracle SELECT --- activerecord/test/cases/attribute_methods_test.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index ab8768ea3e191..055590da0aad4 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -75,13 +75,23 @@ def test_should_unserialize_attributes_for_frozen_records def test_typecast_attribute_from_select_to_false topic = Topic.create(:title => 'Budget') - topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test") + # Oracle does not support boolean expressions in SELECT + if current_adapter?(:OracleAdapter) + topic = Topic.find(:first, :select => "topics.*, 0 as is_test") + else + topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test") + end assert !topic.is_test? end def test_typecast_attribute_from_select_to_true topic = Topic.create(:title => 'Budget') - topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test") + # Oracle does not support boolean expressions in SELECT + if current_adapter?(:OracleAdapter) + topic = Topic.find(:first, :select => "topics.*, 1 as is_test") + else + topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test") + end assert topic.is_test? end From d40e3ea936fe37f0dba696c611d49c700ffa3542 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:05:41 +0200 Subject: [PATCH 06/22] Oracle saves empty string as NULL --- .../test/cases/autosave_association_test.rb | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index ddca5e962d406..271086af8ed23 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -154,7 +154,8 @@ def test_should_save_parent_but_not_invalid_child end def test_save_fails_for_invalid_belongs_to - assert log = AuditLog.create(:developer_id => 0, :message => "") + # Oracle saves empty string as NULL therefore :message changed to one space + assert log = AuditLog.create(:developer_id => 0, :message => " ") log.developer = Developer.new assert !log.developer.valid? @@ -164,7 +165,8 @@ def test_save_fails_for_invalid_belongs_to end def test_save_succeeds_for_invalid_belongs_to_with_validate_false - assert log = AuditLog.create(:developer_id => 0, :message=> "") + # Oracle saves empty string as NULL therefore :message changed to one space + assert log = AuditLog.create(:developer_id => 0, :message=> " ") log.unvalidated_developer = Developer.new assert !log.unvalidated_developer.valid? @@ -666,7 +668,12 @@ def test_should_still_allow_to_bypass_validations_on_the_associated_model @pirate.catchphrase = '' @pirate.ship.name = '' @pirate.save(false) - assert_equal ['', ''], [@pirate.reload.catchphrase, @pirate.ship.name] + # Oracle saves empty string as NULL + if current_adapter?(:OracleAdapter) + assert_equal [nil, nil], [@pirate.reload.catchphrase, @pirate.ship.name] + else + assert_equal ['', ''], [@pirate.reload.catchphrase, @pirate.ship.name] + end end def test_should_allow_to_bypass_validations_on_associated_models_at_any_depth @@ -678,7 +685,12 @@ def test_should_allow_to_bypass_validations_on_associated_models_at_any_depth @pirate.save(false) values = [@pirate.reload.catchphrase, @pirate.ship.name, *@pirate.ship.parts.map(&:name)] - assert_equal ['', '', '', ''], values + # Oracle saves empty string as NULL + if current_adapter?(:OracleAdapter) + assert_equal [nil, nil, nil, nil], values + else + assert_equal ['', '', '', ''], values + end end def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that @@ -756,7 +768,12 @@ def test_should_still_allow_to_bypass_validations_on_the_associated_model @ship.pirate.catchphrase = '' @ship.name = '' @ship.save(false) - assert_equal ['', ''], [@ship.reload.name, @ship.pirate.catchphrase] + # Oracle saves empty string as NULL + if current_adapter?(:OracleAdapter) + assert_equal [nil, nil], [@ship.reload.name, @ship.pirate.catchphrase] + else + assert_equal ['', ''], [@ship.reload.name, @ship.pirate.catchphrase] + end end def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that @@ -837,11 +854,20 @@ def test_should_allow_to_bypass_validations_on_the_associated_models_on_update @pirate.send(@association_name).each { |child| child.name = '' } assert @pirate.save(false) - assert_equal ['', '', ''], [ - @pirate.reload.catchphrase, - @pirate.send(@association_name).first.name, - @pirate.send(@association_name).last.name - ] + # Oracle saves empty string as NULL + if current_adapter?(:OracleAdapter) + assert_equal [nil, nil, nil], [ + @pirate.reload.catchphrase, + @pirate.send(@association_name).first.name, + @pirate.send(@association_name).last.name + ] + else + assert_equal ['', '', ''], [ + @pirate.reload.catchphrase, + @pirate.send(@association_name).first.name, + @pirate.send(@association_name).last.name + ] + end end def test_should_validation_the_associated_models_on_create From a12358b3a5e69f41079595d5c92677b66ae6e642 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:07:23 +0200 Subject: [PATCH 07/22] Oracle adapter returns numeric (not string) value after SUM --- activerecord/test/cases/calculations_test.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 75f52dfa4ae00..24bc4f71ce412 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -298,7 +298,12 @@ def test_count_with_too_many_parameters_raises end def test_should_sum_expression - assert_equal '636', Account.sum("2 * credit_limit") + # Oracle adapter returns floating point value 636.0 after SUM + if current_adapter?(:OracleAdapter) + assert_equal 636, Account.sum("2 * credit_limit") + else + assert_equal '636', Account.sum("2 * credit_limit") + end end def test_count_with_from_option From c3e1ef0b4051c515fa2e3f49ea47309c79a89aee Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:08:37 +0200 Subject: [PATCH 08/22] Oracle needs sequence value for primary key in INSERT statement --- activerecord/test/cases/database_statements_test.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb index 6274d5250f4e1..c689e97d8396b 100644 --- a/activerecord/test/cases/database_statements_test.rb +++ b/activerecord/test/cases/database_statements_test.rb @@ -6,7 +6,14 @@ def setup end def test_insert_should_return_the_inserted_id - id = @connection.insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)") + # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method + if current_adapter?(:OracleAdapter) + sequence_name = "accounts_seq" + id_value = @connection.next_sequence_value(sequence_name) + id = @connection.insert("INSERT INTO accounts (id, firm_id,credit_limit) VALUES (accounts_seq.nextval,42,5000)", nil, :id, id_value, sequence_name) + else + id = @connection.insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)") + end assert_not_nil id end end From 42fd2a3b162e8f93e9c39b07253561bde3c00e35 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:14:42 +0200 Subject: [PATCH 09/22] added :order to find :all as otherwise Oracle tests were failing --- activerecord/test/cases/inheritance_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 167d3abad91f3..5cd11e979907a 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -137,7 +137,8 @@ def test_alt_finding_incorrect_type_data def test_update_all_within_inheritance Client.update_all "name = 'I am a client'" assert_equal "I am a client", Client.find(:all).first.name - assert_equal "37signals", Firm.find(:all).first.name + # Order by added as otherwise Oracle tests were failing because of different order of results + assert_equal "37signals", Firm.find(:all, :order => "id").first.name end def test_alt_update_all_within_inheritance From 3a1cbc5c3b3bcb2de4be6e4469bb87b99759dc59 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:15:59 +0200 Subject: [PATCH 10/22] Oracle adapter returns Time value for DATE columns --- activerecord/test/cases/invalid_date_test.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/invalid_date_test.rb b/activerecord/test/cases/invalid_date_test.rb index e2bb17c37fa4a..99af7d298604f 100644 --- a/activerecord/test/cases/invalid_date_test.rb +++ b/activerecord/test/cases/invalid_date_test.rb @@ -11,13 +11,23 @@ def test_assign_valid_dates valid_dates.each do |date_src| topic = Topic.new("last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s) - assert_equal(topic.last_read, Date.new(*date_src)) + # Oracle DATE columns are datetime columns and Oracle adapter returns Time value + if current_adapter?(:OracleAdapter) + assert_equal(topic.last_read.to_date, Date.new(*date_src)) + else + assert_equal(topic.last_read, Date.new(*date_src)) + end end invalid_dates.each do |date_src| assert_nothing_raised do topic = Topic.new({"last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s}) - assert_equal(topic.last_read, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object") + # Oracle DATE columns are datetime columns and Oracle adapter returns Time value + if current_adapter?(:OracleAdapter) + assert_equal(topic.last_read.to_date, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object") + else + assert_equal(topic.last_read, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object") + end end end end From ee654e54c40ef41cf8bfa4c25324faeb2bf59de0 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:17:05 +0200 Subject: [PATCH 11/22] Oracle generates different ORDER BY fragment --- activerecord/test/cases/method_scoping_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index d8246f49b89bc..35f7bc54433da 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -379,7 +379,8 @@ def test_merged_scoped_find poor_jamis = developers(:poor_jamis) Developer.with_scope(:find => { :conditions => "salary < 100000" }) do Developer.with_scope(:find => { :offset => 1, :order => 'id asc' }) do - assert_sql /ORDER BY id asc / do + # Oracle adapter does not generated space after asc therefore trailing space removed from regex + assert_sql /ORDER BY id asc/ do assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc')) end end From 5d0dece6a69c31437b29396a3d4d04f092a9fc1f Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:18:21 +0200 Subject: [PATCH 12/22] Oracle adapter gets Time or DateTime value already with timezone --- activerecord/test/cases/migration_test.rb | 63 +++++++++++++++++------ 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 215b5a427a7fa..03788bf69e37a 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -446,18 +446,22 @@ def test_native_types assert_equal Date, bob.favorite_day.class end - # Test DateTime column and defaults, including timezone. - # FIXME: moment of truth may be Time on 64-bit platforms. - if bob.moment_of_truth.is_a?(DateTime) - - with_env_tz 'US/Eastern' do - assert_equal DateTime.local_offset, bob.moment_of_truth.offset - assert_not_equal 0, bob.moment_of_truth.offset - assert_not_equal "Z", bob.moment_of_truth.zone - # US/Eastern is -5 hours from GMT - assert_equal Rational(-5, 24), bob.moment_of_truth.offset - assert_match /\A-05:?00\Z/, bob.moment_of_truth.zone #ruby 1.8.6 uses HH:MM, prior versions use HHMM - assert_equal DateTime::ITALY, bob.moment_of_truth.start + # Oracle adapter stores Time or DateTime with timezone value already in _before_type_cast column + # therefore no timezone change is done afterwards when default timezone is changed + unless current_adapter?(:OracleAdapter) + # Test DateTime column and defaults, including timezone. + # FIXME: moment of truth may be Time on 64-bit platforms. + if bob.moment_of_truth.is_a?(DateTime) + + with_env_tz 'US/Eastern' do + assert_equal DateTime.local_offset, bob.moment_of_truth.offset + assert_not_equal 0, bob.moment_of_truth.offset + assert_not_equal "Z", bob.moment_of_truth.zone + # US/Eastern is -5 hours from GMT + assert_equal Rational(-5, 24), bob.moment_of_truth.offset + assert_match /\A-05:?00\Z/, bob.moment_of_truth.zone #ruby 1.8.6 uses HH:MM, prior versions use HHMM + assert_equal DateTime::ITALY, bob.moment_of_truth.start + end end end @@ -571,7 +575,7 @@ def test_rename_nonexistent_column ActiveRecord::Base.connection.create_table(:hats) do |table| table.column :hat_name, :string, :default => nil end - exception = if current_adapter?(:PostgreSQLAdapter) + exception = if current_adapter?(:PostgreSQLAdapter, :OracleAdapter) ActiveRecord::StatementInvalid else ActiveRecord::ActiveRecordError @@ -625,7 +629,13 @@ def test_remove_column_with_multi_column_index table.column :hat_size, :integer table.column :hat_style, :string, :limit => 100 end - ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true + # Oracle index names should be 30 or less characters + if current_adapter?(:OracleAdapter) + ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true, + :name => 'index_hats_on_hat_style_size' + else + ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true + end assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") } ensure @@ -783,7 +793,12 @@ def test_change_column_quotes_column_names assert_nothing_raised { Person.connection.change_column :testings, :select, :string, :limit => 10 } - assert_nothing_raised { Person.connection.execute "insert into testings (#{Person.connection.quote_column_name('select')}) values ('7 chars')" } + # Oracle needs primary key value from sequence + if current_adapter?(:OracleAdapter) + assert_nothing_raised { Person.connection.execute "insert into testings (id, #{Person.connection.quote_column_name('select')}) values (testings_seq.nextval, '7 chars')" } + else + assert_nothing_raised { Person.connection.execute "insert into testings (#{Person.connection.quote_column_name('select')}) values ('7 chars')" } + end ensure Person.connection.drop_table :testings rescue nil end @@ -799,7 +814,12 @@ def test_keeping_default_and_notnull_constaint_on_change person_klass.reset_column_information assert_equal 99, person_klass.columns_hash["wealth"].default assert_equal false, person_klass.columns_hash["wealth"].null - assert_nothing_raised {person_klass.connection.execute("insert into testings (title) values ('tester')")} + # Oracle needs primary key value from sequence + if current_adapter?(:OracleAdapter) + assert_nothing_raised {person_klass.connection.execute("insert into testings (id, title) values (testings_seq.nextval, 'tester')")} + else + assert_nothing_raised {person_klass.connection.execute("insert into testings (title) values ('tester')")} + end # change column default to see that column doesn't lose its not null definition person_klass.connection.change_column_default "testings", "wealth", 100 @@ -1054,7 +1074,12 @@ def test_migrator_interleaved_migrations end def test_migrator_db_has_no_schema_migrations_table - ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations;") + # Oracle adapter raises error if semicolon is present as last character + if current_adapter?(:OracleAdapter) + ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations") + else + ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations;") + end assert_nothing_raised do ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 1) end @@ -1412,6 +1437,8 @@ def test_remove_timestamps_creates_updated_at_and_created_at def string_column if current_adapter?(:PostgreSQLAdapter) "character varying(255)" + elsif current_adapter?(:OracleAdapter) + 'VARCHAR2(255)' else 'varchar(255)' end @@ -1420,6 +1447,8 @@ def string_column def integer_column if current_adapter?(:MysqlAdapter) 'int(11)' + elsif current_adapter?(:OracleAdapter) + 'NUMBER(38)' else 'integer' end From 04e6bc1134c7165d455106767c5caabb5993e52b Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:19:27 +0200 Subject: [PATCH 13/22] Oracle adapter recourns count() as numeric (not string) --- activerecord/test/cases/query_cache_test.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index f90a66d1dc7df..2af6a56b6a7f7 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -50,7 +50,12 @@ def test_cache_is_flat def test_cache_does_not_wrap_string_results_in_arrays Task.cache do - assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") + # Oracle adapter returns count() as Fixnum or Float + if current_adapter?(:OracleAdapter) + assert Task.connection.select_value("SELECT count(*) AS count_all FROM tasks").is_a?(Numeric) + else + assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") + end end end end From 01a4e07c3625fc2985ca7f2cce40c9d34b1728f8 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:20:42 +0200 Subject: [PATCH 14/22] Oracle can store integers with any :limit --- activerecord/test/cases/schema_dumper_test.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 9612b0beb6a5d..bf9446a47426c 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -114,6 +114,11 @@ def test_schema_dump_includes_limit_constraint_for_integer_columns assert_match %r{c_int_6.*:limit => 6}, output assert_match %r{c_int_7.*:limit => 7}, output assert_match %r{c_int_8.*:limit => 8}, output + elsif current_adapter?(:OracleAdapter) + assert_match %r{c_int_5.*:limit => 5}, output + assert_match %r{c_int_6.*:limit => 6}, output + assert_match %r{c_int_7.*:limit => 7}, output + assert_match %r{c_int_8.*:limit => 8}, output else assert_match %r{c_int_5.*:limit => 8}, output assert_match %r{c_int_6.*:limit => 8}, output From 090ec47bec21261ea867fbca686bba132f01834d Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:25:58 +0200 Subject: [PATCH 15/22] added Subject#after_initialize to be the same as Topic#after_initialize --- activerecord/test/models/subject.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/activerecord/test/models/subject.rb b/activerecord/test/models/subject.rb index 3502943f3a31f..1b9d8107f8a13 100644 --- a/activerecord/test/models/subject.rb +++ b/activerecord/test/models/subject.rb @@ -1,4 +1,12 @@ -# used for OracleSynonymTest, see test/synonym_test_oci.rb +# used for OracleSynonymTest, see test/synonym_test_oracle.rb # class Subject < ActiveRecord::Base + protected + # added initialization of author_email_address in the same way as in Topic class + # as otherwise synonym test was failing + def after_initialize + if self.new_record? + self.author_email_address = 'test@test.com' + end + end end From 8f34c966141bbbd0bd8da83e8ce7d8fa322bcc91 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 23 Mar 2009 00:27:48 +0200 Subject: [PATCH 16/22] support for assert_queries when using Oracle adapter initialize $KCODE to UTF8 when JRuby is used --- .../connections/native_oracle/connection.rb | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/activerecord/test/connections/native_oracle/connection.rb b/activerecord/test/connections/native_oracle/connection.rb index 1be4e23b84dbf..01d86aba93c51 100644 --- a/activerecord/test/connections/native_oracle/connection.rb +++ b/activerecord/test/connections/native_oracle/connection.rb @@ -1,8 +1,8 @@ # gem "rsim-activerecord-oracle_enhanced-adapter" -# gem "activerecord-oracle_enhanced-adapter" +gem "activerecord-oracle_enhanced-adapter", ">=1.2.0" # uses local copy of oracle_enhanced adapter -$:.unshift("../../oracle-enhanced/lib") -require 'active_record/connection_adapters/oracle_enhanced_adapter' +# $:.unshift("../../oracle-enhanced/lib") +# require 'active_record/connection_adapters/oracle_enhanced_adapter' print "Using Oracle\n" require_dependency 'models/course' @@ -13,7 +13,7 @@ ActiveRecord::Base.logger = Logger.new("debug.log") # Set these to your database connection strings -db = ENV['ARUNIT_DB'] || 'XE' +db = ENV['ARUNIT_DB_NAME'] = 'XE' ActiveRecord::Base.configurations = { 'arunit' => { @@ -36,3 +36,19 @@ ActiveRecord::Base.establish_connection 'arunit' Course.establish_connection 'arunit2' + +# for assert_queries test helper +ActiveRecord::Base.connection.class.class_eval do + IGNORED_SELECT_SQL = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^\s*select .* from all_tab_columns/im] + + def select_with_query_record(sql, name = nil, return_column_names = false) + $queries_executed ||= [] + $queries_executed << sql unless IGNORED_SELECT_SQL.any? { |r| sql =~ r } + select_without_query_record(sql, name, return_column_names) + end + + alias_method_chain :select, :query_record +end + +# For JRuby Set default $KCODE to UTF8 +$KCODE = "UTF8" if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' From 8afab34a7699abe5c4eed552815276df01510370 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sun, 12 Apr 2009 20:11:40 +0300 Subject: [PATCH 17/22] always sort lists by id before comparison to avoid errors because of different sorting of same results (on Oracle database) --- activerecord/test/cases/named_scope_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index f4fdc9a39d3fc..2a729f06784c0 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -154,7 +154,8 @@ def test_named_scopes_honor_current_scopes_from_when_defined assert !authors(:david).posts.ranked_by_comments.limit(5).empty? assert_not_equal Post.ranked_by_comments.limit(5), authors(:david).posts.ranked_by_comments.limit(5) assert_not_equal Post.top(5), authors(:david).posts.top(5) - assert_equal authors(:david).posts.ranked_by_comments.limit(5), authors(:david).posts.top(5) + # Oracle sometimes sorts differently if WHERE condition is changed + assert_equal authors(:david).posts.ranked_by_comments.limit(5).sort_by(&:id), authors(:david).posts.top(5).sort_by(&:id) assert_equal Post.ranked_by_comments.limit(5), Post.top(5) end From 94e761551b884604b01b43de3da2c873715e9b4b Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sat, 2 May 2009 20:11:19 +0300 Subject: [PATCH 18/22] changed default connection to localhost orcl database --- activerecord/test/connections/native_oracle/connection.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/test/connections/native_oracle/connection.rb b/activerecord/test/connections/native_oracle/connection.rb index 01d86aba93c51..23e9f8f9c6288 100644 --- a/activerecord/test/connections/native_oracle/connection.rb +++ b/activerecord/test/connections/native_oracle/connection.rb @@ -13,13 +13,13 @@ ActiveRecord::Base.logger = Logger.new("debug.log") # Set these to your database connection strings -db = ENV['ARUNIT_DB_NAME'] = 'XE' +db = ENV['ARUNIT_DB_NAME'] = 'orcl' ActiveRecord::Base.configurations = { 'arunit' => { :adapter => 'oracle_enhanced', :database => db, - :host => "arunit", # used just by JRuby to construct JDBC connect string + :host => "localhost", # used just by JRuby to construct JDBC connect string :username => 'arunit', :password => 'arunit', :emulate_oracle_adapter => true @@ -27,7 +27,7 @@ 'arunit2' => { :adapter => 'oracle_enhanced', :database => db, - :host => "arunit", # used just by JRuby to construct JDBC connect string + :host => "localhost", # used just by JRuby to construct JDBC connect string :username => 'arunit2', :password => 'arunit2', :emulate_oracle_adapter => true From 9b2309c4a8a8c8ad46658c170ccfdb828b30c443 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Fri, 5 Jun 2009 18:43:11 +0300 Subject: [PATCH 19/22] fix schema_dumper_test for Oracle as it supports precision up to 38 --- activerecord/test/cases/schema_dumper_test.rb | 7 ++++++- activerecord/test/schema/schema.rb | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index bf9446a47426c..4f8e20b3ba23a 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -198,6 +198,11 @@ def test_schema_dump_includes_decimal_options def test_schema_dump_keeps_large_precision_integer_columns_as_decimal output = standard_dump - assert_match %r{t.decimal\s+"atoms_in_universe",\s+:precision => 55,\s+:scale => 0}, output + # Oracle supports precision up to 38 and it identifies decimals with scale 0 as integers + if current_adapter?(:OracleAdapter) + assert_match %r{t.integer\s+"atoms_in_universe",\s+:precision => 38,\s+:scale => 0}, output + else + assert_match %r{t.decimal\s+"atoms_in_universe",\s+:precision => 55,\s+:scale => 0}, output + end end end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 5752d6fa40017..5f60d5e13745a 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -285,7 +285,12 @@ def create_table(*args, &block) t.decimal :my_house_population, :precision => 2, :scale => 0 t.decimal :decimal_number_with_default, :precision => 3, :scale => 2, :default => 2.78 t.float :temperature - t.decimal :atoms_in_universe, :precision => 55, :scale => 0 + # Oracle supports precision up to 38 + if current_adapter?(:OracleAdapter) + t.decimal :atoms_in_universe, :precision => 38, :scale => 0 + else + t.decimal :atoms_in_universe, :precision => 55, :scale => 0 + end end create_table :orders, :force => true do |t| From 44a7ef85eba5491aaef5a890ef2b44b111888d35 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Fri, 5 Jun 2009 18:45:09 +0300 Subject: [PATCH 20/22] modifications to Oracle connection.rb setup --- .../connections/native_oracle/connection.rb | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/activerecord/test/connections/native_oracle/connection.rb b/activerecord/test/connections/native_oracle/connection.rb index 23e9f8f9c6288..c8183dc0fb7ed 100644 --- a/activerecord/test/connections/native_oracle/connection.rb +++ b/activerecord/test/connections/native_oracle/connection.rb @@ -1,8 +1,13 @@ # gem "rsim-activerecord-oracle_enhanced-adapter" -gem "activerecord-oracle_enhanced-adapter", ">=1.2.0" +# gem "activerecord-oracle_enhanced-adapter", ">=1.2.1" # uses local copy of oracle_enhanced adapter -# $:.unshift("../../oracle-enhanced/lib") -# require 'active_record/connection_adapters/oracle_enhanced_adapter' +$:.unshift("../../oracle-enhanced/lib") +require 'active_record/connection_adapters/oracle_enhanced_adapter' +# gem "activerecord-jdbc-adapter" +# require 'active_record/connection_adapters/jdbc_adapter' + +# otherwise failed with silence_warnings method missing exception +require 'active_support/core_ext/kernel/reporting' print "Using Oracle\n" require_dependency 'models/course' @@ -20,6 +25,9 @@ :adapter => 'oracle_enhanced', :database => db, :host => "localhost", # used just by JRuby to construct JDBC connect string + # :adapter => "jdbc", + # :driver => "oracle.jdbc.driver.OracleDriver", + # :url => "jdbc:oracle:thin:@localhost:1521:#{db}", :username => 'arunit', :password => 'arunit', :emulate_oracle_adapter => true @@ -28,6 +36,9 @@ :adapter => 'oracle_enhanced', :database => db, :host => "localhost", # used just by JRuby to construct JDBC connect string + # :adapter => "jdbc", + # :driver => "oracle.jdbc.driver.OracleDriver", + # :url => "jdbc:oracle:thin:@localhost:1521:#{db}", :username => 'arunit2', :password => 'arunit2', :emulate_oracle_adapter => true @@ -37,6 +48,9 @@ ActiveRecord::Base.establish_connection 'arunit' Course.establish_connection 'arunit2' +# ActiveRecord::Base.connection.execute %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'} +# ActiveRecord::Base.connection.execute %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'} rescue nil + # for assert_queries test helper ActiveRecord::Base.connection.class.class_eval do IGNORED_SELECT_SQL = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^\s*select .* from all_tab_columns/im] From 53be10c5e6939c9093c4ae863fd380a6dbf1e50e Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Thu, 23 Jul 2009 20:02:04 +0300 Subject: [PATCH 21/22] fixed test_foreign_key_violations_are_translated_to_specific_exception to work with Oracle --- activerecord/test/cases/adapter_test.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 65c5fc2fe943a..88136597e3f45 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -132,7 +132,13 @@ def test_uniqueness_violations_are_translated_to_specific_exception def test_foreign_key_violations_are_translated_to_specific_exception unless @connection.adapter_name == 'SQLite' assert_raises(ActiveRecord::InvalidForeignKey) do - @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)" + # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method + if @connection.prefetch_primary_key? + id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id")) + @connection.execute "INSERT INTO fk_test_has_fk (id, fk_id) VALUES (#{id_value},0)" + else + @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)" + end end end end From 5f0c425e8d106df4cdf844ac4859fc373f9c43e1 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 3 Aug 2009 14:13:03 +0300 Subject: [PATCH 22/22] Some databases (e.g. Oracle) does not allow "AS" between table name and table alias name, for others it is optional --- activerecord/test/cases/finder_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 893fc34c36f06..7f3be1fa6758e 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -1027,7 +1027,7 @@ def test_find_all_with_join def test_joins_dont_clobber_id first = Firm.find( :first, - :joins => 'INNER JOIN companies AS clients ON clients.firm_id = companies.id', + :joins => 'INNER JOIN companies clients ON clients.firm_id = companies.id', :conditions => 'companies.id = 1' ) assert_equal 1, first.id