activerecord-oracle_enhanced-adapter 8.1.0-java
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 +7 -0
- data/History.md +1971 -0
- data/License.txt +20 -0
- data/README.md +947 -0
- data/VERSION +1 -0
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +7 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +24 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +137 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +359 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +47 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +325 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +63 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +71 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +629 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +57 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +465 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +195 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +186 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +99 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +197 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +739 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +394 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +886 -0
- data/lib/active_record/type/oracle_enhanced/boolean.rb +19 -0
- data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/integer.rb +14 -0
- data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
- data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
- data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
- data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
- data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
- data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
- data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
- data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
- data/lib/arel/visitors/oracle.rb +216 -0
- data/lib/arel/visitors/oracle12.rb +121 -0
- data/lib/arel/visitors/oracle_common.rb +51 -0
- data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +24 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +40 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +589 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1318 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +485 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
- data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
- data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
- data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
- data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
- data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
- data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +101 -0
- data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
- data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
- data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
- data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
- data/spec/active_record/oracle_enhanced/type/text_spec.rb +295 -0
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +107 -0
- data/spec/spec_config.yaml.template +11 -0
- data/spec/spec_helper.rb +225 -0
- data/spec/support/alter_system_set_open_cursors.sql +1 -0
- data/spec/support/alter_system_user_password.sql +2 -0
- data/spec/support/create_oracle_enhanced_users.sql +31 -0
- metadata +181 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module OracleEnhanced
|
|
6
|
+
module DatabaseStatements
|
|
7
|
+
# DATABASE STATEMENTS ======================================
|
|
8
|
+
#
|
|
9
|
+
# see: abstract/database_statements.rb
|
|
10
|
+
|
|
11
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
|
12
|
+
:close, :declare, :fetch, :move, :set, :show
|
|
13
|
+
) # :nodoc:
|
|
14
|
+
private_constant :READ_QUERY
|
|
15
|
+
|
|
16
|
+
def write_query?(sql) # :nodoc:
|
|
17
|
+
!READ_QUERY.match?(sql)
|
|
18
|
+
rescue ArgumentError # Invalid encoding
|
|
19
|
+
!READ_QUERY.match?(sql.b)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Executes a SQL statement
|
|
23
|
+
def execute(...)
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Low level execution of a SQL statement on the connection returning adapter specific result object.
|
|
28
|
+
def raw_execute(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: false)
|
|
29
|
+
sql = preprocess_query(sql)
|
|
30
|
+
|
|
31
|
+
type_casted_binds = type_casted_binds(binds)
|
|
32
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
|
33
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
|
34
|
+
cursor = nil
|
|
35
|
+
cached = false
|
|
36
|
+
with_retry do
|
|
37
|
+
if binds.nil? || binds.empty?
|
|
38
|
+
cursor = conn.prepare(sql)
|
|
39
|
+
else
|
|
40
|
+
unless @statements.key? sql
|
|
41
|
+
@statements[sql] = conn.prepare(sql)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
cursor = @statements[sql]
|
|
45
|
+
cursor.bind_params(type_casted_binds)
|
|
46
|
+
|
|
47
|
+
cached = true
|
|
48
|
+
end
|
|
49
|
+
cursor.exec
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
columns = cursor.get_col_names.map do |col_name|
|
|
53
|
+
oracle_downcase(col_name)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
rows = []
|
|
57
|
+
if cursor.select_statement?
|
|
58
|
+
fetch_options = { get_lob_value: (name != "Writable Large Object") }
|
|
59
|
+
while row = cursor.fetch(fetch_options)
|
|
60
|
+
rows << row
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
affected_rows_count = cursor.row_count
|
|
65
|
+
|
|
66
|
+
cursor.close unless cached
|
|
67
|
+
|
|
68
|
+
{ columns: columns, rows: rows, affected_rows_count: affected_rows_count }
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def cast_result(result)
|
|
74
|
+
if result.nil?
|
|
75
|
+
ActiveRecord::Result.empty
|
|
76
|
+
else
|
|
77
|
+
ActiveRecord::Result.new(result[:columns], result[:rows])
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def affected_rows(result)
|
|
82
|
+
result[:affected_rows_count]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def supports_explain?
|
|
86
|
+
true
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def explain(arel, binds = [], options = [])
|
|
90
|
+
sql = "EXPLAIN PLAN FOR #{to_sql(arel, binds)}"
|
|
91
|
+
return if /FROM all_/.match?(sql)
|
|
92
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
93
|
+
exec_query(sql, "EXPLAIN", binds)
|
|
94
|
+
else
|
|
95
|
+
exec_query(sql, "EXPLAIN")
|
|
96
|
+
end
|
|
97
|
+
select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)", "EXPLAIN").join("\n")
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def build_explain_clause(options = [])
|
|
101
|
+
# Oracle does not have anything similar to "EXPLAIN ANALYZE"
|
|
102
|
+
# https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/EXPLAIN-PLAN.html#GUID-FD540872-4ED3-4936-96A2-362539931BA0
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# New method in ActiveRecord 3.1
|
|
106
|
+
# Will add RETURNING clause in case of trigger generated primary keys
|
|
107
|
+
def sql_for_insert(sql, pk, binds, _returning)
|
|
108
|
+
unless pk == false || pk.nil? || pk.is_a?(Array) || pk.is_a?(String)
|
|
109
|
+
sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO :returning_id"
|
|
110
|
+
(binds = binds.dup) << ActiveRecord::Relation::QueryAttribute.new("returning_id", nil, Type::OracleEnhanced::Integer.new)
|
|
111
|
+
end
|
|
112
|
+
super
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
|
|
116
|
+
pk = nil if id_value
|
|
117
|
+
Array(super || id_value)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# New method in ActiveRecord 3.1
|
|
121
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
|
|
122
|
+
sql, binds = sql_for_insert(sql, pk, binds, returning)
|
|
123
|
+
type_casted_binds = type_casted_binds(binds)
|
|
124
|
+
|
|
125
|
+
log(sql, name, binds, type_casted_binds) do
|
|
126
|
+
cached = false
|
|
127
|
+
cursor = nil
|
|
128
|
+
returning_id_col = returning_id_index = nil
|
|
129
|
+
with_retry do
|
|
130
|
+
if binds.nil? || binds.empty?
|
|
131
|
+
cursor = _connection.prepare(sql)
|
|
132
|
+
else
|
|
133
|
+
unless @statements.key?(sql)
|
|
134
|
+
@statements[sql] = _connection.prepare(sql)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
cursor = @statements[sql]
|
|
138
|
+
|
|
139
|
+
cursor.bind_params(type_casted_binds)
|
|
140
|
+
|
|
141
|
+
if /:returning_id/.match?(sql)
|
|
142
|
+
# it currently expects that returning_id comes last part of binds
|
|
143
|
+
returning_id_index = binds.size
|
|
144
|
+
cursor.bind_returning_param(returning_id_index, Integer)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
cached = true
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
cursor.exec_update
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
rows = []
|
|
154
|
+
if returning_id_index
|
|
155
|
+
returning_id = cursor.get_returning_param(returning_id_index, Integer).to_i
|
|
156
|
+
rows << [returning_id]
|
|
157
|
+
end
|
|
158
|
+
cursor.close unless cached
|
|
159
|
+
build_result(columns: returning_id_col || [], rows: rows)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# New method in ActiveRecord 3.1
|
|
164
|
+
def exec_update(sql, name = nil, binds = [])
|
|
165
|
+
type_casted_binds = type_casted_binds(binds)
|
|
166
|
+
|
|
167
|
+
log(sql, name, binds, type_casted_binds) do
|
|
168
|
+
with_retry do
|
|
169
|
+
cached = false
|
|
170
|
+
if binds.nil? || binds.empty?
|
|
171
|
+
cursor = _connection.prepare(sql)
|
|
172
|
+
else
|
|
173
|
+
if @statements.key?(sql)
|
|
174
|
+
cursor = @statements[sql]
|
|
175
|
+
else
|
|
176
|
+
cursor = @statements[sql] = _connection.prepare(sql)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
cursor.bind_params(type_casted_binds)
|
|
180
|
+
|
|
181
|
+
cached = true
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
res = cursor.exec_update
|
|
185
|
+
cursor.close unless cached
|
|
186
|
+
res
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
alias :exec_delete :exec_update
|
|
192
|
+
|
|
193
|
+
def returning_column_values(result)
|
|
194
|
+
result.rows.first
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def begin_db_transaction # :nodoc:
|
|
198
|
+
_connection.autocommit = false
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def transaction_isolation_levels
|
|
202
|
+
# Oracle database supports `READ COMMITTED` and `SERIALIZABLE`
|
|
203
|
+
# No read uncommitted nor repeatable read supppoted
|
|
204
|
+
# http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_10005.htm#SQLRF55422
|
|
205
|
+
{
|
|
206
|
+
read_committed: "READ COMMITTED",
|
|
207
|
+
serializable: "SERIALIZABLE"
|
|
208
|
+
}
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def begin_isolated_db_transaction(isolation)
|
|
212
|
+
begin_db_transaction
|
|
213
|
+
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def commit_db_transaction # :nodoc:
|
|
217
|
+
_connection.commit
|
|
218
|
+
ensure
|
|
219
|
+
_connection.autocommit = true
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def exec_rollback_db_transaction # :nodoc:
|
|
223
|
+
_connection.rollback
|
|
224
|
+
ensure
|
|
225
|
+
_connection.autocommit = true
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def create_savepoint(name = current_savepoint_name) # :nodoc:
|
|
229
|
+
execute("SAVEPOINT #{name}", "TRANSACTION")
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def exec_rollback_to_savepoint(name = current_savepoint_name) # :nodoc:
|
|
233
|
+
execute("ROLLBACK TO #{name}", "TRANSACTION")
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def release_savepoint(name = current_savepoint_name) # :nodoc:
|
|
237
|
+
# there is no RELEASE SAVEPOINT statement in Oracle
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Returns default sequence name for table.
|
|
241
|
+
# Will take all or first 26 characters of table name and append _seq suffix
|
|
242
|
+
def default_sequence_name(table_name, primary_key = nil)
|
|
243
|
+
table_name.to_s.gsub((/(^|\.)([\w$-]{1,#{sequence_name_length - 4}})([\w$-]*)$/), '\1\2_seq')
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Inserts the given fixture into the table. Overridden to properly handle lobs.
|
|
247
|
+
def insert_fixture(fixture, table_name) # :nodoc:
|
|
248
|
+
super
|
|
249
|
+
|
|
250
|
+
if ActiveRecord::Base.pluralize_table_names
|
|
251
|
+
klass = table_name.to_s.singularize.camelize
|
|
252
|
+
else
|
|
253
|
+
klass = table_name.to_s.camelize
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
klass = klass.constantize rescue nil
|
|
257
|
+
if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base)
|
|
258
|
+
write_lobs(table_name, klass, fixture, klass.lob_columns)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
|
263
|
+
disable_referential_integrity do
|
|
264
|
+
transaction(requires_new: true) do
|
|
265
|
+
tables_to_delete.each { |table| delete "DELETE FROM #{quote_table_name(table)}", "Fixture Delete" }
|
|
266
|
+
|
|
267
|
+
fixture_set.each do |table_name, rows|
|
|
268
|
+
rows.each { |row| insert_fixture(row, table_name) }
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Oracle Database does not support this feature
|
|
275
|
+
# Refer https://community.oracle.com/ideas/13845 and consider to vote
|
|
276
|
+
# if you need this feature.
|
|
277
|
+
def empty_insert_statement_value
|
|
278
|
+
raise NotImplementedError
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Writes LOB values from attributes for specified columns
|
|
282
|
+
def write_lobs(table_name, klass, attributes, columns) # :nodoc:
|
|
283
|
+
id = quote(attributes[klass.primary_key])
|
|
284
|
+
columns.each do |col|
|
|
285
|
+
value = attributes[col.name]
|
|
286
|
+
# changed sequence of next two lines - should check if value is nil before converting to yaml
|
|
287
|
+
next unless value
|
|
288
|
+
value = klass.attribute_types[col.name].serialize(value)
|
|
289
|
+
# value can be nil after serialization because ActiveRecord serializes [] and {} as nil
|
|
290
|
+
next unless value
|
|
291
|
+
uncached do
|
|
292
|
+
unless lob_record = select_one(sql = <<~SQL.squish, "Writable Large Object")
|
|
293
|
+
SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)}
|
|
294
|
+
WHERE #{quote_column_name(klass.primary_key)} = #{id} FOR UPDATE
|
|
295
|
+
SQL
|
|
296
|
+
raise ActiveRecord::RecordNotFound, "statement #{sql} returned no rows"
|
|
297
|
+
end
|
|
298
|
+
lob = lob_record[col.name]
|
|
299
|
+
_connection.write_lob(lob, value.to_s, col.type == :binary)
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
private
|
|
305
|
+
def with_retry
|
|
306
|
+
_connection.with_retry do
|
|
307
|
+
yield
|
|
308
|
+
rescue
|
|
309
|
+
@statements.clear
|
|
310
|
+
raise
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def handle_warnings(sql)
|
|
315
|
+
@notice_receiver_sql_warnings.each do |warning|
|
|
316
|
+
next if warning_ignored?(warning)
|
|
317
|
+
|
|
318
|
+
warning.sql = sql
|
|
319
|
+
ActiveRecord.db_warnings_action.call(warning)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record/base"
|
|
4
|
+
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
module ConnectionAdapters
|
|
7
|
+
class OracleEnhancedAdapter
|
|
8
|
+
class DatabaseTasks
|
|
9
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
|
10
|
+
|
|
11
|
+
def initialize(config)
|
|
12
|
+
@config = config
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
system_password = ENV.fetch("ORACLE_SYSTEM_PASSWORD") {
|
|
17
|
+
print "Please provide the SYSTEM password for your Oracle installation (set ORACLE_SYSTEM_PASSWORD to avoid this prompt)\n>"
|
|
18
|
+
$stdin.gets.strip
|
|
19
|
+
}
|
|
20
|
+
establish_connection(@config.merge(username: "SYSTEM", password: system_password))
|
|
21
|
+
begin
|
|
22
|
+
connection.execute "CREATE USER #{@config[:username]} IDENTIFIED BY #{@config[:password]}"
|
|
23
|
+
rescue => e
|
|
24
|
+
if /ORA-01920/.match?(e.message) # user name conflicts with another user or role name
|
|
25
|
+
connection.execute "ALTER USER #{@config[:username]} IDENTIFIED BY #{@config[:password]}"
|
|
26
|
+
else
|
|
27
|
+
raise e
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
OracleEnhancedAdapter.permissions.each do |permission|
|
|
32
|
+
connection.execute "GRANT #{permission} TO #{@config[:username]}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def drop
|
|
37
|
+
establish_connection(@config)
|
|
38
|
+
connection.execute_structure_dump(connection.full_drop)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def purge
|
|
42
|
+
drop
|
|
43
|
+
connection.execute("PURGE RECYCLEBIN") rescue nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def structure_dump(filename, extra_flags)
|
|
47
|
+
establish_connection(@config)
|
|
48
|
+
File.open(filename, "w:utf-8") { |f| f << connection.structure_dump }
|
|
49
|
+
if @config[:structure_dump] == "db_stored_code"
|
|
50
|
+
File.open(filename, "a") { |f| f << connection.structure_dump_db_stored_code }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def structure_load(filename, extra_flags)
|
|
55
|
+
establish_connection(@config)
|
|
56
|
+
connection.execute_structure_dump(File.read(filename))
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
ActiveRecord::Tasks::DatabaseTasks.register_task(/(oci|oracle)/, ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::DatabaseTasks)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module OracleEnhanced
|
|
6
|
+
module DbmsOutput
|
|
7
|
+
# DBMS_OUTPUT =============================================
|
|
8
|
+
#
|
|
9
|
+
# PL/SQL in Oracle uses dbms_output for logging print statements
|
|
10
|
+
# These methods stick that output into the Rails log so Ruby and PL/SQL
|
|
11
|
+
# code can can be debugged together in a single application
|
|
12
|
+
|
|
13
|
+
# Maximum DBMS_OUTPUT buffer size
|
|
14
|
+
DBMS_OUTPUT_BUFFER_SIZE = 10000 # can be 1-1000000
|
|
15
|
+
|
|
16
|
+
# Turn DBMS_Output logging on
|
|
17
|
+
def enable_dbms_output
|
|
18
|
+
set_dbms_output_plsql_connection
|
|
19
|
+
@enable_dbms_output = true
|
|
20
|
+
plsql(:dbms_output).sys.dbms_output.enable(DBMS_OUTPUT_BUFFER_SIZE)
|
|
21
|
+
end
|
|
22
|
+
# Turn DBMS_Output logging off
|
|
23
|
+
def disable_dbms_output
|
|
24
|
+
set_dbms_output_plsql_connection
|
|
25
|
+
@enable_dbms_output = false
|
|
26
|
+
plsql(:dbms_output).sys.dbms_output.disable
|
|
27
|
+
end
|
|
28
|
+
# Is DBMS_Output logging enabled?
|
|
29
|
+
def dbms_output_enabled?
|
|
30
|
+
@enable_dbms_output
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block)
|
|
35
|
+
instrumenter.instrument(
|
|
36
|
+
"sql.active_record",
|
|
37
|
+
sql: sql,
|
|
38
|
+
name: name,
|
|
39
|
+
binds: binds,
|
|
40
|
+
type_casted_binds: type_casted_binds,
|
|
41
|
+
statement_name: statement_name,
|
|
42
|
+
async: async,
|
|
43
|
+
connection: self,
|
|
44
|
+
&block
|
|
45
|
+
)
|
|
46
|
+
rescue => e
|
|
47
|
+
# FIXME: raise ex.set_query(sql, binds)
|
|
48
|
+
raise translate_exception_class(e, sql, binds)
|
|
49
|
+
ensure
|
|
50
|
+
log_dbms_output if dbms_output_enabled?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def set_dbms_output_plsql_connection
|
|
54
|
+
raise OracleEnhanced::ConnectionException, "ruby-plsql gem is required for logging DBMS output" unless self.respond_to?(:plsql)
|
|
55
|
+
# do not reset plsql connection if it is the same (as resetting will clear PL/SQL metadata cache)
|
|
56
|
+
unless plsql(:dbms_output).connection && plsql(:dbms_output).connection.raw_connection == raw_connection
|
|
57
|
+
plsql(:dbms_output).connection = raw_connection
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def log_dbms_output
|
|
62
|
+
while true do
|
|
63
|
+
result = plsql(:dbms_output).sys.dbms_output.get_line(line: "", status: 0)
|
|
64
|
+
break unless result[:status] == 0
|
|
65
|
+
@logger.debug "DBMS_OUTPUT: #{result[:line]}" if @logger
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|