activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.0.beta1
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.
- 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
|
|