activerecord-oracle_enhanced-adapter 1.5.5 → 1.5.6
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/History.md +25 -0
- data/README.md +5 -4
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +3 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +28 -274
- data/lib/active_record/connection_adapters/oracle_enhanced_database_statements.rb +262 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_database_tasks.rb +7 -6
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +0 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +9 -7
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +2 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +4 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +3 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +0 -8
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +64 -25
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +6 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +12 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +25 -0
- metadata +4 -3
@@ -0,0 +1,262 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module OracleEnhancedDatabaseStatements
|
4
|
+
# DATABASE STATEMENTS ======================================
|
5
|
+
#
|
6
|
+
# see: abstract/database_statements.rb
|
7
|
+
|
8
|
+
# Executes a SQL statement
|
9
|
+
def execute(sql, name = nil)
|
10
|
+
log(sql, name) { @connection.exec(sql) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def substitute_at(column, index)
|
14
|
+
Arel::Nodes::BindParam.new (":a#{index + 1}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear_cache!
|
18
|
+
@statements.clear
|
19
|
+
end
|
20
|
+
|
21
|
+
def exec_query(sql, name = 'SQL', binds = [])
|
22
|
+
type_casted_binds = binds.map { |col, val|
|
23
|
+
[col, type_cast(val, col)]
|
24
|
+
}
|
25
|
+
log(sql, name, type_casted_binds) do
|
26
|
+
cursor = nil
|
27
|
+
cached = false
|
28
|
+
if without_prepared_statement?(binds)
|
29
|
+
cursor = @connection.prepare(sql)
|
30
|
+
else
|
31
|
+
unless @statements.key? sql
|
32
|
+
@statements[sql] = @connection.prepare(sql)
|
33
|
+
end
|
34
|
+
|
35
|
+
cursor = @statements[sql]
|
36
|
+
|
37
|
+
binds.each_with_index do |bind, i|
|
38
|
+
col, val = bind
|
39
|
+
cursor.bind_param(i + 1, type_cast(val, col), col)
|
40
|
+
end
|
41
|
+
|
42
|
+
cached = true
|
43
|
+
end
|
44
|
+
|
45
|
+
cursor.exec
|
46
|
+
|
47
|
+
if name == 'EXPLAIN' and sql =~ /^EXPLAIN/
|
48
|
+
res = true
|
49
|
+
else
|
50
|
+
columns = cursor.get_col_names.map do |col_name|
|
51
|
+
@connection.oracle_downcase(col_name)
|
52
|
+
end
|
53
|
+
rows = []
|
54
|
+
fetch_options = {:get_lob_value => (name != 'Writable Large Object')}
|
55
|
+
while row = cursor.fetch(fetch_options)
|
56
|
+
rows << row
|
57
|
+
end
|
58
|
+
res = ActiveRecord::Result.new(columns, rows)
|
59
|
+
end
|
60
|
+
|
61
|
+
cursor.close unless cached
|
62
|
+
res
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def supports_statement_cache?
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def supports_explain?
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def explain(arel, binds = [])
|
75
|
+
sql = "EXPLAIN PLAN FOR #{to_sql(arel, binds)}"
|
76
|
+
return if sql =~ /FROM all_/
|
77
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
78
|
+
exec_query(sql, 'EXPLAIN', binds)
|
79
|
+
else
|
80
|
+
exec_query(sql, 'EXPLAIN')
|
81
|
+
end
|
82
|
+
select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)", 'EXPLAIN').join("\n")
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns an array of arrays containing the field values.
|
86
|
+
# Order is the same as that returned by #columns.
|
87
|
+
def select_rows(sql, name = nil, binds = [])
|
88
|
+
exec_query(sql, name, binds).rows
|
89
|
+
end
|
90
|
+
|
91
|
+
# Executes an INSERT statement and returns the new record's ID
|
92
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
93
|
+
# if primary key value is already prefetched from sequence
|
94
|
+
# or if there is no primary key
|
95
|
+
if id_value || pk.nil?
|
96
|
+
execute(sql, name)
|
97
|
+
return id_value
|
98
|
+
end
|
99
|
+
|
100
|
+
sql_with_returning = sql + @connection.returning_clause(quote_column_name(pk))
|
101
|
+
log(sql, name) do
|
102
|
+
@connection.exec_with_returning(sql_with_returning)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
protected :insert_sql
|
106
|
+
|
107
|
+
# New method in ActiveRecord 3.1
|
108
|
+
# Will add RETURNING clause in case of trigger generated primary keys
|
109
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
110
|
+
unless id_value || pk.nil? || (defined?(CompositePrimaryKeys) && pk.kind_of?(CompositePrimaryKeys::CompositeKeys))
|
111
|
+
sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO :returning_id"
|
112
|
+
returning_id_col = OracleEnhancedColumn.new("returning_id", nil, "number", true, "dual", :integer, true, true)
|
113
|
+
(binds = binds.dup) << [returning_id_col, nil]
|
114
|
+
end
|
115
|
+
[sql, binds]
|
116
|
+
end
|
117
|
+
|
118
|
+
# New method in ActiveRecord 3.1
|
119
|
+
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
120
|
+
type_casted_binds = binds.map { |col, val|
|
121
|
+
[col, type_cast(val, col)]
|
122
|
+
}
|
123
|
+
log(sql, name, type_casted_binds) do
|
124
|
+
returning_id_col = returning_id_index = nil
|
125
|
+
if without_prepared_statement?(binds)
|
126
|
+
cursor = @connection.prepare(sql)
|
127
|
+
else
|
128
|
+
unless @statements.key? (sql)
|
129
|
+
@statements[sql] = @connection.prepare(sql)
|
130
|
+
end
|
131
|
+
|
132
|
+
cursor = @statements[sql]
|
133
|
+
|
134
|
+
binds.each_with_index do |bind, i|
|
135
|
+
col, val = bind
|
136
|
+
if col.returning_id?
|
137
|
+
returning_id_col = [col]
|
138
|
+
returning_id_index = i + 1
|
139
|
+
cursor.bind_returning_param(returning_id_index, Integer)
|
140
|
+
else
|
141
|
+
cursor.bind_param(i + 1, type_cast(val, col), col)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
cursor.exec_update
|
147
|
+
|
148
|
+
rows = []
|
149
|
+
if returning_id_index
|
150
|
+
returning_id = cursor.get_returning_param(returning_id_index, Integer)
|
151
|
+
rows << [returning_id]
|
152
|
+
end
|
153
|
+
ActiveRecord::Result.new(returning_id_col || [], rows)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# New method in ActiveRecord 3.1
|
158
|
+
def exec_update(sql, name, binds)
|
159
|
+
log(sql, name, binds) do
|
160
|
+
cached = false
|
161
|
+
if without_prepared_statement?(binds)
|
162
|
+
cursor = @connection.prepare(sql)
|
163
|
+
else
|
164
|
+
cursor = if @statements.key?(sql)
|
165
|
+
@statements[sql]
|
166
|
+
else
|
167
|
+
@statements[sql] = @connection.prepare(sql)
|
168
|
+
end
|
169
|
+
|
170
|
+
binds.each_with_index do |bind, i|
|
171
|
+
col, val = bind
|
172
|
+
cursor.bind_param(i + 1, type_cast(val, col), col)
|
173
|
+
end
|
174
|
+
cached = true
|
175
|
+
end
|
176
|
+
|
177
|
+
res = cursor.exec_update
|
178
|
+
cursor.close unless cached
|
179
|
+
res
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
alias :exec_delete :exec_update
|
184
|
+
|
185
|
+
def begin_db_transaction #:nodoc:
|
186
|
+
@connection.autocommit = false
|
187
|
+
end
|
188
|
+
|
189
|
+
def transaction_isolation_levels
|
190
|
+
# Oracle database supports `READ COMMITTED` and `SERIALIZABLE`
|
191
|
+
# No read uncommitted nor repeatable read supppoted
|
192
|
+
# http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_10005.htm#SQLRF55422
|
193
|
+
{
|
194
|
+
read_committed: "READ COMMITTED",
|
195
|
+
serializable: "SERIALIZABLE"
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
def begin_isolated_db_transaction(isolation)
|
200
|
+
begin_db_transaction
|
201
|
+
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
202
|
+
end
|
203
|
+
|
204
|
+
def commit_db_transaction #:nodoc:
|
205
|
+
@connection.commit
|
206
|
+
ensure
|
207
|
+
@connection.autocommit = true
|
208
|
+
end
|
209
|
+
|
210
|
+
def rollback_db_transaction #:nodoc:
|
211
|
+
@connection.rollback
|
212
|
+
ensure
|
213
|
+
@connection.autocommit = true
|
214
|
+
end
|
215
|
+
|
216
|
+
def create_savepoint(name = current_savepoint_name) #:nodoc:
|
217
|
+
execute("SAVEPOINT #{current_savepoint_name}")
|
218
|
+
end
|
219
|
+
|
220
|
+
def rollback_to_savepoint(name = current_savepoint_name) #:nodoc:
|
221
|
+
execute("ROLLBACK TO #{current_savepoint_name}")
|
222
|
+
end
|
223
|
+
|
224
|
+
def release_savepoint(name = current_savepoint_name) #:nodoc:
|
225
|
+
# there is no RELEASE SAVEPOINT statement in Oracle
|
226
|
+
end
|
227
|
+
|
228
|
+
# Returns default sequence name for table.
|
229
|
+
# Will take all or first 26 characters of table name and append _seq suffix
|
230
|
+
def default_sequence_name(table_name, primary_key = nil)
|
231
|
+
table_name.to_s.gsub /(^|\.)([\w$-]{1,#{sequence_name_length-4}})([\w$-]*)$/, '\1\2_seq'
|
232
|
+
end
|
233
|
+
|
234
|
+
# Inserts the given fixture into the table. Overridden to properly handle lobs.
|
235
|
+
def insert_fixture(fixture, table_name) #:nodoc:
|
236
|
+
super
|
237
|
+
|
238
|
+
if ActiveRecord::Base.pluralize_table_names
|
239
|
+
klass = table_name.to_s.singularize.camelize
|
240
|
+
else
|
241
|
+
klass = table_name.to_s.camelize
|
242
|
+
end
|
243
|
+
|
244
|
+
klass = klass.constantize rescue nil
|
245
|
+
if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base)
|
246
|
+
write_lobs(table_name, klass, fixture, klass.lob_columns)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
private
|
251
|
+
|
252
|
+
def select(sql, name = nil, binds = [])
|
253
|
+
exec_query(sql, name, binds)
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
|
261
|
+
include ActiveRecord::ConnectionAdapters::OracleEnhancedDatabaseStatements
|
262
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_record/base'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
class OracleEnhancedAdapter
|
@@ -9,8 +11,10 @@ module ActiveRecord
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def create
|
12
|
-
|
13
|
-
|
14
|
+
system_password = ENV.fetch('ORACLE_SYSTEM_PASSWORD') {
|
15
|
+
print "Please provide the SYSTEM password for your Oracle installation (set ORACLE_SYSTEM_PASSWORD to avoid this prompt)\n>"
|
16
|
+
$stdin.gets.strip
|
17
|
+
}
|
14
18
|
establish_connection(@config.merge('username' => 'SYSTEM', 'password' => system_password))
|
15
19
|
begin
|
16
20
|
connection.execute "CREATE USER #{@config['username']} IDENTIFIED BY #{@config['password']}"
|
@@ -24,6 +28,7 @@ module ActiveRecord
|
|
24
28
|
connection.execute "GRANT unlimited tablespace TO #{@config['username']}"
|
25
29
|
connection.execute "GRANT create session TO #{@config['username']}"
|
26
30
|
connection.execute "GRANT create table TO #{@config['username']}"
|
31
|
+
connection.execute "GRANT create view TO #{@config['username']}"
|
27
32
|
connection.execute "GRANT create sequence TO #{@config['username']}"
|
28
33
|
end
|
29
34
|
|
@@ -40,9 +45,6 @@ module ActiveRecord
|
|
40
45
|
def structure_dump(filename)
|
41
46
|
establish_connection(@config)
|
42
47
|
File.open(filename, 'w:utf-8') { |f| f << connection.structure_dump }
|
43
|
-
if connection.supports_migrations?
|
44
|
-
File.open(filename, 'a') { |f| f << connection.dump_schema_information }
|
45
|
-
end
|
46
48
|
if @config['structure_dump'] == 'db_stored_code'
|
47
49
|
File.open(filename, 'a') { |f| f << connection.structure_dump_db_stored_code }
|
48
50
|
end
|
@@ -58,4 +60,3 @@ module ActiveRecord
|
|
58
60
|
end
|
59
61
|
|
60
62
|
ActiveRecord::Tasks::DatabaseTasks.register_task(/(oci|oracle)/, ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::DatabaseTasks)
|
61
|
-
|
@@ -26,8 +26,6 @@ begin
|
|
26
26
|
# check any compatible JDBC driver in the priority order
|
27
27
|
ojdbc_jars.any? do |ojdbc_jar|
|
28
28
|
if File.exists?(file_path = File.join(dir, ojdbc_jar))
|
29
|
-
puts "WARNING: JDK #{java_version} is not officially supported by #{ojdbc_jar}" if java_version >= '1.8'
|
30
|
-
puts "See http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#01_03 for supported versions"
|
31
29
|
require file_path
|
32
30
|
true
|
33
31
|
end
|
@@ -2,9 +2,11 @@ require 'delegate'
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require "oci8"
|
5
|
-
rescue LoadError
|
6
|
-
# OCI8 driver is unavailable.
|
7
|
-
raise LoadError, "ERROR:
|
5
|
+
rescue LoadError => e
|
6
|
+
# OCI8 driver is unavailable or failed to load a required library.
|
7
|
+
raise LoadError, "ERROR: '#{e.message}'. "\
|
8
|
+
"ActiveRecord oracle_enhanced adapter could not load ruby-oci8 library. "\
|
9
|
+
"You may need install ruby-oci8 gem."
|
8
10
|
end
|
9
11
|
|
10
12
|
# check ruby-oci8 version
|
@@ -275,7 +277,7 @@ module ActiveRecord
|
|
275
277
|
value.hour == 0 && value.min == 0 && value.sec == 0
|
276
278
|
end
|
277
279
|
end
|
278
|
-
|
280
|
+
|
279
281
|
def create_time_with_default_timezone(value)
|
280
282
|
year, month, day, hour, min, sec, usec = case value
|
281
283
|
when Time
|
@@ -295,7 +297,7 @@ module ActiveRecord
|
|
295
297
|
end
|
296
298
|
|
297
299
|
end
|
298
|
-
|
300
|
+
|
299
301
|
# The OracleEnhancedOCIFactory factors out the code necessary to connect and
|
300
302
|
# configure an Oracle/OCI connection.
|
301
303
|
class OracleEnhancedOCIFactory #:nodoc:
|
@@ -342,8 +344,8 @@ module ActiveRecord
|
|
342
344
|
conn
|
343
345
|
end
|
344
346
|
end
|
345
|
-
|
346
|
-
|
347
|
+
|
348
|
+
|
347
349
|
end
|
348
350
|
end
|
349
351
|
|
@@ -117,6 +117,8 @@ module ActiveRecord
|
|
117
117
|
super(name)
|
118
118
|
seq_name = options[:sequence_name] || default_sequence_name(name)
|
119
119
|
execute "DROP SEQUENCE #{quote_table_name(seq_name)}" rescue nil
|
120
|
+
rescue ActiveRecord::StatementInvalid => e
|
121
|
+
raise e unless options[:if_exists]
|
120
122
|
ensure
|
121
123
|
clear_table_columns_cache(name)
|
122
124
|
self.all_schema_indexes = nil
|
@@ -45,7 +45,7 @@ module ActiveRecord #:nodoc:
|
|
45
45
|
col << "(#{column['data_precision'].to_i}"
|
46
46
|
col << ",#{column['data_scale'].to_i}" if !column['data_scale'].nil?
|
47
47
|
col << ')'
|
48
|
-
elsif column['data_type'].include?('CHAR')
|
48
|
+
elsif column['data_type'].include?('CHAR') || column['data_type'] == 'RAW'
|
49
49
|
length = column['char_used'] == 'C' ? column['char_length'].to_i : column['data_length'].to_i
|
50
50
|
col << "(#{length})"
|
51
51
|
end
|
@@ -61,7 +61,7 @@ module ActiveRecord #:nodoc:
|
|
61
61
|
col << "(#{column['data_precision'].to_i}"
|
62
62
|
col << ",#{column['data_scale'].to_i}" if !column['data_scale'].nil?
|
63
63
|
col << ')'
|
64
|
-
elsif column['data_type'].include?('CHAR')
|
64
|
+
elsif column['data_type'].include?('CHAR') || column['data_type'] == 'RAW'
|
65
65
|
length = column['char_used'] == 'C' ? column['char_length'].to_i : column['data_length'].to_i
|
66
66
|
col << "(#{length})"
|
67
67
|
end
|
@@ -172,8 +172,8 @@ module ActiveRecord #:nodoc:
|
|
172
172
|
select_all("SELECT owner, synonym_name, table_name, table_owner
|
173
173
|
FROM all_synonyms
|
174
174
|
WHERE owner = SYS_CONTEXT('userenv', 'session_user') ").each do |synonym|
|
175
|
-
structure << "CREATE OR REPLACE #{synonym['owner'] == 'PUBLIC' ? 'PUBLIC' : '' } SYNONYM #{synonym['synonym_name']}
|
176
|
-
|
175
|
+
structure << "CREATE OR REPLACE #{synonym['owner'] == 'PUBLIC' ? 'PUBLIC' : '' } SYNONYM #{synonym['synonym_name']}
|
176
|
+
FOR #{synonym['table_owner']}.#{synonym['table_name']}"
|
177
177
|
end
|
178
178
|
|
179
179
|
join_with_statement_token(structure)
|
@@ -240,7 +240,6 @@ module ActiveRecord #:nodoc:
|
|
240
240
|
|
241
241
|
def execute_structure_dump(string)
|
242
242
|
string.split(STATEMENT_TOKEN).each do |ddl|
|
243
|
-
ddl.chop! if ddl[-1,1] == ';'
|
244
243
|
execute(ddl) unless ddl.blank?
|
245
244
|
end
|
246
245
|
end
|
@@ -461,6 +461,9 @@ describe "OracleEnhancedAdapter" do
|
|
461
461
|
@conn.tables.should include("CamelCase")
|
462
462
|
end
|
463
463
|
|
464
|
+
it "properly quotes database links" do
|
465
|
+
@conn.quote_table_name('asdf@some.link').should eq('"ASDF"@"SOME.LINK"')
|
466
|
+
end
|
464
467
|
end
|
465
468
|
|
466
469
|
describe "access table over database link" do
|
@@ -174,8 +174,6 @@ describe "OracleEnhancedAdapter context index" do
|
|
174
174
|
describe "on multiple tables" do
|
175
175
|
before(:all) do
|
176
176
|
@conn = ActiveRecord::Base.connection
|
177
|
-
@oracle12c = !! @conn.select_value(
|
178
|
-
"select * from product_component_version where product like 'Oracle%' and to_number(substr(version,1,2)) = 12")
|
179
177
|
create_tables
|
180
178
|
class ::Post < ActiveRecord::Base
|
181
179
|
has_many :comments, dependent: :destroy
|
@@ -200,7 +198,6 @@ describe "OracleEnhancedAdapter context index" do
|
|
200
198
|
end
|
201
199
|
|
202
200
|
it "should create multiple table index with specified main index column" do
|
203
|
-
pending "It always fails when Oracle 12c 12.1.0 used." if @oracle12c
|
204
201
|
@conn.add_context_index :posts,
|
205
202
|
[:title, :body,
|
206
203
|
# specify aliases always with AS keyword
|
@@ -218,7 +215,6 @@ describe "OracleEnhancedAdapter context index" do
|
|
218
215
|
end
|
219
216
|
|
220
217
|
it "should create multiple table index with specified main index column (when subquery has newlines)" do
|
221
|
-
pending "It always fails when Oracle 12c 12.1.0 used." if @oracle12c
|
222
218
|
@conn.add_context_index :posts,
|
223
219
|
[:title, :body,
|
224
220
|
# specify aliases always with AS keyword
|
@@ -381,9 +377,6 @@ describe "OracleEnhancedAdapter context index" do
|
|
381
377
|
|
382
378
|
describe "with table prefix and suffix" do
|
383
379
|
before(:all) do
|
384
|
-
@conn = ActiveRecord::Base.connection
|
385
|
-
@oracle12c = !! @conn.select_value(
|
386
|
-
"select * from product_component_version where product like 'Oracle%' and to_number(substr(version,1,2)) = 12")
|
387
380
|
ActiveRecord::Base.table_name_prefix = 'xxx_'
|
388
381
|
ActiveRecord::Base.table_name_suffix = '_xxx'
|
389
382
|
create_tables
|
@@ -408,7 +401,6 @@ describe "OracleEnhancedAdapter context index" do
|
|
408
401
|
end
|
409
402
|
|
410
403
|
it "should dump definition of multiple table index with options" do
|
411
|
-
pending "It always fails when Oracle 12c 12.1.0 used." if @oracle12c
|
412
404
|
options = {
|
413
405
|
name: 'xxx_post_and_comments_i',
|
414
406
|
index_column: :all_text, index_column_trigger_on: :updated_at,
|