This file is indexed.

/usr/lib/ruby/vendor_ruby/sequel/plugins/prepared_statements_associations.rb is in ruby-sequel 4.15.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
module Sequel
  module Plugins
    # The prepared_statements_associations plugin modifies the regular association
    # load method to use a cached prepared statement to load the associations.
    # It will not work on all associations, but it should skip the use of prepared
    # statements for associations where it will not work, assuming you load the
    # plugin before defining the associations.
    #
    # Usage:
    #
    #   # Make all model subclasses more safe when using prepared statements (called before loading subclasses)
    #   Sequel::Model.plugin :prepared_statements_associations
    #
    #   # Make the Album class more safe when using prepared statements
    #   Album.plugin :prepared_statements_associations
    module PreparedStatementsAssociations
      # Synchronize access to the integer sequence so that no two calls get the same integer.
      MUTEX = Mutex.new

      i = 0
      # This plugin names prepared statements uniquely using an integer sequence, this
      # lambda returns the next integer to use.
      NEXT = lambda{MUTEX.synchronize{i += 1}}

      module InstanceMethods
        private

        # Return a bound variable hash that maps the keys in +ks+ (qualified by the +table+)
        # to the values of the results of sending the methods in +vs+.
        def association_bound_variable_hash(table, ks, vs)
          Hash[*ks.zip(vs).map{|k, v| [:"#{table}.#{k}", send(v)]}.flatten]
        end

        # Given an association reflection, return a bound variable hash for the given
        # association for this instance's values.
        def association_bound_variables(opts)
          case opts[:type]
          when :many_to_one
            association_bound_variable_hash(opts.associated_class.table_name, opts.primary_keys, opts[:keys])
          when :one_to_many, :one_to_one
            association_bound_variable_hash(opts.associated_class.table_name, opts[:keys], opts[:primary_keys])
          when :many_to_many, :one_through_one
            association_bound_variable_hash(opts.join_table_alias, opts[:left_keys], opts[:left_primary_keys])
          when :many_through_many, :one_through_many
            association_bound_variable_hash(opts.final_reverse_edge[:alias], Array(opts[:left_key]), opts[:left_primary_keys])
          end
        end

        # Given an association reflection, return and cache a prepared statement for this association such
        # that, given appropriate bound variables, the prepared statement will work correctly for any
        # instance.  Return false if such a prepared statement cannot be created.
        def association_prepared_statement(opts, assoc_bv)
          opts.send(:cached_fetch, :prepared_statement) do
            unless opts[:instance_specific]
              ds, bv = _associated_dataset(opts, {}).unbind

              f = ds.opts[:from]
              if f && f.length == 1
                s = ds.opts[:select]
                if ds.opts[:join]
                  if opts.eager_loading_use_associated_key? && s && s.length == 1 && s.first.is_a?(SQL::ColumnAll)
                    table = s.first.table
                    ds = ds.select(*opts.associated_class.columns.map{|c| Sequel.identifier(c).qualify(table)})
                  end
                elsif !s || s.empty?
                  ds = ds.select(*opts.associated_class.columns.map{|c| Sequel.identifier(c)})
                end
              end 
          
              if bv.length != assoc_bv.length
                h = {}
                bv.each do |k,v|
                  h[k] = v unless assoc_bv.has_key?(k)
                end
                ds = ds.bind(h)
              end
              ps = ds.prepare(opts.returns_array? ? :select : :first, :"smpsap_#{NEXT.call}")
              ps.log_sql = true
              ps
            end
          end
        end

        # Use a prepared statement if possible to load the associated object,
        # unless a dynamic callback is given.
        def _load_associated_object(opts, dynamic_opts)
          if !dynamic_opts[:callback] && (bv = association_bound_variables(opts)) && (ps ||= association_prepared_statement(opts, bv))
            ps.call(bv)
          else
            super
          end
        end

        # Use a prepared statement if possible to load the associated object,
        # unless the associated model uses caching.
        def _load_associated_object_via_primary_key(opts)
          if !opts.associated_class.respond_to?(:cache_get_pk) && (bv = association_bound_variables(opts)) && (ps ||= association_prepared_statement(opts, bv))
            ps.call(bv)
          else
            super
          end
        end

        # Use a prepared statement if possible to load the associated objects,
        # unless a dynamic callback is given.
        def _load_associated_object_array(opts, dynamic_opts)
          if !dynamic_opts[:callback] && (bv = association_bound_variables(opts)) && (ps ||= association_prepared_statement(opts, bv))
            ps.call(bv)
          else
            super
          end
        end
      end
    end
  end
end