This file is indexed.

/usr/lib/ruby/vendor_ruby/sequel/adapters/db2.rb is in ruby-sequel 3.33.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
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
require 'db2/db2cli'
Sequel.require %w'shared/db2', 'adapters'

module Sequel
  module DB2

    @convert_smallint_to_bool = true

    # Underlying error raised by Sequel, since ruby-db2 doesn't
    # use exceptions.
    class DB2Error < StandardError
    end

    class << self
      # Whether to convert smallint values to bool, true by default.
      # Can also be overridden per dataset.
      attr_accessor :convert_smallint_to_bool
    end

    tt = Class.new do
      def boolean(s) !s.to_i.zero? end
      def date(s) Date.new(s.year, s.month, s.day) end
      def time(s) Sequel::SQLTime.create(s.hour, s.minute, s.second) end
    end.new

    # Hash holding type translation methods, used by Dataset#fetch_rows.
    DB2_TYPES = {
      :boolean  => tt.method(:boolean),
      DB2CLI::SQL_BLOB => ::Sequel::SQL::Blob.method(:new),
      DB2CLI::SQL_TYPE_DATE => tt.method(:date),
      DB2CLI::SQL_TYPE_TIME => tt.method(:time),
      DB2CLI::SQL_DECIMAL => ::BigDecimal.method(:new)
    }
    DB2_TYPES[DB2CLI::SQL_CLOB] = DB2_TYPES[DB2CLI::SQL_BLOB]

    class Database < Sequel::Database
      include DatabaseMethods

      set_adapter_scheme :db2

      TEMPORARY = 'GLOBAL TEMPORARY '.freeze
      rc, NullHandle = DB2CLI.SQLAllocHandle(DB2CLI::SQL_HANDLE_ENV, DB2CLI::SQL_NULL_HANDLE)
      
      # Hash of connection procs for converting
      attr_reader :conversion_procs

      def initialize(opts={})
        super
        @conversion_procs = DB2_TYPES.dup
        @conversion_procs[DB2CLI::SQL_TYPE_TIMESTAMP] = method(:to_application_timestamp_db2)
      end

      def connect(server)
        opts = server_opts(server)
        dbc = checked_error("Could not allocate database connection"){DB2CLI.SQLAllocHandle(DB2CLI::SQL_HANDLE_DBC, NullHandle)}
        checked_error("Could not connect to database"){DB2CLI.SQLConnect(dbc, opts[:database], opts[:user], opts[:password])}
        dbc
      end
      
      def execute(sql, opts={}, &block)
        synchronize(opts[:server]){|conn| log_connection_execute(conn, sql, &block)}
      end
      alias do execute

      def execute_insert(sql, opts={})
        synchronize(opts[:server]) do |conn|
          log_connection_execute(conn, sql)
          sql = "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1"
          log_connection_execute(conn, sql) do |sth|
            name, buflen, datatype, size, digits, nullable = checked_error("Could not describe column"){DB2CLI.SQLDescribeCol(sth, 1, 256)}
            if DB2CLI.SQLFetch(sth) != DB2CLI::SQL_NO_DATA_FOUND
              v, _ = checked_error("Could not get data"){DB2CLI.SQLGetData(sth, 1, datatype, size)}
              if v.is_a?(String) 
                return v.to_i
              else
                return nil
              end
            end
          end
        end
      end
      
      ERROR_MAP = {}
      %w'SQL_INVALID_HANDLE SQL_STILL_EXECUTING SQL_ERROR'.each do |s|
        ERROR_MAP[DB2CLI.const_get(s)] = s
      end
      def check_error(rc, msg)
        case rc
        when DB2CLI::SQL_SUCCESS, DB2CLI::SQL_SUCCESS_WITH_INFO, DB2CLI::SQL_NO_DATA_FOUND
          nil
        when DB2CLI::SQL_INVALID_HANDLE, DB2CLI::SQL_STILL_EXECUTING
          e = DB2Error.new("#{ERROR_MAP[rc]}: #{msg}")
          e.set_backtrace(caller)
          raise_error(e, :disconnect=>true)
        else
          e = DB2Error.new("#{ERROR_MAP[rc] || "Error code #{rc}"}: #{msg}")
          e.set_backtrace(caller)
          raise_error(e, :disconnect=>true)
        end
      end

      def checked_error(msg)
        rc, *ary= yield
        check_error(rc, msg)
        ary.length <= 1 ? ary.first : ary
      end

      def to_application_timestamp_db2(v)
        to_application_timestamp(v.to_s)
      end

      private

      def begin_transaction(conn, opts={})
        log_yield(TRANSACTION_BEGIN){DB2CLI.SQLSetConnectAttr(conn, DB2CLI::SQL_ATTR_AUTOCOMMIT, DB2CLI::SQL_AUTOCOMMIT_OFF)}
      end

      def remove_transaction(conn, committed)
        DB2CLI.SQLSetConnectAttr(conn, DB2CLI::SQL_ATTR_AUTOCOMMIT, DB2CLI::SQL_AUTOCOMMIT_ON)
      ensure
        super
      end

      def rollback_transaction(conn, opts={})
        log_yield(TRANSACTION_ROLLBACK){DB2CLI.SQLEndTran(DB2CLI::SQL_HANDLE_DBC, conn, DB2CLI::SQL_ROLLBACK)}
      end

      def commit_transaction(conn, opts={})
        log_yield(TRANSACTION_COMMIT){DB2CLI.SQLEndTran(DB2CLI::SQL_HANDLE_DBC, conn, DB2CLI::SQL_COMMIT)}
      end
    
      def log_connection_execute(conn, sql)
        sth = checked_error("Could not allocate statement"){DB2CLI.SQLAllocHandle(DB2CLI::SQL_HANDLE_STMT, conn)}

        begin
          checked_error("Could not execute statement: #{sql}"){log_yield(sql){DB2CLI.SQLExecDirect(sth, sql)}}
          
          if block_given?
            yield(sth)
          else
            checked_error("Could not get RPC"){DB2CLI.SQLRowCount(sth)}
          end
        ensure
          checked_error("Could not free statement"){DB2CLI.SQLFreeHandle(DB2CLI::SQL_HANDLE_STMT, sth)}
        end
      end

      # Convert smallint type to boolean if convert_smallint_to_bool is true
      def schema_column_type(db_type)
        if DB2.convert_smallint_to_bool && db_type =~ /smallint/i 
          :boolean
        else
          super
        end
      end

      def disconnect_connection(conn)
        checked_error("Could not disconnect from database"){DB2CLI.SQLDisconnect(conn)}
        checked_error("Could not free Database handle"){DB2CLI.SQLFreeHandle(DB2CLI::SQL_HANDLE_DBC, conn)}
      end
    end
    
    class Dataset < Sequel::Dataset
      include DatasetMethods

      Database::DatasetClass = self
      MAX_COL_SIZE = 256
      
      # Whether to convert smallint to boolean arguments for this dataset.
      # Defaults to the DB2 module setting.
      def convert_smallint_to_bool
        defined?(@convert_smallint_to_bool) ? @convert_smallint_to_bool : (@convert_smallint_to_bool = DB2.convert_smallint_to_bool)
      end

      # Override the default DB2.convert_smallint_to_bool setting for this dataset.
      attr_writer :convert_smallint_to_bool

      def fetch_rows(sql)
        execute(sql) do |sth|
          offset = @opts[:offset]
          db = @db
          i = 1
          column_info = get_column_info(sth)
          cols = column_info.map{|c| c.at(1)}
          cols.delete(row_number_column) if offset
          @columns = cols
          errors = [DB2CLI::SQL_NO_DATA_FOUND, DB2CLI::SQL_ERROR]
          until errors.include?(rc = DB2CLI.SQLFetch(sth))
            db.check_error(rc, "Could not fetch row")
            row = {}
            column_info.each do |i, c, t, s, pr|
              v, _ = db.checked_error("Could not get data"){DB2CLI.SQLGetData(sth, i, t, s)}
              row[c] = if v == DB2CLI::Null
                nil
              elsif pr
                pr.call(v)
              else
                v
              end
            end
            row.delete(row_number_column) if offset
            yield row
          end
        end
        self
      end
      
      private

      def get_column_info(sth)
        db = @db
        column_count = db.checked_error("Could not get number of result columns"){DB2CLI.SQLNumResultCols(sth)}
        convert = convert_smallint_to_bool
        cps = db.conversion_procs

        (1..column_count).map do |i| 
          name, buflen, datatype, size, digits, nullable = db.checked_error("Could not describe column"){DB2CLI.SQLDescribeCol(sth, i, MAX_COL_SIZE)}
          pr = if datatype == DB2CLI::SQL_SMALLINT && convert && size <= 5 && digits <= 1
            cps[:boolean]
          else
            cps[datatype]
          end
          [i, output_identifier(name), datatype, size, pr]
        end 
      end
    end
  end
end