ruby-plsql 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,302 @@
1
+ module PLSQL
2
+ class JDBCConnection < Connection
3
+ def logoff
4
+ raw_connection.close
5
+ true
6
+ rescue
7
+ false
8
+ end
9
+
10
+ def commit
11
+ raw_connection.commit
12
+ end
13
+
14
+ def rollback
15
+ raw_connection.rollback
16
+ end
17
+
18
+ def autocommit?
19
+ raw_connection.getAutoCommit
20
+ end
21
+
22
+ def autocommit=(value)
23
+ raw_connection.setAutoCommit(value)
24
+ end
25
+
26
+ def select_first(sql, *bindvars)
27
+ stmt = prepare_statement(sql, *bindvars)
28
+ rset = stmt.executeQuery
29
+ metadata = rset.getMetaData
30
+ column_count = metadata.getColumnCount
31
+ if rset.next
32
+ (1..column_count).map do |i|
33
+ get_ruby_value_from_result_set(rset,i,metadata.getColumnTypeName(i))
34
+ end
35
+ else
36
+ nil
37
+ end
38
+ ensure
39
+ rset.close rescue nil
40
+ stmt.close rescue nil
41
+ end
42
+
43
+ def select_all(sql, *bindvars, &block)
44
+ stmt = prepare_statement(sql, *bindvars)
45
+ results = []
46
+ row_count = 0
47
+ rset = stmt.executeQuery
48
+ metadata = rset.getMetaData
49
+ column_count = metadata.getColumnCount
50
+ while rset.next
51
+ row_with_typecast = (1..column_count).map do |i|
52
+ get_ruby_value_from_result_set(rset,i,metadata.getColumnTypeName(i))
53
+ end
54
+ if block_given?
55
+ yield(row_with_typecast)
56
+ row_count += 1
57
+ else
58
+ results << row_with_typecast
59
+ end
60
+ end
61
+ block_given? ? row_count : results
62
+ ensure
63
+ rset.close rescue nil
64
+ stmt.close rescue nil
65
+ end
66
+
67
+ def exec(sql, *bindvars)
68
+ cs = prepare_call(sql, *bindvars)
69
+ cs.execute
70
+ true
71
+ ensure
72
+ cs.close rescue nil
73
+ end
74
+
75
+ class Cursor
76
+
77
+ def initialize(sql, conn)
78
+ @sql = sql
79
+ @connection = conn
80
+ @params = sql.scan(/\:\w+/)
81
+ @out_types = {}
82
+ @out_index = {}
83
+ @statement = @connection.prepare_call(sql)
84
+ end
85
+
86
+ def bind_param(key, value, type=nil, length=nil, in_out='IN')
87
+ @connection.set_bind_variable(@statement, key, value, type, length)
88
+ if in_out =~ /OUT/
89
+ @out_types[key] = type || value.class
90
+ @out_index[key] = bind_param_index(key)
91
+ @statement.registerOutParameter(@out_index[key],@connection.get_java_sql_type(value,type))
92
+ end
93
+ end
94
+
95
+ def exec
96
+ @statement.execute
97
+ end
98
+
99
+ def [](key)
100
+ @connection.get_bind_variable(@statement, @out_index[key], @out_types[key])
101
+ end
102
+
103
+ def close
104
+ @statement.close
105
+ end
106
+
107
+ private
108
+
109
+ def bind_param_index(key)
110
+ return key if key.kind_of? Integer
111
+ key = ":#{key.to_s}" unless key.to_s =~ /^:/
112
+ @params.index(key)+1
113
+ end
114
+ end
115
+
116
+ def parse(sql)
117
+ Cursor.new(sql, self)
118
+ end
119
+
120
+ def prepare_statement(sql, *bindvars)
121
+ stmt = raw_connection.prepareStatement(sql)
122
+ bindvars.each_with_index do |bv, i|
123
+ set_bind_variable(stmt, i+1, bv)
124
+ end
125
+ stmt
126
+ end
127
+
128
+ def prepare_call(sql, *bindvars)
129
+ stmt = raw_connection.prepareCall(sql)
130
+ bindvars.each_with_index do |bv, i|
131
+ set_bind_variable(stmt, i+1, bv)
132
+ end
133
+ stmt
134
+ end
135
+
136
+ def get_java_sql_type(value, type)
137
+ case type ? type.to_s : value.class.to_s
138
+ when 'Fixnum', 'Bignum', 'Integer'
139
+ java.sql.Types::INTEGER
140
+ when 'Float'
141
+ java.sql.Types::FLOAT
142
+ when 'BigDecimal'
143
+ java.sql.Types::NUMERIC
144
+ when 'String'
145
+ java.sql.Types::VARCHAR
146
+ when 'Java::OracleSql::CLOB'
147
+ Java::oracle.jdbc.OracleTypes::CLOB
148
+ when 'Date'
149
+ java.sql.Types::DATE
150
+ when 'Time'
151
+ java.sql.Types::DATE
152
+ when 'DateTime'
153
+ java.sql.Types::DATE
154
+ else
155
+ java.sql.Types::VARCHAR
156
+ end
157
+ end
158
+
159
+ def set_bind_variable(stmt, i, value, type=nil, length=nil)
160
+ key = i.kind_of?(Integer) ? nil : i.to_s.gsub(':','')
161
+ case !value.nil? && type ? type.to_s : value.class.to_s
162
+ when 'Fixnum', 'Bignum', 'Integer'
163
+ stmt.send("setInt#{key && "AtName"}", key || i, value)
164
+ when 'Float'
165
+ stmt.send("setFloat#{key && "AtName"}", key || i, value)
166
+ when 'BigDecimal'
167
+ stmt.send("setBigDecimal#{key && "AtName"}", key || i, java.math.BigDecimal.new(value.to_s))
168
+ when 'String'
169
+ stmt.send("setString#{key && "AtName"}", key || i, value)
170
+ when 'Java::OracleSql::CLOB'
171
+ stmt.send("setClob#{key && "AtName"}", key || i, value)
172
+ when 'Date'
173
+ stmt.send("setDate#{key && "AtName"}", key || i, java.sql.Date.new(Time.parse(value.to_s).to_i*1000))
174
+ when 'Time'
175
+ stmt.send("setTime#{key && "AtName"}", key || i, java.sql.Time.new(value.to_i*1000))
176
+ when 'DateTime'
177
+ stmt.send("setTime#{key && "AtName"}", key || i, java.sql.Time.new(Time.parse(value.strftime("%c")).to_i*1000))
178
+ when 'NilClass'
179
+ stmt.send("setNull#{key && "AtName"}", key || i, get_java_sql_type(value, type))
180
+ end
181
+ end
182
+
183
+ def get_bind_variable(stmt, i, type)
184
+ case type.to_s
185
+ when 'Fixnum', 'Bignum', 'Integer'
186
+ stmt.getInt(i)
187
+ when 'Float'
188
+ stmt.getFloat(i)
189
+ when 'BigDecimal'
190
+ bd = stmt.getBigDecimal(i)
191
+ bd && BigDecimal.new(bd.to_s)
192
+ when 'String'
193
+ stmt.getString(i)
194
+ when 'Java::OracleSql::CLOB'
195
+ stmt.getClob(i)
196
+ when 'Date','Time','DateTime'
197
+ ts = stmt.getTimestamp(i)
198
+ # ts && Time.parse(Time.at(ts.getTime/1000).iso8601)
199
+ ts && Time.local(1900+ts.year, ts.month+1, ts.date, ts.hours, ts.minutes, ts.seconds)
200
+ end
201
+ end
202
+
203
+ def get_ruby_value_from_result_set(rset, i, type_name)
204
+ case type_name
205
+ when "CHAR", "VARCHAR2"
206
+ rset.getString(i)
207
+ when "CLOB"
208
+ ora_value_to_ruby_value(rset.getClob(i))
209
+ when "NUMBER"
210
+ d = rset.getBigDecimal(i)
211
+ if d.nil?
212
+ nil
213
+ elsif d.scale == 0
214
+ d.longValue
215
+ else
216
+ d.doubleValue
217
+ end
218
+ when "DATE", "TIMESTAMP"
219
+ Time.at(rset.getTimestamp(i).getTime/1000)
220
+ else
221
+ nil
222
+ end
223
+ end
224
+
225
+ def plsql_to_ruby_data_type(data_type, data_length)
226
+ case data_type
227
+ when "VARCHAR2"
228
+ [String, data_length || 4000]
229
+ when "CLOB"
230
+ [Java::OracleSql::CLOB, nil]
231
+ when "NUMBER"
232
+ [BigDecimal, nil]
233
+ when "DATE"
234
+ [Time, nil]
235
+ when "TIMESTAMP"
236
+ [Time, nil]
237
+ # CLOB
238
+ # BLOB
239
+ else
240
+ [String, 4000]
241
+ end
242
+ end
243
+
244
+ def ruby_value_to_ora_value(val, type)
245
+ if type == BigDecimal
246
+ val.nil? || val.is_a?(Fixnum) ? val : val.to_f
247
+ elsif type == Time
248
+ date_to_time(val)
249
+ elsif type == Java::OracleSql::CLOB
250
+ if val
251
+ clob = Java::OracleSql::CLOB.createTemporary(raw_connection, false, Java::OracleSql::CLOB::DURATION_SESSION)
252
+ clob.setString(1,val)
253
+ clob
254
+ else
255
+ Java::OracleSql::CLOB.getEmptyCLOB
256
+ end
257
+ else
258
+ val
259
+ end
260
+ end
261
+
262
+ def ora_value_to_ruby_value(val)
263
+ case val
264
+ when Float, BigDecimal
265
+ ora_number_to_ruby_number(val)
266
+ # when OraDate
267
+ # ora_date_to_ruby_date(val)
268
+ when Java::OracleSql::CLOB
269
+ if val.isEmptyLob
270
+ nil
271
+ else
272
+ val.getSubString(1, val.length)
273
+ end
274
+ else
275
+ val
276
+ end
277
+ end
278
+
279
+ private
280
+
281
+ def ora_number_to_ruby_number(num)
282
+ num.to_i == num.to_f ? num.to_i : num.to_f
283
+ end
284
+
285
+ # def ora_date_to_ruby_date(val)
286
+ # val.to_time
287
+ # end
288
+
289
+ def date_to_time(val)
290
+ case val
291
+ when Time
292
+ val
293
+ when DateTime
294
+ Time.parse(val.strftime("%c"))
295
+ when Date
296
+ Time.parse(val.strftime("%c"))
297
+ end
298
+ end
299
+
300
+ end
301
+
302
+ end
@@ -0,0 +1,165 @@
1
+ module PLSQL
2
+ class OCIConnection < Connection
3
+
4
+ def logoff
5
+ raw_connection.logoff
6
+ end
7
+
8
+ def commit
9
+ raw_connection.commit
10
+ end
11
+
12
+ def rollback
13
+ raw_connection.rollback
14
+ end
15
+
16
+ def autocommit?
17
+ raw_connection.autocommit?
18
+ end
19
+
20
+ def autocommit=(value)
21
+ raw_connection.autocommit = value
22
+ end
23
+
24
+ def select_first(sql, *bindvars)
25
+ cursor = raw_connection.exec(sql, *bindvars)
26
+ result = cursor.fetch
27
+ if result
28
+ result.map { |val| ora_value_to_ruby_value(val) }
29
+ else
30
+ nil
31
+ end
32
+ ensure
33
+ cursor.close rescue nil
34
+ end
35
+
36
+ def select_all(sql, *bindvars, &block)
37
+ cursor = raw_connection.exec(sql, *bindvars)
38
+ results = []
39
+ row_count = 0
40
+ while row = cursor.fetch
41
+ row_with_typecast = row.map {|val| ora_value_to_ruby_value(val) }
42
+ if block_given?
43
+ yield(row_with_typecast)
44
+ row_count += 1
45
+ else
46
+ results << row_with_typecast
47
+ end
48
+ end
49
+ block_given? ? row_count : results
50
+ ensure
51
+ cursor.close rescue nil
52
+ end
53
+
54
+ def exec(sql, *bindvars)
55
+ raw_connection.exec(sql, *bindvars)
56
+ true
57
+ end
58
+
59
+ class Cursor
60
+ attr_accessor :raw_cursor
61
+
62
+ def initialize(raw_cur)
63
+ @raw_cursor = raw_cur
64
+ end
65
+
66
+ def bind_param(key, value, type=nil, length=nil, in_out='IN')
67
+ raw_cursor.bind_param(key, value, type, length)
68
+ end
69
+
70
+ def exec(*bindvars)
71
+ raw_cursor.exec(*bindvars)
72
+ end
73
+
74
+ def [](key)
75
+ raw_cursor[key]
76
+ end
77
+
78
+ def close
79
+ raw_cursor.close
80
+ end
81
+ end
82
+
83
+ def parse(sql)
84
+ Cursor.new(raw_connection.parse(sql))
85
+ end
86
+
87
+
88
+ def plsql_to_ruby_data_type(data_type, data_length)
89
+ case data_type
90
+ when "VARCHAR2"
91
+ [String, data_length || 4000]
92
+ when "CLOB"
93
+ [OCI8::CLOB, nil]
94
+ when "NUMBER"
95
+ [OraNumber, nil]
96
+ when "DATE"
97
+ [DateTime, nil]
98
+ when "TIMESTAMP"
99
+ [Time, nil]
100
+ # CLOB
101
+ # BLOB
102
+ else
103
+ [String, 4000]
104
+ end
105
+ end
106
+
107
+ def ruby_value_to_ora_value(val, type)
108
+ if type == OraNumber
109
+ val.nil? || val.is_a?(Fixnum) ? val : val.to_f
110
+ elsif type == DateTime
111
+ val ? val.to_datetime : nil
112
+ elsif type == OCI8::CLOB
113
+ # ruby-oci8 cannot create CLOB from ''
114
+ val = nil if val == ''
115
+ OCI8::CLOB.new(raw_oci_connection, val)
116
+ else
117
+ val
118
+ end
119
+ end
120
+
121
+ def ora_value_to_ruby_value(val)
122
+ case val
123
+ when Float, OraNumber
124
+ ora_number_to_ruby_number(val)
125
+ when DateTime, OraDate
126
+ ora_date_to_ruby_date(val)
127
+ when OCI8::CLOB
128
+ val.rewind
129
+ val.read
130
+ else
131
+ val
132
+ end
133
+ end
134
+
135
+
136
+ private
137
+
138
+ def raw_oci_connection
139
+ if raw_connection.is_a? OCI8
140
+ raw_connection
141
+ # ActiveRecord Oracle enhanced adapter puts OCI8EnhancedAutoRecover wrapper around OCI8
142
+ # in this case we need to pass original OCI8 connection
143
+ else
144
+ raw_connection.instance_variable_get(:@connection)
145
+ end
146
+ end
147
+
148
+ def ora_number_to_ruby_number(num)
149
+ num.to_i == num.to_f ? num.to_i : num.to_f
150
+ end
151
+
152
+ def ora_date_to_ruby_date(val)
153
+ case val
154
+ when DateTime
155
+ Time.parse(val.strftime("%c")) rescue val
156
+ when OraDate
157
+ val.to_time rescue val.to_datetime
158
+ else
159
+ val
160
+ end
161
+ end
162
+
163
+ end
164
+
165
+ end