3scale/porta

View on GitHub
lib/arel/visitors/oracle12_hack.rb

Summary

Maintainability
A
55 mins
Test Coverage
# frozen_string_literal: true

module Arel
  module Visitors
    Oracle12.class_eval do
      # we need to strip ORDER from subqueries because Oracle does not support it
      def strip_order_from_select(o)
        case (node = o.right)
        when Arel::Nodes::SelectStatement
          node.orders = []
        end
      end

      def visit_Arel_Nodes_In(o, collector)
        strip_order_from_select(o)

        super
      end

      def visit_Arel_Nodes_NotIn(o, collector)
        strip_order_from_select(o)

        super
      end

      # Another wonderful piece.
      # Oracle can't compare CLOB columns with standard SQL operators for comparison.
      # We need to replace standard equality for text/binary columns to use DBMS_LOB.COMPARE function.
      # Fixes ORA-00932: inconsistent datatypes: expected - got CLOB
      # remove if https://github.com/rsim/oracle-enhanced/issues/2239 is fixed (in Rails 7.0.1)
      def visit_Arel_Nodes_Equality(o, collector)
        case (left = o.left)
        when Arel::Attributes::Attribute
          table = left.relation.table_name
          schema_cache = @connection.schema_cache

          return super unless schema_cache.data_source_exists?(table)

          column = schema_cache.columns_hash(table)[left.name.to_s]

          case column.type
          when :text, :binary
            # 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])
            collector = visit comparator, collector
            collector << ' = 0'
            collector
          else
            super
          end
        else
          super
        end
      end

      # remove when addressed: https://github.com/rsim/oracle-enhanced/pull/2247
      def visit_Arel_Nodes_Matches o, collector
        if !o.case_sensitive && o.left && o.right
          o.left = Arel::Nodes::NamedFunction.new('UPPER', [o.left])
          o.right = Arel::Nodes::NamedFunction.new('UPPER', [o.right])
        end

        super o, collector
      end
    end
  end
end