File: db2.rb

package info (click to toggle)
libsequel-core-ruby 1.5.1-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 648 kB
  • ctags: 840
  • sloc: ruby: 10,949; makefile: 36
file content (158 lines) | stat: -rw-r--r-- 4,119 bytes parent folder | download
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
require 'db2/db2cli'

module Sequel
  module DB2
    class Database < Sequel::Database
      set_adapter_scheme :db2
      include DB2CLI
      
      # AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
      # 
      # def auto_increment_sql
      #   AUTO_INCREMENT
      # end
      
      def check_error(rc, msg)
        case rc
        when SQL_SUCCESS, SQL_SUCCESS_WITH_INFO
          nil
        else
          raise Error, msg
        end
      end
      
      rc, @@env = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE)
      check_error(rc, "Could not allocate DB2 environment")

      def connect
        rc, dbc = SQLAllocHandle(SQL_HANDLE_DBC, @@env) 
        check_error(rc, "Could not allocate database connection")
        
        rc = SQLConnect(dbc, @opts[:database], @opts[:user], @opts[:password]) 
        check_error(rc, "Could not connect to database")
        
        dbc
      end
      
      def disconnect
        @pool.disconnect do |conn|
          rc = SQLDisconnect(conn)
          check_error(rc, "Could not disconnect from database")

          rc = SQLFreeHandle(SQL_HANDLE_DBC, conn)
          check_error(rc, "Could not free Database handle")
        end
      end
    
      def test_connection
        @pool.hold {|conn|}
        true
      end

      def dataset(opts = nil)
        DB2::Dataset.new(self, opts)
      end
      
      def execute(sql, &block)
        @logger.info(sql) if @logger
        @pool.hold do |conn|
          rc, sth = SQLAllocHandle(SQL_HANDLE_STMT, @handle) 
          check_error(rc, "Could not allocate statement")

          begin
            rc = SQLExecDirect(sth, sql) 
            check_error(rc, "Could not execute statement")
            
            block[sth] if block

            rc, rpc = SQLRowCount(sth)
            check_error(rc, "Could not get RPC") 
            rpc
          ensure
            rc = SQLFreeHandle(SQL_HANDLE_STMT, sth)
            check_error(rc, "Could not free statement")
          end
        end
      end
      alias_method :do, :execute
    end
    
    class Dataset < Sequel::Dataset
      def literal(v)
        case v
        when Time
          literal(v.iso8601)
        else
          super
        end
      end

      def fetch_rows(sql, &block)
        @db.synchronize do
          @db.execute(sql) do |sth|
            @column_info = get_column_info(sth)
            @columns = @column_info.map {|c| c[:name]}
            while (rc = SQLFetch(@handle)) != SQL_NO_DATA_FOUND
              @db.check_error(rc, "Could not fetch row")
              yield hash_row(sth)
            end
          end
        end
        self
      end
      
      MAX_COL_SIZE = 256

      def get_column_info(sth)
        rc, column_count = SQLNumResultCols(sth)
        @db.check_error(rc, "Could not get number of result columns")

        (1..column_count).map do |i| 
          rc, name, buflen, datatype, size, digits, nullable = SQLDescribeCol(sth, i, MAX_COL_SIZE)
          @b.check_error(rc, "Could not describe column")
          
          {:name => name, :db2_type => datatype, :precision => size}
        end 
      end
      
      def hash_row(sth)
        row = {}
        @column_info.each_with_index do |c, i|
          rc, v = SQLGetData(sth, i+1, c[:db2_type], c[:precision]) 
          @db.check_error(rc, "Could not get data")
          
          @row[c[:name]] = convert_type(v)
        end
        row
      end
      
      def convert_type(v)
        case v
        when DB2CLI::Date 
          DBI::Date.new(v.year, v.month, v.day)
        when DB2CLI::Time
          DBI::Time.new(v.hour, v.minute, v.second)
        when DB2CLI::Timestamp 
          DBI::Timestamp.new(v.year, v.month, v.day,
            v.hour, v.minute, v.second, v.fraction)
        when DB2CLI::Null
          nil
        else  
          v
        end
      end
    
      def insert(*values)
        @db.do insert_sql(*values)
      end
    
      def update(*args, &block)
        @db.do update_sql(*args, &block)
      end
    
      def delete(opts = nil)
        @db.do delete_sql(opts)
      end
    end
  end
end