diff --git a/lib/arel/visitors/oracle_common.rb b/lib/arel/visitors/oracle_common.rb index 594ff3a3c..b103f4f9f 100644 --- a/lib/arel/visitors/oracle_common.rb +++ b/lib/arel/visitors/oracle_common.rb @@ -9,11 +9,14 @@ module OracleCommon # Fixes ORA-00932: inconsistent datatypes: expected - got CLOB def visit_Arel_Nodes_Equality(o, collector) left = o.left + right = o.right + + return super if right.nil? return super unless %i(text binary).include?(cached_column_for(left)&.type) # https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lob.htm#i1016668 # returns 0 when the comparison succeeds - comparator = Arel::Nodes::NamedFunction.new("DBMS_LOB.COMPARE", [left, o.right]) + comparator = Arel::Nodes::NamedFunction.new("DBMS_LOB.COMPARE", [left, right]) collector = visit comparator, collector collector << " = 0" collector diff --git a/spec/active_record/oracle_enhanced/type/binary_spec.rb b/spec/active_record/oracle_enhanced/type/binary_spec.rb index 3f1cae8a3..244af7c4b 100644 --- a/spec/active_record/oracle_enhanced/type/binary_spec.rb +++ b/spec/active_record/oracle_enhanced/type/binary_spec.rb @@ -15,6 +15,14 @@ end class ::TestEmployee < ActiveRecord::Base end + class ::TestSerializedEmployee < ActiveRecord::Base + self.table_name = "test_employees" + serialize :binary_data, coder: YAML + end + class ::TestSerializedHashEmployee < ActiveRecord::Base + self.table_name = "test_employees" + serialize :binary_data, type: Hash, coder: YAML + end @binary_data = "\0\1\2\3\4\5\6\7\8\9" * 10000 @binary_data2 = "\1\2\3\4\5\6\7\8\9\0" * 10000 end @@ -22,6 +30,8 @@ class ::TestEmployee < ActiveRecord::Base after(:all) do @conn.drop_table :test_employees, if_exists: true Object.send(:remove_const, "TestEmployee") + Object.send(:remove_const, "TestSerializedEmployee") + Object.send(:remove_const, "TestSerializedHashEmployee") end after(:each) do @@ -116,4 +126,32 @@ class ::TestEmployee < ActiveRecord::Base @employee.reload expect(@employee.binary_data).to eq(@binary_data) end + + it "should find NULL BLOB data when queried with nil" do + TestEmployee.delete_all + TestEmployee.create!(binary_data: nil) + TestEmployee.create!(binary_data: @binary_data) + expect(TestEmployee.where(binary_data: nil)).to have_attributes(count: 1) + end + + it "should find serialized NULL BLOB data when queried with nil" do + TestSerializedEmployee.delete_all + TestSerializedEmployee.create!(binary_data: nil) + TestSerializedEmployee.create!(binary_data: { data: "some data" }) + expect(TestSerializedEmployee.where(binary_data: nil)).to have_attributes(count: 1) + end + + it "should find serialized Hash NULL BLOB data when queried with nil" do + TestSerializedHashEmployee.delete_all + TestSerializedHashEmployee.create!(binary_data: nil) + TestSerializedHashEmployee.create!(binary_data: { data: "some data" }) + expect(TestSerializedHashEmployee.where(binary_data: nil)).to have_attributes(count: 1) + end + + it "should find serialized Hash NULL BLOB data when queried with {}" do + TestSerializedHashEmployee.delete_all + TestSerializedHashEmployee.create!(binary_data: nil) + TestSerializedHashEmployee.create!(binary_data: { data: "some data" }) + expect(TestSerializedHashEmployee.where(binary_data: {})).to have_attributes(count: 1) + end end diff --git a/spec/active_record/oracle_enhanced/type/text_spec.rb b/spec/active_record/oracle_enhanced/type/text_spec.rb index ccffd5e49..d9e2e47f3 100644 --- a/spec/active_record/oracle_enhanced/type/text_spec.rb +++ b/spec/active_record/oracle_enhanced/type/text_spec.rb @@ -31,6 +31,10 @@ class ::TestEmployee < ActiveRecord::Base; end class ::Test2Employee < ActiveRecord::Base serialize :comments end + class ::TestSerializedHashEmployee < ActiveRecord::Base + self.table_name = "test_employees" + serialize :comments, type: Hash, coder: YAML + end class ::TestEmployeeReadOnlyClob < ActiveRecord::Base self.table_name = "test_employees" attr_readonly :comments @@ -47,6 +51,7 @@ class ::TestSerializeEmployee < ActiveRecord::Base @conn.drop_table :test_serialize_employees, if_exists: true Object.send(:remove_const, "TestEmployee") Object.send(:remove_const, "Test2Employee") + Object.send(:remove_const, "TestSerializedHashEmployee") Object.send(:remove_const, "TestEmployeeReadOnlyClob") Object.send(:remove_const, "TestSerializeEmployee") ActiveRecord::Base.clear_cache! @@ -241,4 +246,32 @@ class ::TestSerializeEmployee < ActiveRecord::Base ) expect(Test2Employee.where(comments: search_data)).to have_attributes(count: 1) end + + it "should find NULL CLOB data when queried with nil" do + TestEmployee.delete_all + TestEmployee.create!(comments: nil) + TestEmployee.create!(comments: @char_data) + expect(TestEmployee.where(comments: nil)).to have_attributes(count: 1) + end + + it "should find serialized NULL CLOB data when queried with nil" do + TestSerializeEmployee.delete_all + TestSerializeEmployee.create!(comments: nil) + TestSerializeEmployee.create!(comments: { some: "text" }) + expect(TestSerializeEmployee.where(comments: nil)).to have_attributes(count: 1) + end + + it "should find serialized Hash NULL CLOB data when queried with nil" do + TestSerializedHashEmployee.delete_all + TestSerializedHashEmployee.create!(comments: nil) + TestSerializedHashEmployee.create!(comments: { some: "text" }) + expect(TestSerializedHashEmployee.where(comments: nil)).to have_attributes(count: 1) + end + + it "should find serialized Hash NULL CLOB data when queried with {}" do + TestSerializedHashEmployee.delete_all + TestSerializedHashEmployee.create!(comments: nil) + TestSerializedHashEmployee.create!(comments: { some: "text" }) + expect(TestSerializedHashEmployee.where(comments: {})).to have_attributes(count: 1) + end end