activerecord-oracle_enhanced-adapter 1.1.9 → 1.2.0
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.
- data/History.txt +11 -0
- data/README.txt +6 -2
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +771 -907
- data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +71 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +64 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +2 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +352 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +346 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +2 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_reserved_words.rb +126 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +200 -97
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +170 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +40 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +11 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +148 -53
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +13 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +27 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +10 -6
- data/spec/spec_helper.rb +51 -6
- metadata +11 -2
@@ -0,0 +1,71 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
# interface independent methods
|
4
|
+
class OracleEnhancedConnection
|
5
|
+
|
6
|
+
def self.create(config)
|
7
|
+
case ORACLE_ENHANCED_CONNECTION
|
8
|
+
when :oci
|
9
|
+
OracleEnhancedOCIConnection.new(config)
|
10
|
+
when :jdbc
|
11
|
+
OracleEnhancedJDBCConnection.new(config)
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :raw_connection
|
18
|
+
|
19
|
+
# Oracle column names by default are case-insensitive, but treated as upcase;
|
20
|
+
# for neatness, we'll downcase within Rails. EXCEPT that folks CAN quote
|
21
|
+
# their column names when creating Oracle tables, which makes then case-sensitive.
|
22
|
+
# I don't know anybody who does this, but we'll handle the theoretical case of a
|
23
|
+
# camelCase column name. I imagine other dbs handle this different, since there's a
|
24
|
+
# unit test that's currently failing test_oci.
|
25
|
+
def oracle_downcase(column_name)
|
26
|
+
column_name =~ /[a-z]/ ? column_name : column_name.downcase
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Returns a record hash with the column names as keys and column values
|
32
|
+
# as values.
|
33
|
+
def select_one(sql)
|
34
|
+
result = select(sql)
|
35
|
+
result.first if result
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a single value from a record
|
39
|
+
def select_value(sql)
|
40
|
+
if result = select_one(sql)
|
41
|
+
result.values.first
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns an array of the values of the first column in a select:
|
46
|
+
# select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
|
47
|
+
def select_values(sql)
|
48
|
+
result = select(sql)
|
49
|
+
result.map { |r| r.values.first }
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class OracleEnhancedConnectionException < StandardError
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# if MRI or YARV
|
62
|
+
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
|
63
|
+
ORACLE_ENHANCED_CONNECTION = :oci
|
64
|
+
require 'active_record/connection_adapters/oracle_enhanced_oci_connection'
|
65
|
+
# if JRuby
|
66
|
+
elsif RUBY_ENGINE == 'jruby'
|
67
|
+
ORACLE_ENHANCED_CONNECTION = :jdbc
|
68
|
+
require 'active_record/connection_adapters/oracle_enhanced_jdbc_connection'
|
69
|
+
else
|
70
|
+
raise "Unsupported Ruby engine #{RUBY_ENGINE}"
|
71
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "bigdecimal"
|
2
|
+
unless BigDecimal.instance_methods.include?("to_d")
|
3
|
+
BigDecimal.class_eval do
|
4
|
+
def to_d
|
5
|
+
self
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
unless Bignum.instance_methods.include?("to_d")
|
11
|
+
Bignum.class_eval do
|
12
|
+
def to_d
|
13
|
+
BigDecimal.new(self.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
unless Fixnum.instance_methods.include?("to_d")
|
19
|
+
Fixnum.class_eval do
|
20
|
+
def to_d
|
21
|
+
BigDecimal.new(self.to_s)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Add Unicode aware String#upcase and String#downcase methods when mb_chars method is called
|
27
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' && RUBY_VERSION >= '1.9'
|
28
|
+
begin
|
29
|
+
gem "unicode_utils", ">=1.0.0"
|
30
|
+
require "unicode_utils/upcase"
|
31
|
+
require "unicode_utils/downcase"
|
32
|
+
|
33
|
+
module ActiveRecord
|
34
|
+
module ConnectionAdapters
|
35
|
+
module OracleEnhancedUnicodeString
|
36
|
+
def upcase
|
37
|
+
UnicodeUtils.upcase(self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def downcase
|
41
|
+
UnicodeUtils.downcase(self)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class String
|
48
|
+
def mb_chars
|
49
|
+
self.extend(ActiveRecord::ConnectionAdapters::OracleEnhancedUnicodeString)
|
50
|
+
self
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
rescue LoadError
|
55
|
+
warning_message = "WARNING: Please install unicode_utils gem to support Unicode aware upcase and downcase for String#mb_chars"
|
56
|
+
if defined?(RAILS_DEFAULT_LOGGER)
|
57
|
+
RAILS_DEFAULT_LOGGER.warn warning_message
|
58
|
+
else
|
59
|
+
STDERR.puts warning_message
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
@@ -8,12 +8,12 @@ module ActiveRecord #:nodoc:
|
|
8
8
|
def field_changed?(attr, old, value)
|
9
9
|
if column = column_for_attribute(attr)
|
10
10
|
# RSI: added also :decimal type
|
11
|
-
if (column.type == :integer || column.type == :decimal) && column.null && (old.nil? || old == 0)
|
11
|
+
if (column.type == :integer || column.type == :decimal) && column.null && (old.nil? || old == 0) && value.blank?
|
12
12
|
# For nullable integer columns, NULL gets stored in database for blank (i.e. '') values.
|
13
13
|
# Hence we don't record it as a change if the value changes from nil to ''.
|
14
14
|
# If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
|
15
15
|
# be typecast back to 0 (''.to_i => 0)
|
16
|
-
value = nil
|
16
|
+
value = nil
|
17
17
|
# RSI: Oracle stores empty string '' or empty text (CLOB) as NULL
|
18
18
|
# therefore need to convert empty string value to nil if old value is nil
|
19
19
|
elsif (column.type == :string || column.type == :text) && column.null && old.nil?
|
@@ -0,0 +1,352 @@
|
|
1
|
+
begin
|
2
|
+
require "java"
|
3
|
+
require "jruby"
|
4
|
+
# Adds JRuby classloader to current thread classloader - as a result ojdbc14.jar should not be in $JRUBY_HOME/lib
|
5
|
+
java.lang.Thread.currentThread.setContextClassLoader(JRuby.runtime.jruby_class_loader)
|
6
|
+
|
7
|
+
ojdbc_jar = "ojdbc14.jar"
|
8
|
+
if ojdbc_jar_path = ENV["PATH"].split(/[:;]/).find{|d| File.exists?(File.join(d,ojdbc_jar))}
|
9
|
+
require File.join(ojdbc_jar_path,ojdbc_jar)
|
10
|
+
end
|
11
|
+
# import java.sql.Statement
|
12
|
+
# import java.sql.Connection
|
13
|
+
# import java.sql.SQLException
|
14
|
+
# import java.sql.Types
|
15
|
+
# import java.sql.DriverManager
|
16
|
+
java.sql.DriverManager.registerDriver Java::oracle.jdbc.driver.OracleDriver.new
|
17
|
+
|
18
|
+
rescue LoadError, NameError
|
19
|
+
# JDBC driver is unavailable.
|
20
|
+
error_message = "ERROR: ActiveRecord oracle_enhanced adapter could not load Oracle JDBC driver. "+
|
21
|
+
"Please install ojdbc14.jar library."
|
22
|
+
if defined?(RAILS_DEFAULT_LOGGER)
|
23
|
+
RAILS_DEFAULT_LOGGER.error error_message
|
24
|
+
else
|
25
|
+
STDERR.puts error_message
|
26
|
+
end
|
27
|
+
raise LoadError
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
module ActiveRecord
|
32
|
+
module ConnectionAdapters
|
33
|
+
|
34
|
+
# JDBC database interface for JRuby
|
35
|
+
class OracleEnhancedJDBCConnection < OracleEnhancedConnection
|
36
|
+
|
37
|
+
attr_accessor :active
|
38
|
+
alias :active? :active
|
39
|
+
|
40
|
+
attr_accessor :auto_retry
|
41
|
+
alias :auto_retry? :auto_retry
|
42
|
+
@auto_retry = false
|
43
|
+
|
44
|
+
def initialize(config)
|
45
|
+
@active = true
|
46
|
+
@config = config
|
47
|
+
new_connection(@config)
|
48
|
+
end
|
49
|
+
|
50
|
+
def new_connection(config)
|
51
|
+
username, password, database = config[:username].to_s, config[:password].to_s, config[:database].to_s
|
52
|
+
privilege = config[:privilege] && config[:privilege].to_s
|
53
|
+
host, port = config[:host], config[:port]
|
54
|
+
|
55
|
+
url = config[:url] || "jdbc:oracle:thin:@#{host || 'localhost'}:#{port || 1521}:#{database || 'XE'}"
|
56
|
+
|
57
|
+
prefetch_rows = config[:prefetch_rows] || 100
|
58
|
+
cursor_sharing = config[:cursor_sharing] || 'similar'
|
59
|
+
|
60
|
+
properties = java.util.Properties.new
|
61
|
+
properties.put("user", username)
|
62
|
+
properties.put("password", password)
|
63
|
+
properties.put("defaultRowPrefetch", "#{prefetch_rows}") if prefetch_rows
|
64
|
+
properties.put("internal_logon", privilege) if privilege
|
65
|
+
|
66
|
+
@raw_connection = java.sql.DriverManager.getConnection(url, properties)
|
67
|
+
exec %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
|
68
|
+
exec %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'} # rescue nil
|
69
|
+
exec "alter session set cursor_sharing = #{cursor_sharing}" # rescue nil
|
70
|
+
self.autocommit = true
|
71
|
+
|
72
|
+
# Set session time zone to current time zone
|
73
|
+
@raw_connection.setSessionTimeZone(java.util.TimeZone.default.getID)
|
74
|
+
|
75
|
+
# default schema owner
|
76
|
+
@owner = username.upcase
|
77
|
+
|
78
|
+
@raw_connection
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def logoff
|
83
|
+
@active = false
|
84
|
+
@raw_connection.close
|
85
|
+
true
|
86
|
+
rescue
|
87
|
+
false
|
88
|
+
end
|
89
|
+
|
90
|
+
def commit
|
91
|
+
@raw_connection.commit
|
92
|
+
end
|
93
|
+
|
94
|
+
def rollback
|
95
|
+
@raw_connection.rollback
|
96
|
+
end
|
97
|
+
|
98
|
+
def autocommit?
|
99
|
+
@raw_connection.getAutoCommit
|
100
|
+
end
|
101
|
+
|
102
|
+
def autocommit=(value)
|
103
|
+
@raw_connection.setAutoCommit(value)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Checks connection, returns true if active. Note that ping actively
|
107
|
+
# checks the connection, while #active? simply returns the last
|
108
|
+
# known state.
|
109
|
+
def ping
|
110
|
+
exec_no_retry("select 1 from dual")
|
111
|
+
@active = true
|
112
|
+
rescue NativeException => e
|
113
|
+
@active = false
|
114
|
+
if e.message =~ /^java\.sql\.SQLException/
|
115
|
+
raise OracleEnhancedConnectionException, e.message
|
116
|
+
else
|
117
|
+
raise
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Resets connection, by logging off and creating a new connection.
|
122
|
+
def reset!
|
123
|
+
logoff rescue nil
|
124
|
+
begin
|
125
|
+
new_connection(@config)
|
126
|
+
@active = true
|
127
|
+
rescue NativeException => e
|
128
|
+
@active = false
|
129
|
+
if e.message =~ /^java\.sql\.SQLException/
|
130
|
+
raise OracleEnhancedConnectionException, e.message
|
131
|
+
else
|
132
|
+
raise
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# mark connection as dead if connection lost
|
138
|
+
def with_retry(&block)
|
139
|
+
should_retry = auto_retry? && autocommit?
|
140
|
+
begin
|
141
|
+
yield if block_given?
|
142
|
+
rescue NativeException => e
|
143
|
+
raise unless e.message =~ /^java\.sql\.SQLException: (Closed Connection|Io exception:|No more data to read from socket)/
|
144
|
+
@active = false
|
145
|
+
raise unless should_retry
|
146
|
+
should_retry = false
|
147
|
+
reset! rescue nil
|
148
|
+
retry
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def exec(sql)
|
153
|
+
with_retry do
|
154
|
+
exec_no_retry(sql)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def exec_no_retry(sql)
|
159
|
+
cs = prepare_call(sql)
|
160
|
+
case sql
|
161
|
+
when /\A\s*UPDATE/i, /\A\s*INSERT/i, /\A\s*DELETE/i
|
162
|
+
cs.executeUpdate
|
163
|
+
else
|
164
|
+
cs.execute
|
165
|
+
true
|
166
|
+
end
|
167
|
+
ensure
|
168
|
+
cs.close rescue nil
|
169
|
+
end
|
170
|
+
|
171
|
+
def select(sql, name = nil, return_column_names = false)
|
172
|
+
with_retry do
|
173
|
+
select_no_retry(sql, name, return_column_names)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def select_no_retry(sql, name = nil, return_column_names = false)
|
178
|
+
stmt = prepare_statement(sql)
|
179
|
+
rset = stmt.executeQuery
|
180
|
+
metadata = rset.getMetaData
|
181
|
+
column_count = metadata.getColumnCount
|
182
|
+
cols = (1..column_count).map do |i|
|
183
|
+
oracle_downcase(metadata.getColumnName(i))
|
184
|
+
end
|
185
|
+
col_types = (1..column_count).map do |i|
|
186
|
+
metadata.getColumnTypeName(i)
|
187
|
+
end
|
188
|
+
|
189
|
+
rows = []
|
190
|
+
|
191
|
+
while rset.next
|
192
|
+
hash = Hash.new
|
193
|
+
|
194
|
+
cols.each_with_index do |col, i0|
|
195
|
+
i = i0 + 1
|
196
|
+
hash[col] =
|
197
|
+
case column_type = col_types[i0]
|
198
|
+
when /CLOB/
|
199
|
+
name == 'Writable Large Object' ? rset.getClob(i) : get_ruby_value_from_result_set(rset, i, column_type)
|
200
|
+
when /BLOB/
|
201
|
+
name == 'Writable Large Object' ? rset.getBlob(i) : get_ruby_value_from_result_set(rset, i, column_type)
|
202
|
+
when 'DATE'
|
203
|
+
t = get_ruby_value_from_result_set(rset, i, column_type)
|
204
|
+
# RSI: added emulate_dates_by_column_name functionality
|
205
|
+
# if emulate_dates_by_column_name && self.class.is_date_column?(col)
|
206
|
+
# d.to_date
|
207
|
+
# elsif
|
208
|
+
if t && OracleEnhancedAdapter.emulate_dates && (t.hour == 0 && t.min == 0 && t.sec == 0)
|
209
|
+
t.to_date
|
210
|
+
else
|
211
|
+
# JRuby Time supports time before year 1900 therefore now need to fall back to DateTime
|
212
|
+
t
|
213
|
+
end
|
214
|
+
# RSI: added emulate_integers_by_column_name functionality
|
215
|
+
when "NUMBER"
|
216
|
+
n = get_ruby_value_from_result_set(rset, i, column_type)
|
217
|
+
if n && n.is_a?(Float) && OracleEnhancedAdapter.emulate_integers_by_column_name && OracleEnhancedAdapter.is_integer_column?(col)
|
218
|
+
n.to_i
|
219
|
+
else
|
220
|
+
n
|
221
|
+
end
|
222
|
+
else
|
223
|
+
get_ruby_value_from_result_set(rset, i, column_type)
|
224
|
+
end unless col == 'raw_rnum_'
|
225
|
+
end
|
226
|
+
|
227
|
+
rows << hash
|
228
|
+
end
|
229
|
+
|
230
|
+
return_column_names ? [rows, cols] : rows
|
231
|
+
ensure
|
232
|
+
rset.close rescue nil
|
233
|
+
stmt.close rescue nil
|
234
|
+
end
|
235
|
+
|
236
|
+
def write_lob(lob, value, is_binary = false)
|
237
|
+
if is_binary
|
238
|
+
lob.setBytes(1, value.to_java_bytes)
|
239
|
+
else
|
240
|
+
lob.setString(1,value)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def describe(name)
|
245
|
+
real_name = OracleEnhancedAdapter.valid_table_name?(name) ? name.to_s.upcase : name.to_s
|
246
|
+
if real_name.include?('.')
|
247
|
+
table_owner, table_name = real_name.split('.')
|
248
|
+
else
|
249
|
+
table_owner, table_name = @owner, real_name
|
250
|
+
end
|
251
|
+
sql = <<-SQL
|
252
|
+
SELECT owner, table_name, 'TABLE' name_type
|
253
|
+
FROM all_tables
|
254
|
+
WHERE owner = '#{table_owner}'
|
255
|
+
AND table_name = '#{table_name}'
|
256
|
+
UNION ALL
|
257
|
+
SELECT owner, view_name table_name, 'VIEW' name_type
|
258
|
+
FROM all_views
|
259
|
+
WHERE owner = '#{table_owner}'
|
260
|
+
AND view_name = '#{table_name}'
|
261
|
+
UNION ALL
|
262
|
+
SELECT table_owner, table_name, 'SYNONYM' name_type
|
263
|
+
FROM all_synonyms
|
264
|
+
WHERE owner = '#{table_owner}'
|
265
|
+
AND synonym_name = '#{table_name}'
|
266
|
+
UNION ALL
|
267
|
+
SELECT table_owner, table_name, 'SYNONYM' name_type
|
268
|
+
FROM all_synonyms
|
269
|
+
WHERE owner = 'PUBLIC'
|
270
|
+
AND synonym_name = '#{real_name}'
|
271
|
+
SQL
|
272
|
+
if result = select_one(sql)
|
273
|
+
case result['name_type']
|
274
|
+
when 'SYNONYM'
|
275
|
+
describe("#{result['owner']}.#{result['table_name']}")
|
276
|
+
else
|
277
|
+
[result['owner'], result['table_name']]
|
278
|
+
end
|
279
|
+
else
|
280
|
+
raise OracleEnhancedConnectionException, %Q{"DESC #{name}" failed; does it exist?}
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
private
|
286
|
+
|
287
|
+
def prepare_statement(sql)
|
288
|
+
@raw_connection.prepareStatement(sql)
|
289
|
+
end
|
290
|
+
|
291
|
+
def prepare_call(sql, *bindvars)
|
292
|
+
@raw_connection.prepareCall(sql)
|
293
|
+
end
|
294
|
+
|
295
|
+
def get_ruby_value_from_result_set(rset, i, type_name)
|
296
|
+
case type_name
|
297
|
+
when "CHAR", "VARCHAR2", "LONG"
|
298
|
+
rset.getString(i)
|
299
|
+
when "CLOB"
|
300
|
+
ora_value_to_ruby_value(rset.getClob(i))
|
301
|
+
when "BLOB"
|
302
|
+
ora_value_to_ruby_value(rset.getBlob(i))
|
303
|
+
when "NUMBER"
|
304
|
+
d = rset.getBigDecimal(i)
|
305
|
+
if d.nil?
|
306
|
+
nil
|
307
|
+
elsif d.scale == 0
|
308
|
+
d.toBigInteger+0
|
309
|
+
else
|
310
|
+
# Is there better way how to convert Java BigDecimal to Ruby BigDecimal?
|
311
|
+
d.toString.to_d
|
312
|
+
end
|
313
|
+
when "DATE"
|
314
|
+
if dt = rset.getDATE(i)
|
315
|
+
d = dt.dateValue
|
316
|
+
t = dt.timeValue
|
317
|
+
Time.send(Base.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
|
318
|
+
else
|
319
|
+
nil
|
320
|
+
end
|
321
|
+
when /^TIMESTAMP/
|
322
|
+
ts = rset.getTimestamp(i)
|
323
|
+
ts && Time.send(Base.default_timezone, ts.year + 1900, ts.month + 1, ts.date, ts.hours, ts.minutes, ts.seconds,
|
324
|
+
ts.nanos / 1000)
|
325
|
+
else
|
326
|
+
nil
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def ora_value_to_ruby_value(val)
|
331
|
+
case val
|
332
|
+
when ::Java::OracleSql::CLOB
|
333
|
+
if val.isEmptyLob
|
334
|
+
nil
|
335
|
+
else
|
336
|
+
val.getSubString(1, val.length)
|
337
|
+
end
|
338
|
+
when ::Java::OracleSql::BLOB
|
339
|
+
if val.isEmptyLob
|
340
|
+
nil
|
341
|
+
else
|
342
|
+
String.from_java_bytes(val.getBytes(1, val.length))
|
343
|
+
end
|
344
|
+
else
|
345
|
+
val
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
352
|
+
end
|