activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.2
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 +206 -4
- data/README.md +37 -1
- data/VERSION +1 -1
- 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 +37 -27
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +56 -71
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +0 -7
- 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 +14 -43
- 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 +150 -160
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +95 -133
- 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 +66 -101
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +290 -533
- 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/json.rb +8 -0
- 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/active_record/oracle_enhanced/type/timestamptz.rb +23 -0
- data/lib/activerecord-oracle_enhanced-adapter.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +55 -162
- 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 +44 -42
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +250 -357
- 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 +115 -124
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +2 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +68 -72
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +64 -80
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +223 -329
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +18 -20
- data/spec/spec_config.yaml.template +11 -0
- data/spec/spec_helper.rb +59 -59
- data/spec/support/alter_system_user_password.sql +2 -0
- data/spec/support/create_oracle_enhanced_users.sql +31 -0
- metadata +25 -25
- data/.rspec +0 -2
- data/Gemfile +0 -22
- data/RUNNING_TESTS.md +0 -83
- data/Rakefile +0 -45
- data/activerecord-oracle_enhanced-adapter.gemspec +0 -94
- data/lib/active_record/connection_adapters/oracle_enhanced/cpk.rb +0 -19
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +0 -113
@@ -74,9 +74,9 @@ module ActiveRecord
|
|
74
74
|
def add_context_index(table_name, column_name, options = {})
|
75
75
|
self.all_schema_indexes = nil
|
76
76
|
column_names = Array(column_name)
|
77
|
-
index_name = options[:name] || index_name(table_name, :
|
77
|
+
index_name = options[:name] || index_name(table_name, column: options[:index_column] || column_names,
|
78
78
|
# CONEXT index name max length is 25
|
79
|
-
:
|
79
|
+
identifier_max_length: 25)
|
80
80
|
|
81
81
|
quoted_column_name = quote_column_name(options[:index_column] || column_names.first)
|
82
82
|
if options[:index_column_trigger_on]
|
@@ -129,10 +129,10 @@ module ActiveRecord
|
|
129
129
|
def remove_context_index(table_name, options = {})
|
130
130
|
self.all_schema_indexes = nil
|
131
131
|
unless Hash === options # if column names passed as argument
|
132
|
-
options = {:
|
132
|
+
options = { column: Array(options) }
|
133
133
|
end
|
134
134
|
index_name = options[:name] || index_name(table_name,
|
135
|
-
:
|
135
|
+
column: options[:index_column] || options[:column], identifier_max_length: 25)
|
136
136
|
execute "DROP INDEX #{index_name}"
|
137
137
|
drop_ctx_preference(default_datastore_name(index_name))
|
138
138
|
drop_ctx_preference(default_storage_name(index_name))
|
@@ -143,17 +143,17 @@ module ActiveRecord
|
|
143
143
|
|
144
144
|
private
|
145
145
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
146
|
+
def create_datastore_procedure(table_name, procedure_name, column_names, options)
|
147
|
+
quoted_table_name = quote_table_name(table_name)
|
148
|
+
select_queries, column_names = column_names.partition { |c| c.to_s =~ /^\s*SELECT\s+/i }
|
149
|
+
select_queries = select_queries.map { |s| s.strip.gsub(/\s+/, " ") }
|
150
|
+
keys, selected_columns = parse_select_queries(select_queries)
|
151
|
+
quoted_column_names = (column_names + keys).map { |col| quote_column_name(col) }
|
152
|
+
execute compress_lines(<<-SQL)
|
153
153
|
CREATE OR REPLACE PROCEDURE #{quote_table_name(procedure_name)}
|
154
154
|
(p_rowid IN ROWID,
|
155
155
|
p_clob IN OUT NOCOPY CLOB) IS
|
156
|
-
-- add_context_index_parameters #{(column_names+select_queries).inspect}#{!options.empty? ? ', ' << options.inspect[1..-2] : ''}
|
156
|
+
-- add_context_index_parameters #{(column_names + select_queries).inspect}#{!options.empty? ? ', ' << options.inspect[1..-2] : ''}
|
157
157
|
#{
|
158
158
|
selected_columns.map do |cols|
|
159
159
|
cols.map do |col|
|
@@ -170,171 +170,171 @@ module ActiveRecord
|
|
170
170
|
#{
|
171
171
|
(column_names.map do |col|
|
172
172
|
col = col.to_s
|
173
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+2}, '<#{col}>');\n" <<
|
173
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length + 2}, '<#{col}>');\n" <<
|
174
174
|
"IF LENGTH(r1.#{col}) > 0 THEN\n" <<
|
175
175
|
"DBMS_LOB.WRITEAPPEND(p_clob, LENGTH(r1.#{col}), r1.#{col});\n" <<
|
176
176
|
"END IF;\n" <<
|
177
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+3}, '</#{col}>');\n"
|
177
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length + 3}, '</#{col}>');\n"
|
178
178
|
end.join) <<
|
179
179
|
(selected_columns.zip(select_queries).map do |cols, query|
|
180
180
|
(cols.map do |col|
|
181
181
|
"l_#{col} := '';\n"
|
182
182
|
end.join) <<
|
183
183
|
"FOR r2 IN (\n" <<
|
184
|
-
query.gsub(/:(\w+)/,"r1.\\1") << "\n) LOOP\n" <<
|
184
|
+
query.gsub(/:(\w+)/, "r1.\\1") << "\n) LOOP\n" <<
|
185
185
|
(cols.map do |col|
|
186
186
|
"l_#{col} := l_#{col} || r2.#{col} || CHR(10);\n"
|
187
187
|
end.join) <<
|
188
188
|
"END LOOP;\n" <<
|
189
189
|
(cols.map do |col|
|
190
190
|
col = col.to_s
|
191
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+2}, '<#{col}>');\n" <<
|
191
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length + 2}, '<#{col}>');\n" <<
|
192
192
|
"IF LENGTH(l_#{col}) > 0 THEN\n" <<
|
193
193
|
"DBMS_LOB.WRITEAPPEND(p_clob, LENGTH(l_#{col}), l_#{col});\n" <<
|
194
194
|
"END IF;\n" <<
|
195
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+3}, '</#{col}>');\n"
|
195
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length + 3}, '</#{col}>');\n"
|
196
196
|
end.join)
|
197
197
|
end.join)
|
198
198
|
}
|
199
199
|
END LOOP;
|
200
200
|
END;
|
201
201
|
SQL
|
202
|
-
|
202
|
+
end
|
203
203
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
204
|
+
def parse_select_queries(select_queries)
|
205
|
+
keys = []
|
206
|
+
selected_columns = []
|
207
|
+
select_queries.each do |query|
|
208
|
+
# get primary or foreign keys like :id or :something_id
|
209
|
+
keys << (query.scan(/:\w+/).map { |k| k[1..-1].downcase.to_sym })
|
210
|
+
select_part = query.scan(/^select\s.*\sfrom/i).first
|
211
|
+
selected_columns << select_part.scan(/\sas\s+(\w+)/i).map { |c| c.first }
|
212
|
+
end
|
213
|
+
[keys.flatten.uniq, selected_columns]
|
212
214
|
end
|
213
|
-
[keys.flatten.uniq, selected_columns]
|
214
|
-
end
|
215
215
|
|
216
|
-
|
217
|
-
|
218
|
-
|
216
|
+
def create_datastore_preference(datastore_name, procedure_name)
|
217
|
+
drop_ctx_preference(datastore_name)
|
218
|
+
execute <<-SQL
|
219
219
|
BEGIN
|
220
220
|
CTX_DDL.CREATE_PREFERENCE('#{datastore_name}', 'USER_DATASTORE');
|
221
221
|
CTX_DDL.SET_ATTRIBUTE('#{datastore_name}', 'PROCEDURE', '#{procedure_name}');
|
222
222
|
END;
|
223
223
|
SQL
|
224
|
-
|
224
|
+
end
|
225
225
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
226
|
+
def create_storage_preference(storage_name, tablespace)
|
227
|
+
drop_ctx_preference(storage_name)
|
228
|
+
sql = "BEGIN\nCTX_DDL.CREATE_PREFERENCE('#{storage_name}', 'BASIC_STORAGE');\n"
|
229
|
+
["I_TABLE_CLAUSE", "K_TABLE_CLAUSE", "R_TABLE_CLAUSE",
|
230
|
+
"N_TABLE_CLAUSE", "I_INDEX_CLAUSE", "P_TABLE_CLAUSE"].each do |clause|
|
231
|
+
default_clause = case clause
|
232
|
+
when "R_TABLE_CLAUSE"; "LOB(DATA) STORE AS (CACHE) "
|
233
|
+
when "I_INDEX_CLAUSE"; "COMPRESS 2 "
|
234
|
+
else ""
|
235
|
+
end
|
236
|
+
sql << "CTX_DDL.SET_ATTRIBUTE('#{storage_name}', '#{clause}', '#{default_clause}TABLESPACE #{tablespace}');\n"
|
235
237
|
end
|
236
|
-
sql << "
|
238
|
+
sql << "END;\n"
|
239
|
+
execute sql
|
237
240
|
end
|
238
|
-
sql << "END;\n"
|
239
|
-
execute sql
|
240
|
-
end
|
241
241
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
242
|
+
def create_lexer_preference(lexer_name, lexer_type, options)
|
243
|
+
drop_ctx_preference(lexer_name)
|
244
|
+
sql = "BEGIN\nCTX_DDL.CREATE_PREFERENCE('#{lexer_name}', '#{lexer_type}');\n"
|
245
|
+
options.each do |key, value|
|
246
|
+
plsql_value = case value
|
247
|
+
when String; "'#{value}'"
|
248
|
+
when true; "'YES'"
|
249
|
+
when false; "'NO'"
|
250
|
+
when nil; "NULL"
|
251
|
+
else value
|
252
|
+
end
|
253
|
+
sql << "CTX_DDL.SET_ATTRIBUTE('#{lexer_name}', '#{key}', #{plsql_value});\n"
|
252
254
|
end
|
253
|
-
sql << "
|
255
|
+
sql << "END;\n"
|
256
|
+
execute sql
|
254
257
|
end
|
255
|
-
sql << "END;\n"
|
256
|
-
execute sql
|
257
|
-
end
|
258
258
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
259
|
+
def create_wordlist_preference(wordlist_name, wordlist_type, options)
|
260
|
+
drop_ctx_preference(wordlist_name)
|
261
|
+
sql = "BEGIN\nCTX_DDL.CREATE_PREFERENCE('#{wordlist_name}', '#{wordlist_type}');\n"
|
262
|
+
options.each do |key, value|
|
263
|
+
plsql_value = case value
|
264
|
+
when String; "'#{value}'"
|
265
|
+
when true; "'YES'"
|
266
|
+
when false; "'NO'"
|
267
|
+
when nil; "NULL"
|
268
|
+
else value
|
269
|
+
end
|
270
|
+
sql << "CTX_DDL.SET_ATTRIBUTE('#{wordlist_name}', '#{key}', #{plsql_value});\n"
|
269
271
|
end
|
270
|
-
sql << "
|
272
|
+
sql << "END;\n"
|
273
|
+
execute sql
|
271
274
|
end
|
272
|
-
sql << "END;\n"
|
273
|
-
execute sql
|
274
|
-
end
|
275
275
|
|
276
|
-
|
277
|
-
|
278
|
-
|
276
|
+
def drop_ctx_preference(preference_name)
|
277
|
+
execute "BEGIN CTX_DDL.DROP_PREFERENCE('#{preference_name}'); END;" rescue nil
|
278
|
+
end
|
279
279
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
280
|
+
def create_index_column_trigger(table_name, index_name, index_column, index_column_source)
|
281
|
+
trigger_name = default_index_column_trigger_name(index_name)
|
282
|
+
columns = Array(index_column_source)
|
283
|
+
quoted_column_names = columns.map { |col| quote_column_name(col) }.join(", ")
|
284
|
+
execute compress_lines(<<-SQL)
|
285
285
|
CREATE OR REPLACE TRIGGER #{quote_table_name(trigger_name)}
|
286
286
|
BEFORE UPDATE OF #{quoted_column_names} ON #{quote_table_name(table_name)} FOR EACH ROW
|
287
287
|
BEGIN
|
288
288
|
:new.#{quote_column_name(index_column)} := '1';
|
289
289
|
END;
|
290
290
|
SQL
|
291
|
-
|
291
|
+
end
|
292
292
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
293
|
+
def drop_index_column_trigger(index_name)
|
294
|
+
trigger_name = default_index_column_trigger_name(index_name)
|
295
|
+
execute "DROP TRIGGER #{quote_table_name(trigger_name)}" rescue nil
|
296
|
+
end
|
297
297
|
|
298
|
-
|
299
|
-
|
300
|
-
|
298
|
+
def default_datastore_procedure(index_name)
|
299
|
+
"#{index_name}_prc"
|
300
|
+
end
|
301
301
|
|
302
|
-
|
303
|
-
|
304
|
-
|
302
|
+
def default_datastore_name(index_name)
|
303
|
+
"#{index_name}_dst"
|
304
|
+
end
|
305
305
|
|
306
|
-
|
307
|
-
|
308
|
-
|
306
|
+
def default_storage_name(index_name)
|
307
|
+
"#{index_name}_sto"
|
308
|
+
end
|
309
309
|
|
310
|
-
|
311
|
-
|
312
|
-
|
310
|
+
def default_index_column_trigger_name(index_name)
|
311
|
+
"#{index_name}_trg"
|
312
|
+
end
|
313
313
|
|
314
|
-
|
315
|
-
|
316
|
-
|
314
|
+
def default_lexer_name(index_name)
|
315
|
+
"#{index_name}_lex"
|
316
|
+
end
|
317
317
|
|
318
|
-
|
319
|
-
|
320
|
-
|
318
|
+
def default_wordlist_name(index_name)
|
319
|
+
"#{index_name}_wl"
|
320
|
+
end
|
321
321
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
322
|
+
module BaseClassMethods
|
323
|
+
# Declare that model table has context index defined.
|
324
|
+
# As a result <tt>contains</tt> class scope method is defined.
|
325
|
+
def has_context_index
|
326
|
+
extend ContextIndexClassMethods
|
327
|
+
end
|
327
328
|
end
|
328
|
-
end
|
329
329
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
330
|
+
module ContextIndexClassMethods
|
331
|
+
# Add context index condition.
|
332
|
+
def contains(column, query, options = {})
|
333
|
+
score_label = options[:label].to_i || 1
|
334
|
+
where("CONTAINS(#{connection.quote_table_name(column)}, ?, #{score_label}) > 0", query).
|
335
|
+
order("SCORE(#{score_label}) DESC")
|
336
|
+
end
|
336
337
|
end
|
337
|
-
end
|
338
338
|
end
|
339
339
|
end
|
340
340
|
end
|
@@ -16,10 +16,10 @@ module ActiveRecord
|
|
16
16
|
reload_type_map
|
17
17
|
end
|
18
18
|
|
19
|
-
def exec_query(sql, name =
|
20
|
-
type_casted_binds = binds
|
19
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
20
|
+
type_casted_binds = type_casted_binds(binds)
|
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,34 +69,35 @@ 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
|
86
80
|
# Will add RETURNING clause in case of trigger generated primary keys
|
87
81
|
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
88
|
-
unless id_value || pk == false || pk.nil? ||
|
82
|
+
unless id_value || pk == false || pk.nil? || pk.is_a?(Array)
|
89
83
|
sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO :returning_id"
|
90
84
|
(binds = binds.dup) << ActiveRecord::Relation::QueryAttribute.new("returning_id", nil, ActiveRecord::OracleEnhanced::Type::Integer.new)
|
91
85
|
end
|
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)
|
97
|
-
|
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
|
+
type_casted_binds = type_casted_binds(binds)
|
98
98
|
|
99
|
-
log(sql, name, binds) do
|
99
|
+
log(sql, name, binds, type_casted_binds) do
|
100
|
+
cached = false
|
100
101
|
returning_id_col = returning_id_index = nil
|
101
102
|
if without_prepared_statement?(binds)
|
102
103
|
cursor = @connection.prepare(sql)
|
@@ -115,6 +116,7 @@ module ActiveRecord
|
|
115
116
|
cursor.bind_returning_param(returning_id_index, Integer) if ORACLE_ENHANCED_CONNECTION == :jdbc
|
116
117
|
end
|
117
118
|
|
119
|
+
cached = true
|
118
120
|
end
|
119
121
|
|
120
122
|
cursor.exec_update
|
@@ -124,24 +126,25 @@ module ActiveRecord
|
|
124
126
|
returning_id = cursor.get_returning_param(returning_id_index, Integer).to_i
|
125
127
|
rows << [returning_id]
|
126
128
|
end
|
129
|
+
cursor.close unless cached
|
127
130
|
ActiveRecord::Result.new(returning_id_col || [], rows)
|
128
131
|
end
|
129
132
|
end
|
130
133
|
|
131
134
|
# New method in ActiveRecord 3.1
|
132
|
-
def exec_update(sql, name, binds)
|
133
|
-
type_casted_binds = binds
|
135
|
+
def exec_update(sql, name = nil, binds = [])
|
136
|
+
type_casted_binds = type_casted_binds(binds)
|
134
137
|
|
135
|
-
log(sql, name, binds) do
|
138
|
+
log(sql, name, binds, type_casted_binds) do
|
136
139
|
cached = false
|
137
140
|
if without_prepared_statement?(binds)
|
138
141
|
cursor = @connection.prepare(sql)
|
139
142
|
else
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
143
|
+
if @statements.key?(sql)
|
144
|
+
cursor = @statements[sql]
|
145
|
+
else
|
146
|
+
cursor = @statements[sql] = @connection.prepare(sql)
|
147
|
+
end
|
145
148
|
|
146
149
|
cursor.bind_params(type_casted_binds)
|
147
150
|
|
@@ -202,7 +205,7 @@ module ActiveRecord
|
|
202
205
|
# Returns default sequence name for table.
|
203
206
|
# Will take all or first 26 characters of table name and append _seq suffix
|
204
207
|
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')
|
208
|
+
table_name.to_s.gsub((/(^|\.)([\w$-]{1,#{sequence_name_length - 4}})([\w$-]*)$/), '\1\2_seq')
|
206
209
|
end
|
207
210
|
|
208
211
|
# Inserts the given fixture into the table. Overridden to properly handle lobs.
|
@@ -220,6 +223,13 @@ module ActiveRecord
|
|
220
223
|
write_lobs(table_name, klass, fixture, klass.lob_columns)
|
221
224
|
end
|
222
225
|
end
|
226
|
+
|
227
|
+
# Oracle Database does not support this feature
|
228
|
+
# Refer https://community.oracle.com/ideas/13845 and consider to vote
|
229
|
+
# if you need this feature.
|
230
|
+
def empty_insert_statement_value
|
231
|
+
raise NotImplementedError
|
232
|
+
end
|
223
233
|
end
|
224
234
|
end
|
225
235
|
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
|