This file is indexed.

/usr/lib/ruby/vendor_ruby/sequel/extensions/pg_interval.rb is in ruby-sequel 4.1.1-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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# The pg_interval extension adds support for PostgreSQL's interval type.
#
# This extension integrates with Sequel's native postgres adapter, so
# that when interval type values are retrieved, they are parsed and returned
# as instances of ActiveSupport::Duration.
#
# In addition to the parser, this extension adds literalizers for
# ActiveSupport::Duration that use the standard Sequel literalization
# callbacks, so they work on all adapters.
#
# If you would like to use interval columns in your model objects, you
# probably want to modify the typecasting so that it
# recognizes and correctly handles the interval columns, which you can
# do by:
#
#   DB.extension :pg_interval
#
# If you are not using the native postgres adapter, you probably
# also want to use the pg_typecast_on_load plugin in the model, and
# set it to typecast the interval type column(s) on load.
#
# This extension integrates with the pg_array extension.  If you plan
# to use arrays of interval types, load the pg_array extension before the
# pg_interval extension:
#
#   DB.extension :pg_array, :pg_interval
#
# The parser this extension uses requires that IntervalStyle for PostgreSQL
# is set to postgres (the default setting).  If IntervalStyle is changed from
# the default setting, the parser will probably not work.  The parser used is
# very simple, and is only designed to parse PostgreSQL's default output
# format, it is not designed to support all input formats that PostgreSQL
# supports.

require 'active_support/duration'
Sequel.require 'adapters/utils/pg_types'

module Sequel
  module Postgres
    module IntervalDatabaseMethods
      EMPTY_INTERVAL = '0'.freeze
      DURATION_UNITS = [:years, :months, :days, :minutes, :seconds].freeze

      # Return an unquoted string version of the duration object suitable for
      # use as a bound variable.
      def self.literal_duration(duration)
        h = Hash.new(0)
        duration.parts.each{|unit, value| h[unit] += value}
        s = ''

        DURATION_UNITS.each do |unit|
          if (v = h[unit]) != 0
            s << "#{v.is_a?(Integer) ? v : sprintf('%0.6f', v)} #{unit} "
          end
        end

        if s.empty?
          EMPTY_INTERVAL
        else
          s
        end
      end

      # Creates callable objects that convert strings into ActiveSupport::Duration instances.
      class Parser
        # Regexp that parses the full range of PostgreSQL interval type output.
        PARSER = /\A([+-]?\d+ years?\s?)?([+-]?\d+ mons?\s?)?([+-]?\d+ days?\s?)?(?:(?:([+-])?(\d\d):(\d\d):(\d\d(\.\d+)?))|([+-]?\d+ hours?\s?)?([+-]?\d+ mins?\s?)?([+-]?\d+(\.\d+)? secs?\s?)?)?\z/o

        # Parse the interval input string into an ActiveSupport::Duration instance.
        def call(string)
          raise(InvalidValue, "invalid or unhandled interval format: #{string.inspect}") unless matches = PARSER.match(string)

          value = 0
          parts = []

          if v = matches[1]
            v = v.to_i
            value += 31557600 * v
            parts << [:years, v]
          end
          if v = matches[2]
            v = v.to_i
            value += 2592000 * v
            parts << [:months, v]
          end
          if v = matches[3]
            v = v.to_i
            value += 86400 * v
            parts << [:days, v]
          end
          if matches[5]
            seconds = matches[5].to_i * 3600 + matches[6].to_i * 60
            seconds += matches[8] ? matches[7].to_f : matches[7].to_i
            seconds *= -1 if matches[4] == '-'
            value += seconds
            parts << [:seconds, seconds]
          elsif matches[9] || matches[10] || matches[11]
            seconds = 0
            if v = matches[9]
              seconds += v.to_i * 3600
            end
            if v = matches[10]
              seconds += v.to_i * 60
            end
            if v = matches[11]
              seconds += matches[12] ? v.to_f : v.to_i
            end
            value += seconds
            parts << [:seconds, seconds]
          end

          ActiveSupport::Duration.new(value, parts)
        end
      end

      # Single instance of Parser used for parsing, to save on memory (since the parser has no state).
      PARSER = Parser.new

      # Reset the conversion procs if using the native postgres adapter,
      # and extend the datasets to correctly literalize ActiveSupport::Duration values.
      def self.extended(db)
        db.instance_eval do
          extend_datasets(IntervalDatasetMethods)
          copy_conversion_procs([1186, 1187])
          @schema_type_classes[:interval] = ActiveSupport::Duration
        end
      end

      # Handle ActiveSupport::Duration values in bound variables.
      def bound_variable_arg(arg, conn)
        case arg
        when ActiveSupport::Duration
          IntervalDatabaseMethods.literal_duration(arg)
        else
          super
        end
      end

      private

      # Handle arrays of interval types in bound variables.
      def bound_variable_array(a)
        case a
        when ActiveSupport::Duration
          "\"#{IntervalDatabaseMethods.literal_duration(a)}\""
        else
          super
        end
      end

      # Typecast value correctly to an ActiveSupport::Duration instance.
      # If already an ActiveSupport::Duration, return it. 
      # If a numeric argument is given, assume it represents a number
      # of seconds, and create a new ActiveSupport::Duration instance
      # representing that number of seconds.
      # If a String, assume it is in PostgreSQL interval output format
      # and attempt to parse it.
      def typecast_value_interval(value)
        case value
        when ActiveSupport::Duration
          value
        when Numeric
          ActiveSupport::Duration.new(value, [[:seconds, value]])
        when String
          PARSER.call(value)
        else
          raise Sequel::InvalidValue, "invalid value for interval type: #{value.inspect}"
        end
      end
    end

    module IntervalDatasetMethods
      CAST_INTERVAL = '::interval'.freeze

      # Handle literalization of ActiveSupport::Duration objects, treating them as
      # PostgreSQL intervals.
      def literal_other_append(sql, v)
        case v
        when ActiveSupport::Duration
          literal_append(sql, IntervalDatabaseMethods.literal_duration(v))
          sql << CAST_INTERVAL
        else
          super
        end
      end
    end

    PG_TYPES[1186] = Postgres::IntervalDatabaseMethods::PARSER
    if defined?(PGArray) && PGArray.respond_to?(:register)
      PGArray.register('interval', :oid=>1187, :scalar_oid=>1186)
    end
  end

  Database.register_extension(:pg_interval, Postgres::IntervalDatabaseMethods)
end