Skip to content

Commit dc42c57

Browse files
committed
support LOB equality
1 parent f2561f7 commit dc42c57

File tree

4 files changed

+60
-1
lines changed

4 files changed

+60
-1
lines changed

lib/arel/visitors/oracle_common.rb

+29
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@ module Arel # :nodoc: all
44
module Visitors
55
module OracleCommon
66
private
7+
# Oracle can't compare CLOB columns with standard SQL operators for comparison.
8+
# We need to replace standard equality for text/binary columns to use DBMS_LOB.COMPARE function.
9+
# Fixes ORA-00932: inconsistent datatypes: expected - got CLOB
10+
def visit_Arel_Nodes_Equality(o, collector)
11+
left = o.left
12+
return super unless %i(text binary).include?(cached_column_for(left)&.type)
13+
14+
# https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lob.htm#i1016668
15+
# returns 0 when the comparison succeeds
16+
comparator = Arel::Nodes::NamedFunction.new("DBMS_LOB.COMPARE", [left, o.right])
17+
collector = visit comparator, collector
18+
collector << " = 0"
19+
collector
20+
end
21+
722
def visit_Arel_Nodes_Matches(o, collector)
823
if !o.case_sensitive && o.left && o.right
924
o.left = Arel::Nodes::NamedFunction.new("UPPER", [o.left])
@@ -12,6 +27,20 @@ def visit_Arel_Nodes_Matches(o, collector)
1227

1328
super o, collector
1429
end
30+
31+
def cached_column_for(attr)
32+
return unless Arel::Attributes::Attribute === attr
33+
34+
table = attr.relation.table_name
35+
return unless schema_cache.columns_hash?(table)
36+
37+
column = attr.name.to_s
38+
schema_cache.columns_hash(table)[column]
39+
end
40+
41+
def schema_cache
42+
@connection.schema_cache
43+
end
1544
end
1645
end
1746
end

spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ class Group < ActiveRecord::Base
648648
expect(@logger.logged(:debug).last).to match(/\["table_name", "TEST_POSTS"\]/)
649649
end
650650

651-
it "should not raise missing IN/OUT parameter like issue 1687 " do
651+
it "should not raise missing IN/OUT parameter like issue 1678 " do
652652
# "to_sql" enforces unprepared_statement including dictionary access SQLs
653653
expect { User.joins(:group).to_sql }.not_to raise_exception
654654
end

spec/active_record/oracle_enhanced/type/raw_spec.rb

+15
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,19 @@ class ::TestEmployee < ActiveRecord::Base
119119
@employee.reload
120120
expect(@employee.binary_data).to eq(@binary_data)
121121
end
122+
123+
it "should allow equality on select" do
124+
TestEmployee.delete_all
125+
TestEmployee.create!(
126+
first_name: "First",
127+
last_name: "Last",
128+
binary_data: @binary_data,
129+
)
130+
TestEmployee.create!(
131+
first_name: "First1",
132+
last_name: "Last1",
133+
binary_data: @binary_data2,
134+
)
135+
expect(TestEmployee.where(binary_data: @binary_data)).to have_attributes(count: 1)
136+
end
122137
end

spec/active_record/oracle_enhanced/type/text_spec.rb

+15
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,19 @@ class ::TestSerializeEmployee < ActiveRecord::Base
226226
@employee.reload
227227
expect(@employee.comments).to eq(length: { is: 2 })
228228
end
229+
230+
it "should allow equality on select" do
231+
search_data = "text search CLOB"
232+
Test2Employee.create!(
233+
first_name: "First",
234+
last_name: "Last",
235+
comments: search_data,
236+
)
237+
Test2Employee.create!(
238+
first_name: "First1",
239+
last_name: "Last1",
240+
comments: "other data",
241+
)
242+
expect(Test2Employee.where(comments: search_data)).to have_attributes(count: 1)
243+
end
229244
end

0 commit comments

Comments
 (0)