activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/Gemfile +20 -11
- data/History.md +123 -4
- data/RUNNING_TESTS.md +79 -55
- data/Rakefile +13 -19
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +16 -17
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +7 -59
- data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +6 -50
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +11 -11
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +117 -117
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +30 -23
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +48 -70
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +51 -69
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +4 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +76 -76
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +13 -42
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +60 -64
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +33 -47
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +146 -159
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +94 -132
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +65 -100
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +250 -487
- data/lib/active_record/oracle_enhanced/type/boolean.rb +7 -10
- data/lib/active_record/oracle_enhanced/type/integer.rb +3 -4
- data/lib/active_record/oracle_enhanced/type/national_character_string.rb +1 -1
- data/lib/active_record/oracle_enhanced/type/raw.rb +2 -3
- data/lib/active_record/oracle_enhanced/type/string.rb +2 -2
- data/lib/active_record/oracle_enhanced/type/text.rb +2 -2
- data/lib/activerecord-oracle_enhanced-adapter.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +57 -131
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +32 -34
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -42
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +83 -85
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +205 -286
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +14 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +3 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +42 -49
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +68 -71
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +51 -92
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +221 -327
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +16 -18
- data/spec/spec_helper.rb +59 -57
- metadata +10 -10
@@ -16,10 +16,10 @@ module ActiveRecord
|
|
16
16
|
reload_type_map
|
17
17
|
end
|
18
18
|
|
19
|
-
def exec_query(sql, name =
|
19
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
20
20
|
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
|
21
21
|
|
22
|
-
log(sql, name, binds) do
|
22
|
+
log(sql, name, binds, type_casted_binds) do
|
23
23
|
cursor = nil
|
24
24
|
cached = false
|
25
25
|
if without_prepared_statement?(binds)
|
@@ -38,14 +38,14 @@ module ActiveRecord
|
|
38
38
|
|
39
39
|
cursor.exec
|
40
40
|
|
41
|
-
if name ==
|
41
|
+
if (name == "EXPLAIN") && sql =~ /^EXPLAIN/
|
42
42
|
res = true
|
43
43
|
else
|
44
44
|
columns = cursor.get_col_names.map do |col_name|
|
45
45
|
@connection.oracle_downcase(col_name)
|
46
46
|
end
|
47
47
|
rows = []
|
48
|
-
fetch_options = {:
|
48
|
+
fetch_options = { get_lob_value: (name != "Writable Large Object") }
|
49
49
|
while row = cursor.fetch(fetch_options)
|
50
50
|
rows << row
|
51
51
|
end
|
@@ -69,17 +69,11 @@ module ActiveRecord
|
|
69
69
|
sql = "EXPLAIN PLAN FOR #{to_sql(arel, binds)}"
|
70
70
|
return if sql =~ /FROM all_/
|
71
71
|
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
72
|
-
exec_query(sql,
|
72
|
+
exec_query(sql, "EXPLAIN", binds)
|
73
73
|
else
|
74
|
-
exec_query(sql,
|
74
|
+
exec_query(sql, "EXPLAIN")
|
75
75
|
end
|
76
|
-
select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)",
|
77
|
-
end
|
78
|
-
|
79
|
-
# Returns an array of arrays containing the field values.
|
80
|
-
# Order is the same as that returned by #columns.
|
81
|
-
def select_rows(sql, name = nil, binds = [])
|
82
|
-
exec_query(sql, name, binds).rows
|
76
|
+
select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)", "EXPLAIN").join("\n")
|
83
77
|
end
|
84
78
|
|
85
79
|
# New method in ActiveRecord 3.1
|
@@ -92,11 +86,17 @@ module ActiveRecord
|
|
92
86
|
super
|
93
87
|
end
|
94
88
|
|
89
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
90
|
+
pk = nil if id_value
|
91
|
+
super
|
92
|
+
end
|
93
|
+
|
95
94
|
# New method in ActiveRecord 3.1
|
96
|
-
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
95
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
96
|
+
sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
|
97
97
|
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
|
98
98
|
|
99
|
-
log(sql, name, binds) do
|
99
|
+
log(sql, name, binds, type_casted_binds) do
|
100
100
|
returning_id_col = returning_id_index = nil
|
101
101
|
if without_prepared_statement?(binds)
|
102
102
|
cursor = @connection.prepare(sql)
|
@@ -129,19 +129,19 @@ module ActiveRecord
|
|
129
129
|
end
|
130
130
|
|
131
131
|
# New method in ActiveRecord 3.1
|
132
|
-
def exec_update(sql, name, binds)
|
132
|
+
def exec_update(sql, name = nil, binds = [])
|
133
133
|
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
|
134
134
|
|
135
|
-
log(sql, name, binds) do
|
135
|
+
log(sql, name, binds, type_casted_binds) do
|
136
136
|
cached = false
|
137
137
|
if without_prepared_statement?(binds)
|
138
138
|
cursor = @connection.prepare(sql)
|
139
139
|
else
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
140
|
+
if @statements.key?(sql)
|
141
|
+
cursor = @statements[sql]
|
142
|
+
else
|
143
|
+
cursor = @statements[sql] = @connection.prepare(sql)
|
144
|
+
end
|
145
145
|
|
146
146
|
cursor.bind_params(type_casted_binds)
|
147
147
|
|
@@ -202,7 +202,7 @@ module ActiveRecord
|
|
202
202
|
# Returns default sequence name for table.
|
203
203
|
# Will take all or first 26 characters of table name and append _seq suffix
|
204
204
|
def default_sequence_name(table_name, primary_key = nil)
|
205
|
-
table_name.to_s.gsub((/(^|\.)([\w$-]{1,#{sequence_name_length-4}})([\w$-]*)$/), '\1\2_seq')
|
205
|
+
table_name.to_s.gsub((/(^|\.)([\w$-]{1,#{sequence_name_length - 4}})([\w$-]*)$/), '\1\2_seq')
|
206
206
|
end
|
207
207
|
|
208
208
|
# Inserts the given fixture into the table. Overridden to properly handle lobs.
|
@@ -220,6 +220,13 @@ module ActiveRecord
|
|
220
220
|
write_lobs(table_name, klass, fixture, klass.lob_columns)
|
221
221
|
end
|
222
222
|
end
|
223
|
+
|
224
|
+
# Oracle Database does not support this feature
|
225
|
+
# Refer https://community.oracle.com/ideas/13845 and consider to vote
|
226
|
+
# if you need this feature.
|
227
|
+
def empty_insert_statement_value
|
228
|
+
raise NotImplementedError
|
229
|
+
end
|
223
230
|
end
|
224
231
|
end
|
225
232
|
end
|
@@ -1,21 +1,21 @@
|
|
1
|
-
require
|
1
|
+
require "active_record/base"
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
5
|
class OracleEnhancedAdapter
|
6
6
|
class DatabaseTasks
|
7
|
-
delegate :connection, :establish_connection, :
|
7
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
8
8
|
|
9
9
|
def initialize(config)
|
10
10
|
@config = config
|
11
11
|
end
|
12
12
|
|
13
13
|
def create
|
14
|
-
system_password = ENV.fetch(
|
14
|
+
system_password = ENV.fetch("ORACLE_SYSTEM_PASSWORD") {
|
15
15
|
print "Please provide the SYSTEM password for your Oracle installation (set ORACLE_SYSTEM_PASSWORD to avoid this prompt)\n>"
|
16
16
|
$stdin.gets.strip
|
17
17
|
}
|
18
|
-
establish_connection(@config.merge(
|
18
|
+
establish_connection(@config.merge("username" => "SYSTEM", "password" => system_password))
|
19
19
|
begin
|
20
20
|
connection.execute "CREATE USER #{@config['username']} IDENTIFIED BY #{@config['password']}"
|
21
21
|
rescue => e
|
@@ -39,18 +39,18 @@ module ActiveRecord
|
|
39
39
|
|
40
40
|
def purge
|
41
41
|
drop
|
42
|
-
connection.execute(
|
42
|
+
connection.execute("PURGE RECYCLEBIN") rescue nil
|
43
43
|
end
|
44
44
|
|
45
|
-
def structure_dump(filename)
|
45
|
+
def structure_dump(filename, extra_flags)
|
46
46
|
establish_connection(@config)
|
47
|
-
File.open(filename,
|
48
|
-
if @config[
|
49
|
-
|
47
|
+
File.open(filename, "w:utf-8") { |f| f << connection.structure_dump }
|
48
|
+
if @config["structure_dump"] == "db_stored_code"
|
49
|
+
File.open(filename, "a") { |f| f << connection.structure_dump_db_stored_code }
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def structure_load(filename)
|
53
|
+
def structure_load(filename, extra_flags)
|
54
54
|
establish_connection(@config)
|
55
55
|
connection.execute_structure_dump(File.read(filename))
|
56
56
|
end
|
@@ -2,27 +2,25 @@ begin
|
|
2
2
|
require "java"
|
3
3
|
require "jruby"
|
4
4
|
|
5
|
-
# ojdbc7.jar
|
5
|
+
# ojdbc7.jar or ojdbc6.jar file should be in application ./lib directory or in load path or in ENV['PATH']
|
6
6
|
|
7
7
|
java_version = java.lang.System.getProperty("java.version")
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
elsif java_version >= '1.7'
|
13
|
-
# Oracle 11g client ojdbc6.jar is also compatible with Java 1.7
|
14
|
-
# Oracle 12c client provides new ojdbc7.jar
|
15
|
-
%w(ojdbc7.jar ojdbc6.jar)
|
16
|
-
else
|
17
|
-
nil
|
8
|
+
# Dropping Java SE 6(1.6) or older version without deprecation cycle.
|
9
|
+
# Rails 5.0 already requires CRuby 2.2.2 or higher and JRuby 9.0 supporging CRuby 2.2 requires Java SE 7.
|
10
|
+
if java_version < "1.7"
|
11
|
+
raise "ERROR: Java SE 6 or older version is not supported. Upgrade Java version to Java SE 7 or higher"
|
18
12
|
end
|
19
13
|
|
20
|
-
|
14
|
+
# Oracle 11g client ojdbc6.jar is also compatible with Java 1.7
|
15
|
+
# Oracle 12c client provides new ojdbc7.jar
|
16
|
+
ojdbc_jars = %w(ojdbc7.jar ojdbc6.jar)
|
17
|
+
|
18
|
+
if ENV_JAVA["java.class.path"] !~ Regexp.new(ojdbc_jars.join("|"))
|
21
19
|
# On Unix environment variable should be PATH, on Windows it is sometimes Path
|
22
|
-
env_path = (ENV["PATH"] || ENV["Path"] ||
|
20
|
+
env_path = (ENV["PATH"] || ENV["Path"] || "").split(File::PATH_SEPARATOR)
|
23
21
|
# Look for JDBC driver at first in lib subdirectory (application specific JDBC file version)
|
24
22
|
# then in Ruby load path and finally in environment PATH
|
25
|
-
[
|
23
|
+
["./lib"].concat($LOAD_PATH).concat(env_path).detect do |dir|
|
26
24
|
# check any compatible JDBC driver in the priority order
|
27
25
|
ojdbc_jars.any? do |ojdbc_jar|
|
28
26
|
if File.exists?(file_path = File.join(dir, ojdbc_jar))
|
@@ -43,7 +41,7 @@ begin
|
|
43
41
|
|
44
42
|
rescue LoadError, NameError
|
45
43
|
# JDBC driver is unavailable.
|
46
|
-
raise LoadError, "ERROR: ActiveRecord oracle_enhanced adapter could not load Oracle JDBC driver. Please install #{ojdbc_jars
|
44
|
+
raise LoadError, "ERROR: ActiveRecord oracle_enhanced adapter could not load Oracle JDBC driver. Please install #{ojdbc_jars.join(' or ') } library."
|
47
45
|
end
|
48
46
|
|
49
47
|
module ActiveRecord
|
@@ -74,7 +72,7 @@ module ActiveRecord
|
|
74
72
|
|
75
73
|
# tomcat needs first lookup method, oc4j (and maybe other application servers) need second method
|
76
74
|
begin
|
77
|
-
env = ctx.lookup(
|
75
|
+
env = ctx.lookup("java:/comp/env")
|
78
76
|
ds = env.lookup(jndi)
|
79
77
|
rescue
|
80
78
|
ds = ctx.lookup(jndi)
|
@@ -102,13 +100,13 @@ module ActiveRecord
|
|
102
100
|
# to_s needed if username, password or database is specified as number in database.yml file
|
103
101
|
username = config[:username] && config[:username].to_s
|
104
102
|
password = config[:password] && config[:password].to_s
|
105
|
-
database = config[:database] && config[:database].to_s ||
|
103
|
+
database = config[:database] && config[:database].to_s || "XE"
|
106
104
|
host, port = config[:host], config[:port]
|
107
105
|
privilege = config[:privilege] && config[:privilege].to_s
|
108
106
|
|
109
107
|
# connection using TNS alias, or connection-string from DATABASE_URL
|
110
|
-
using_tns_alias = !host && !config[:url] && ENV[
|
111
|
-
if database && (using_tns_alias || host ==
|
108
|
+
using_tns_alias = !host && !config[:url] && ENV["TNS_ADMIN"]
|
109
|
+
if database && (using_tns_alias || host == "connection-string")
|
112
110
|
url = "jdbc:oracle:thin:@#{database}"
|
113
111
|
else
|
114
112
|
unless database.match(/^(\:|\/)/)
|
@@ -120,7 +118,7 @@ module ActiveRecord
|
|
120
118
|
|
121
119
|
prefetch_rows = config[:prefetch_rows] || 100
|
122
120
|
# get session time_zone from configuration or from TZ environment variable
|
123
|
-
time_zone = config[:time_zone] || ENV[
|
121
|
+
time_zone = config[:time_zone] || ENV["TZ"] || java.util.TimeZone.default.getID
|
124
122
|
|
125
123
|
properties = java.util.Properties.new
|
126
124
|
properties.put("user", username)
|
@@ -144,7 +142,7 @@ module ActiveRecord
|
|
144
142
|
# @raw_connection.setDefaultRowPrefetch(prefetch_rows) if prefetch_rows
|
145
143
|
end
|
146
144
|
|
147
|
-
cursor_sharing = config[:cursor_sharing] ||
|
145
|
+
cursor_sharing = config[:cursor_sharing] || "force"
|
148
146
|
exec "alter session set cursor_sharing = #{cursor_sharing}"
|
149
147
|
|
150
148
|
# Initialize NLS parameters
|
@@ -327,7 +325,7 @@ module ActiveRecord
|
|
327
325
|
@raw_statement = raw_statement
|
328
326
|
end
|
329
327
|
|
330
|
-
def bind_params(
|
328
|
+
def bind_params(*bind_vars)
|
331
329
|
index = 1
|
332
330
|
bind_vars.flatten.each do |var|
|
333
331
|
if Hash === var
|
@@ -339,17 +337,7 @@ module ActiveRecord
|
|
339
337
|
end
|
340
338
|
end
|
341
339
|
|
342
|
-
def bind_param(position, value
|
343
|
-
if column
|
344
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
345
|
-
*******************************************************
|
346
|
-
Passing a column to `bind_param` will be deprecated.
|
347
|
-
`type_casted_binds` should be already type casted
|
348
|
-
so that `bind_param` should not need to know column.
|
349
|
-
*******************************************************
|
350
|
-
MSG
|
351
|
-
end
|
352
|
-
|
340
|
+
def bind_param(position, value)
|
353
341
|
case value
|
354
342
|
when Integer
|
355
343
|
@raw_statement.setLong(position, value)
|
@@ -376,14 +364,10 @@ module ActiveRecord
|
|
376
364
|
# TODO: Really needed or not
|
377
365
|
@raw_statement.setTimestamp(position, value)
|
378
366
|
when NilClass
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
# When nils will actually be used by ActiveRecord as bound parameters
|
384
|
-
# then need to pass actual column type.
|
385
|
-
@raw_statement.setNull(position, java.sql.Types::VARCHAR)
|
386
|
-
end
|
367
|
+
# TODO: currently nil is always bound as NULL with VARCHAR type.
|
368
|
+
# When nils will actually be used by ActiveRecord as bound parameters
|
369
|
+
# then need to pass actual column type.
|
370
|
+
@raw_statement.setNull(position, java.sql.Types::VARCHAR)
|
387
371
|
else
|
388
372
|
raise ArgumentError, "Don't know how to bind variable with type #{value.class}"
|
389
373
|
end
|
@@ -411,21 +395,21 @@ module ActiveRecord
|
|
411
395
|
end
|
412
396
|
|
413
397
|
def column_types
|
414
|
-
@column_types ||= (1..metadata.getColumnCount).map{|i| metadata.getColumnTypeName(i).to_sym}
|
398
|
+
@column_types ||= (1..metadata.getColumnCount).map { |i| metadata.getColumnTypeName(i).to_sym }
|
415
399
|
end
|
416
400
|
|
417
401
|
def column_names
|
418
|
-
@column_names ||= (1..metadata.getColumnCount).map{|i| metadata.getColumnName(i)}
|
402
|
+
@column_names ||= (1..metadata.getColumnCount).map { |i| metadata.getColumnName(i) }
|
419
403
|
end
|
420
404
|
alias :get_col_names :column_names
|
421
405
|
|
422
|
-
def fetch(options={})
|
406
|
+
def fetch(options = {})
|
423
407
|
if @raw_result_set.next
|
424
408
|
get_lob_value = options[:get_lob_value]
|
425
409
|
row_values = []
|
426
410
|
column_types.each_with_index do |column_type, i|
|
427
411
|
row_values <<
|
428
|
-
@connection.get_ruby_value_from_result_set(@raw_result_set, i+1, column_type, get_lob_value)
|
412
|
+
@connection.get_ruby_value_from_result_set(@raw_result_set, i + 1, column_type, get_lob_value)
|
429
413
|
end
|
430
414
|
row_values
|
431
415
|
else
|
@@ -469,14 +453,14 @@ module ActiveRecord
|
|
469
453
|
|
470
454
|
cols_types_index = (1..column_count).map do |i|
|
471
455
|
col_name = oracle_downcase(metadata.getColumnName(i))
|
472
|
-
next if col_name ==
|
456
|
+
next if col_name == "raw_rnum_"
|
473
457
|
column_hash[col_name] = nil
|
474
458
|
[col_name, metadata.getColumnTypeName(i).to_sym, i]
|
475
459
|
end
|
476
460
|
cols_types_index.delete(nil)
|
477
461
|
|
478
462
|
rows = []
|
479
|
-
get_lob_value = !(name ==
|
463
|
+
get_lob_value = !(name == "Writable Large Object")
|
480
464
|
|
481
465
|
while rset.next
|
482
466
|
hash = column_hash.dup
|
@@ -496,7 +480,7 @@ module ActiveRecord
|
|
496
480
|
if is_binary
|
497
481
|
lob.setBytes(1, value.to_java_bytes)
|
498
482
|
else
|
499
|
-
lob.setString(1,value)
|
483
|
+
lob.setString(1, value)
|
500
484
|
end
|
501
485
|
end
|
502
486
|
|
@@ -521,19 +505,13 @@ module ActiveRecord
|
|
521
505
|
else
|
522
506
|
BigDecimal.new(d.stringValue)
|
523
507
|
end
|
524
|
-
when :BINARY_FLOAT
|
525
|
-
rset.getFloat(i)
|
526
508
|
when :VARCHAR2, :CHAR, :LONG, :NVARCHAR2, :NCHAR
|
527
509
|
rset.getString(i)
|
528
510
|
when :DATE
|
529
511
|
if dt = rset.getDATE(i)
|
530
512
|
d = dt.dateValue
|
531
513
|
t = dt.timeValue
|
532
|
-
|
533
|
-
Date.new(d.year + 1900, d.month + 1, d.date)
|
534
|
-
else
|
535
|
-
Time.send(Base.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
|
536
|
-
end
|
514
|
+
Time.send(Base.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
|
537
515
|
else
|
538
516
|
nil
|
539
517
|
end
|
@@ -547,7 +525,7 @@ module ActiveRecord
|
|
547
525
|
get_lob_value ? lob_to_ruby_value(rset.getBlob(i)) : rset.getBlob(i)
|
548
526
|
when :RAW
|
549
527
|
raw_value = rset.getRAW(i)
|
550
|
-
raw_value && raw_value.getBytes.to_a.pack(
|
528
|
+
raw_value && raw_value.getBytes.to_a.pack("C*")
|
551
529
|
else
|
552
530
|
nil
|
553
531
|
end
|
@@ -555,22 +533,22 @@ module ActiveRecord
|
|
555
533
|
|
556
534
|
private
|
557
535
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
536
|
+
def lob_to_ruby_value(val)
|
537
|
+
case val
|
538
|
+
when ::Java::OracleSql::CLOB
|
539
|
+
if val.isEmptyLob
|
540
|
+
nil
|
541
|
+
else
|
542
|
+
val.getSubString(1, val.length)
|
543
|
+
end
|
544
|
+
when ::Java::OracleSql::BLOB
|
545
|
+
if val.isEmptyLob
|
546
|
+
nil
|
547
|
+
else
|
548
|
+
String.from_java_bytes(val.getBytes(1, val.length))
|
549
|
+
end
|
571
550
|
end
|
572
551
|
end
|
573
|
-
end
|
574
552
|
end
|
575
553
|
end
|
576
554
|
end
|
@@ -15,10 +15,7 @@ module ActiveRecord
|
|
15
15
|
when Date, DateTime
|
16
16
|
Java::oracle.sql.DATE.new(value.strftime("%Y-%m-%d %H:%M:%S"))
|
17
17
|
when Time
|
18
|
-
Java::java.sql.Timestamp.new(value.year-1900, value.month-1, value.day, value.hour, value.min, value.sec, value.usec * 1000)
|
19
|
-
when Java::JavaSql::Timestamp
|
20
|
-
# Returning value as it is likely this value was already type casted from Time to Java::JavaSql::Timestamp
|
21
|
-
value
|
18
|
+
Java::java.sql.Timestamp.new(value.year - 1900, value.month - 1, value.day, value.hour, value.min, value.sec, value.usec * 1000)
|
22
19
|
else
|
23
20
|
super
|
24
21
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "delegate"
|
2
2
|
|
3
3
|
begin
|
4
4
|
require "oci8"
|
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
# check ruby-oci8 version
|
13
13
|
required_oci8_version = [2, 2, 0]
|
14
|
-
oci8_version_ints = OCI8::VERSION.scan(/\d+/).map{|s| s.to_i}
|
14
|
+
oci8_version_ints = OCI8::VERSION.scan(/\d+/).map { |s| s.to_i }
|
15
15
|
if (oci8_version_ints <=> required_oci8_version) < 0
|
16
16
|
raise LoadError, "ERROR: ruby-oci8 version #{OCI8::VERSION} is too old. Please install ruby-oci8 version #{required_oci8_version.join('.')} or later."
|
17
17
|
end
|
@@ -98,9 +98,9 @@ module ActiveRecord
|
|
98
98
|
# and return :insert_id value
|
99
99
|
def exec_with_returning(sql)
|
100
100
|
cursor = @raw_connection.parse(sql)
|
101
|
-
cursor.bind_param(
|
101
|
+
cursor.bind_param(":insert_id", nil, Integer)
|
102
102
|
cursor.exec
|
103
|
-
cursor[
|
103
|
+
cursor[":insert_id"]
|
104
104
|
ensure
|
105
105
|
cursor.close rescue nil
|
106
106
|
end
|
@@ -115,7 +115,7 @@ module ActiveRecord
|
|
115
115
|
@raw_cursor = raw_cursor
|
116
116
|
end
|
117
117
|
|
118
|
-
def bind_params(
|
118
|
+
def bind_params(*bind_vars)
|
119
119
|
index = 1
|
120
120
|
bind_vars.flatten.each do |var|
|
121
121
|
if Hash === var
|
@@ -127,30 +127,16 @@ module ActiveRecord
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
def bind_param(position, value
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
MSG
|
139
|
-
end
|
140
|
-
|
141
|
-
if column && column.object_type?
|
142
|
-
@raw_cursor.bind_param(position, value, :named_type, column.sql_type)
|
130
|
+
def bind_param(position, value)
|
131
|
+
case value
|
132
|
+
when ActiveRecord::OracleEnhanced::Type::Raw
|
133
|
+
@raw_cursor.bind_param(position, ActiveRecord::ConnectionAdapters::OracleEnhanced::Quoting.encode_raw(value))
|
134
|
+
when ActiveModel::Type::Decimal
|
135
|
+
@raw_cursor.bind_param(position, BigDecimal.new(value.to_s))
|
136
|
+
when NilClass
|
137
|
+
@raw_cursor.bind_param(position, nil, String)
|
143
138
|
else
|
144
|
-
|
145
|
-
when ActiveRecord::OracleEnhanced::Type::Raw
|
146
|
-
@raw_cursor.bind_param(position, ActiveRecord::ConnectionAdapters::OracleEnhanced::Quoting.encode_raw(value))
|
147
|
-
when ActiveModel::Type::Decimal
|
148
|
-
@raw_cursor.bind_param(position, BigDecimal.new(value.to_s))
|
149
|
-
when NilClass
|
150
|
-
@raw_cursor.bind_param(position, nil, String)
|
151
|
-
else
|
152
|
-
@raw_cursor.bind_param(position, value)
|
153
|
-
end
|
139
|
+
@raw_cursor.bind_param(position, value)
|
154
140
|
end
|
155
141
|
end
|
156
142
|
|
@@ -170,7 +156,7 @@ module ActiveRecord
|
|
170
156
|
@raw_cursor.get_col_names
|
171
157
|
end
|
172
158
|
|
173
|
-
def fetch(options={})
|
159
|
+
def fetch(options = {})
|
174
160
|
if row = @raw_cursor.fetch
|
175
161
|
get_lob_value = options[:get_lob_value]
|
176
162
|
row.map do |col|
|
@@ -194,13 +180,13 @@ module ActiveRecord
|
|
194
180
|
# Ignore raw_rnum_ which is used to simulate LIMIT and OFFSET
|
195
181
|
cursor.get_col_names.each do |col_name|
|
196
182
|
col_name = oracle_downcase(col_name)
|
197
|
-
cols << col_name unless col_name ==
|
183
|
+
cols << col_name unless col_name == "raw_rnum_"
|
198
184
|
end
|
199
185
|
# Reuse the same hash for all rows
|
200
186
|
column_hash = {}
|
201
|
-
cols.each {|c| column_hash[c] = nil}
|
187
|
+
cols.each { |c| column_hash[c] = nil }
|
202
188
|
rows = []
|
203
|
-
get_lob_value = !(name ==
|
189
|
+
get_lob_value = !(name == "Writable Large Object")
|
204
190
|
|
205
191
|
while row = cursor.fetch
|
206
192
|
hash = column_hash.dup
|
@@ -223,7 +209,7 @@ module ActiveRecord
|
|
223
209
|
|
224
210
|
def describe(name)
|
225
211
|
# fall back to SELECT based describe if using database link
|
226
|
-
return super if name.to_s.include?(
|
212
|
+
return super if name.to_s.include?("@")
|
227
213
|
quoted_name = ActiveRecord::ConnectionAdapters::OracleEnhanced::Quoting.valid_table_name?(name) ? name : "\"#{name}\""
|
228
214
|
@raw_connection.describe(quoted_name)
|
229
215
|
rescue OCIException => e
|
@@ -261,17 +247,13 @@ module ActiveRecord
|
|
261
247
|
if get_lob_value
|
262
248
|
data = value.read || "" # if value.read returns nil, then we have an empty_clob() i.e. an empty string
|
263
249
|
# In Ruby 1.9.1 always change encoding to ASCII-8BIT for binaries
|
264
|
-
data.force_encoding(
|
250
|
+
data.force_encoding("ASCII-8BIT") if data.respond_to?(:force_encoding) && value.is_a?(OCI8::BLOB)
|
265
251
|
data
|
266
252
|
else
|
267
253
|
value
|
268
254
|
end
|
269
255
|
when Time, DateTime
|
270
|
-
|
271
|
-
value.to_date
|
272
|
-
else
|
273
|
-
create_time_with_default_timezone(value)
|
274
|
-
end
|
256
|
+
create_time_with_default_timezone(value)
|
275
257
|
else
|
276
258
|
value
|
277
259
|
end
|
@@ -283,32 +265,32 @@ module ActiveRecord
|
|
283
265
|
|
284
266
|
private
|
285
267
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
268
|
+
def date_without_time?(value)
|
269
|
+
case value
|
270
|
+
when OraDate
|
271
|
+
value.hour == 0 && value.minute == 0 && value.second == 0
|
272
|
+
else
|
273
|
+
value.hour == 0 && value.min == 0 && value.sec == 0
|
274
|
+
end
|
292
275
|
end
|
293
|
-
end
|
294
276
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
277
|
+
def create_time_with_default_timezone(value)
|
278
|
+
year, month, day, hour, min, sec, usec = case value
|
279
|
+
when Time
|
280
|
+
[value.year, value.month, value.day, value.hour, value.min, value.sec, value.usec]
|
281
|
+
when OraDate
|
282
|
+
[value.year, value.month, value.day, value.hour, value.minute, value.second, 0]
|
283
|
+
else
|
284
|
+
[value.year, value.month, value.day, value.hour, value.min, value.sec, 0]
|
285
|
+
end
|
286
|
+
# code from Time.time_with_datetime_fallback
|
287
|
+
begin
|
288
|
+
Time.send(Base.default_timezone, year, month, day, hour, min, sec, usec)
|
289
|
+
rescue
|
290
|
+
offset = Base.default_timezone.to_sym == :local ? ::DateTime.local_offset : 0
|
291
|
+
::DateTime.civil(year, month, day, hour, min, sec, offset)
|
292
|
+
end
|
310
293
|
end
|
311
|
-
end
|
312
294
|
end
|
313
295
|
|
314
296
|
# The OracleEnhancedOCIFactory factors out the code necessary to connect and
|
@@ -324,16 +306,16 @@ module ActiveRecord
|
|
324
306
|
privilege = config[:privilege] && config[:privilege].to_sym
|
325
307
|
async = config[:allow_concurrency]
|
326
308
|
prefetch_rows = config[:prefetch_rows] || 100
|
327
|
-
cursor_sharing = config[:cursor_sharing] ||
|
309
|
+
cursor_sharing = config[:cursor_sharing] || "force"
|
328
310
|
# get session time_zone from configuration or from TZ environment variable
|
329
|
-
time_zone = config[:time_zone] || ENV[
|
311
|
+
time_zone = config[:time_zone] || ENV["TZ"]
|
330
312
|
|
331
313
|
# using a connection string via DATABASE_URL
|
332
|
-
connection_string = if host ==
|
314
|
+
connection_string = if host == "connection-string"
|
333
315
|
database
|
334
316
|
# connection using host, port and database name
|
335
317
|
elsif host || port
|
336
|
-
host ||=
|
318
|
+
host ||= "localhost"
|
337
319
|
host = "[#{host}]" if host =~ /^[^\[].*:/ # IPv6
|
338
320
|
port ||= 1521
|
339
321
|
database = "/#{database}" unless database.match(/^\//)
|
@@ -372,8 +354,8 @@ class OCI8 #:nodoc:
|
|
372
354
|
def describe(name)
|
373
355
|
info = describe_table(name.to_s)
|
374
356
|
raise %Q{"DESC #{name}" failed} if info.nil?
|
375
|
-
if info.respond_to?
|
376
|
-
[info.obj_schema, info.obj_name,
|
357
|
+
if info.respond_to?(:obj_link) && info.obj_link
|
358
|
+
[info.obj_schema, info.obj_name, "@" + info.obj_link]
|
377
359
|
else
|
378
360
|
[info.obj_schema, info.obj_name]
|
379
361
|
end
|
@@ -402,7 +384,7 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
|
|
402
384
|
@active = true
|
403
385
|
@config = config
|
404
386
|
@factory = factory
|
405
|
-
@connection
|
387
|
+
@connection = @factory.new_connection @config
|
406
388
|
super @connection
|
407
389
|
end
|
408
390
|
|