activerecord-oracle_enhanced-adapter 1.4.3 → 5.2.0
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 +5 -5
- data/History.md +1162 -2
- data/README.md +567 -155
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +19 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +132 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +345 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +52 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +280 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +64 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +59 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +538 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +46 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +435 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +196 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +164 -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 +79 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +194 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +709 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +28 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +353 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +33 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +385 -1083
- data/lib/active_record/type/oracle_enhanced/boolean.rb +20 -0
- data/lib/active_record/type/oracle_enhanced/integer.rb +15 -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 +5 -13
- data/spec/active_record/connection_adapters/{oracle_enhanced_emulate_oracle_adapter_spec.rb → emulation/oracle_adapter_spec.rb} +5 -4
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +469 -0
- data/spec/active_record/connection_adapters/{oracle_enhanced_context_index_spec.rb → oracle_enhanced/context_index_spec.rb} +140 -128
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +112 -0
- data/spec/active_record/connection_adapters/{oracle_enhanced_dbms_output_spec.rb → oracle_enhanced/dbms_output_spec.rb} +13 -13
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +365 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +196 -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 +1433 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +478 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +385 -550
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +92 -1249
- data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +208 -0
- data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +139 -0
- data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +91 -0
- data/spec/active_record/oracle_enhanced/type/json_spec.rb +57 -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 +122 -0
- data/spec/active_record/oracle_enhanced/type/text_spec.rb +229 -0
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +75 -0
- data/spec/spec_config.yaml.template +11 -0
- data/spec/spec_helper.rb +100 -93
- 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 +105 -152
- data/.rspec +0 -2
- data/Gemfile +0 -52
- data/RUNNING_TESTS.md +0 -45
- data/Rakefile +0 -59
- data/activerecord-oracle_enhanced-adapter.gemspec +0 -130
- data/lib/active_record/connection_adapters/oracle_enhanced.rake +0 -105
- data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +0 -41
- data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +0 -121
- data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +0 -151
- data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +0 -119
- data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +0 -359
- data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +0 -25
- data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +0 -21
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +0 -46
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +0 -572
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +0 -497
- data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +0 -260
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +0 -227
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +0 -260
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +0 -428
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +0 -258
- data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +0 -294
- data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +0 -17
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +0 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +0 -334
- data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +0 -19
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +0 -113
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +0 -141
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +0 -378
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +0 -440
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +0 -1400
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +0 -339
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module OracleEnhanced
|
|
6
|
+
module DatabaseLimits
|
|
7
|
+
# maximum length of Oracle identifiers
|
|
8
|
+
IDENTIFIER_MAX_LENGTH = 30
|
|
9
|
+
|
|
10
|
+
def table_alias_length #:nodoc:
|
|
11
|
+
IDENTIFIER_MAX_LENGTH
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# the maximum length of a table name
|
|
15
|
+
def table_name_length
|
|
16
|
+
IDENTIFIER_MAX_LENGTH
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# the maximum length of a column name
|
|
20
|
+
def column_name_length
|
|
21
|
+
IDENTIFIER_MAX_LENGTH
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Returns the maximum allowed length for an index name. This
|
|
25
|
+
# limit is enforced by rails and Is less than or equal to
|
|
26
|
+
# <tt>index_name_length</tt>. The gap between
|
|
27
|
+
# <tt>index_name_length</tt> is to allow internal rails
|
|
28
|
+
# opreations to use prefixes in temporary opreations.
|
|
29
|
+
def allowed_index_name_length
|
|
30
|
+
index_name_length
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# the maximum length of an index name
|
|
34
|
+
# supported by this database
|
|
35
|
+
def index_name_length
|
|
36
|
+
IDENTIFIER_MAX_LENGTH
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# the maximum length of a sequence name
|
|
40
|
+
def sequence_name_length
|
|
41
|
+
IDENTIFIER_MAX_LENGTH
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# To avoid ORA-01795: maximum number of expressions in a list is 1000
|
|
45
|
+
# tell ActiveRecord to limit us to 1000 ids at a time
|
|
46
|
+
def in_clause_length
|
|
47
|
+
1000
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,280 @@
|
|
|
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
|
+
# Executes a SQL statement
|
|
12
|
+
def execute(sql, name = nil)
|
|
13
|
+
log(sql, name) { @connection.exec(sql) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def clear_cache!
|
|
17
|
+
@statements.clear
|
|
18
|
+
reload_type_map
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
|
22
|
+
type_casted_binds = type_casted_binds(binds)
|
|
23
|
+
|
|
24
|
+
log(sql, name, binds, type_casted_binds) do
|
|
25
|
+
cursor = nil
|
|
26
|
+
cached = false
|
|
27
|
+
if without_prepared_statement?(binds)
|
|
28
|
+
cursor = @connection.prepare(sql)
|
|
29
|
+
else
|
|
30
|
+
unless @statements.key? sql
|
|
31
|
+
@statements[sql] = @connection.prepare(sql)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
cursor = @statements[sql]
|
|
35
|
+
|
|
36
|
+
cursor.bind_params(type_casted_binds)
|
|
37
|
+
|
|
38
|
+
cached = true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
cursor.exec
|
|
42
|
+
|
|
43
|
+
if (name == "EXPLAIN") && sql =~ /^EXPLAIN/
|
|
44
|
+
res = true
|
|
45
|
+
else
|
|
46
|
+
columns = cursor.get_col_names.map do |col_name|
|
|
47
|
+
oracle_downcase(col_name)
|
|
48
|
+
end
|
|
49
|
+
rows = []
|
|
50
|
+
fetch_options = { get_lob_value: (name != "Writable Large Object") }
|
|
51
|
+
while row = cursor.fetch(fetch_options)
|
|
52
|
+
rows << row
|
|
53
|
+
end
|
|
54
|
+
res = ActiveRecord::Result.new(columns, rows)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
cursor.close unless cached
|
|
58
|
+
res
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def supports_explain?
|
|
63
|
+
true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def explain(arel, binds = [])
|
|
67
|
+
sql = "EXPLAIN PLAN FOR #{to_sql(arel, binds)}"
|
|
68
|
+
return if sql =~ /FROM all_/
|
|
69
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
70
|
+
exec_query(sql, "EXPLAIN", binds)
|
|
71
|
+
else
|
|
72
|
+
exec_query(sql, "EXPLAIN")
|
|
73
|
+
end
|
|
74
|
+
select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)", "EXPLAIN").join("\n")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# New method in ActiveRecord 3.1
|
|
78
|
+
# Will add RETURNING clause in case of trigger generated primary keys
|
|
79
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
|
80
|
+
unless id_value || pk == false || pk.nil? || pk.is_a?(Array)
|
|
81
|
+
sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO :returning_id"
|
|
82
|
+
(binds = binds.dup) << ActiveRecord::Relation::QueryAttribute.new("returning_id", nil, Type::OracleEnhanced::Integer.new)
|
|
83
|
+
end
|
|
84
|
+
super
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
|
88
|
+
pk = nil if id_value
|
|
89
|
+
super
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# New method in ActiveRecord 3.1
|
|
93
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
|
94
|
+
sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
|
|
95
|
+
type_casted_binds = type_casted_binds(binds)
|
|
96
|
+
|
|
97
|
+
log(sql, name, binds, type_casted_binds) do
|
|
98
|
+
cached = false
|
|
99
|
+
returning_id_col = returning_id_index = nil
|
|
100
|
+
if without_prepared_statement?(binds)
|
|
101
|
+
cursor = @connection.prepare(sql)
|
|
102
|
+
else
|
|
103
|
+
unless @statements.key?(sql)
|
|
104
|
+
@statements[sql] = @connection.prepare(sql)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
cursor = @statements[sql]
|
|
108
|
+
|
|
109
|
+
cursor.bind_params(type_casted_binds)
|
|
110
|
+
|
|
111
|
+
if sql =~ /:returning_id/
|
|
112
|
+
# it currently expects that returning_id comes last part of binds
|
|
113
|
+
returning_id_index = binds.size
|
|
114
|
+
cursor.bind_returning_param(returning_id_index, Integer)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
cached = true
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
cursor.exec_update
|
|
121
|
+
|
|
122
|
+
rows = []
|
|
123
|
+
if returning_id_index
|
|
124
|
+
returning_id = cursor.get_returning_param(returning_id_index, Integer).to_i
|
|
125
|
+
rows << [returning_id]
|
|
126
|
+
end
|
|
127
|
+
cursor.close unless cached
|
|
128
|
+
ActiveRecord::Result.new(returning_id_col || [], rows)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# New method in ActiveRecord 3.1
|
|
133
|
+
def exec_update(sql, name = nil, binds = [])
|
|
134
|
+
type_casted_binds = type_casted_binds(binds)
|
|
135
|
+
|
|
136
|
+
log(sql, name, binds, type_casted_binds) do
|
|
137
|
+
cached = false
|
|
138
|
+
if without_prepared_statement?(binds)
|
|
139
|
+
cursor = @connection.prepare(sql)
|
|
140
|
+
else
|
|
141
|
+
if @statements.key?(sql)
|
|
142
|
+
cursor = @statements[sql]
|
|
143
|
+
else
|
|
144
|
+
cursor = @statements[sql] = @connection.prepare(sql)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
cursor.bind_params(type_casted_binds)
|
|
148
|
+
|
|
149
|
+
cached = true
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
res = cursor.exec_update
|
|
153
|
+
cursor.close unless cached
|
|
154
|
+
res
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
alias :exec_delete :exec_update
|
|
159
|
+
|
|
160
|
+
def begin_db_transaction #:nodoc:
|
|
161
|
+
@connection.autocommit = false
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def transaction_isolation_levels
|
|
165
|
+
# Oracle database supports `READ COMMITTED` and `SERIALIZABLE`
|
|
166
|
+
# No read uncommitted nor repeatable read supppoted
|
|
167
|
+
# http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_10005.htm#SQLRF55422
|
|
168
|
+
{
|
|
169
|
+
read_committed: "READ COMMITTED",
|
|
170
|
+
serializable: "SERIALIZABLE"
|
|
171
|
+
}
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def begin_isolated_db_transaction(isolation)
|
|
175
|
+
begin_db_transaction
|
|
176
|
+
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def commit_db_transaction #:nodoc:
|
|
180
|
+
@connection.commit
|
|
181
|
+
ensure
|
|
182
|
+
@connection.autocommit = true
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def exec_rollback_db_transaction #:nodoc:
|
|
186
|
+
@connection.rollback
|
|
187
|
+
ensure
|
|
188
|
+
@connection.autocommit = true
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def create_savepoint(name = current_savepoint_name) #:nodoc:
|
|
192
|
+
execute("SAVEPOINT #{name}")
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def exec_rollback_to_savepoint(name = current_savepoint_name) #:nodoc:
|
|
196
|
+
execute("ROLLBACK TO #{name}")
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def release_savepoint(name = current_savepoint_name) #:nodoc:
|
|
200
|
+
# there is no RELEASE SAVEPOINT statement in Oracle
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Returns default sequence name for table.
|
|
204
|
+
# Will take all or first 26 characters of table name and append _seq suffix
|
|
205
|
+
def default_sequence_name(table_name, primary_key = nil)
|
|
206
|
+
table_name.to_s.gsub((/(^|\.)([\w$-]{1,#{sequence_name_length - 4}})([\w$-]*)$/), '\1\2_seq')
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Inserts the given fixture into the table. Overridden to properly handle lobs.
|
|
210
|
+
def insert_fixture(fixture, table_name) #:nodoc:
|
|
211
|
+
super
|
|
212
|
+
|
|
213
|
+
if ActiveRecord::Base.pluralize_table_names
|
|
214
|
+
klass = table_name.to_s.singularize.camelize
|
|
215
|
+
else
|
|
216
|
+
klass = table_name.to_s.camelize
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
klass = klass.constantize rescue nil
|
|
220
|
+
if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base)
|
|
221
|
+
write_lobs(table_name, klass, fixture, klass.lob_columns)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# fallback to non bulk fixture insert
|
|
226
|
+
def insert_fixtures(fixtures, table_name)
|
|
227
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
|
228
|
+
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
|
229
|
+
Consider using `insert_fixtures_set` for performance improvement.
|
|
230
|
+
MSG
|
|
231
|
+
fixtures.each do |fixture|
|
|
232
|
+
insert_fixture(fixture, table_name)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
|
237
|
+
disable_referential_integrity do
|
|
238
|
+
transaction(requires_new: true) do
|
|
239
|
+
tables_to_delete.each { |table| delete "DELETE FROM #{quote_table_name(table)}", "Fixture Delete" }
|
|
240
|
+
|
|
241
|
+
fixture_set.each do |table_name, rows|
|
|
242
|
+
rows.each { |row| insert_fixture(row, table_name) }
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Oracle Database does not support this feature
|
|
249
|
+
# Refer https://community.oracle.com/ideas/13845 and consider to vote
|
|
250
|
+
# if you need this feature.
|
|
251
|
+
def empty_insert_statement_value
|
|
252
|
+
raise NotImplementedError
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Writes LOB values from attributes for specified columns
|
|
256
|
+
def write_lobs(table_name, klass, attributes, columns) #:nodoc:
|
|
257
|
+
id = quote(attributes[klass.primary_key])
|
|
258
|
+
columns.each do |col|
|
|
259
|
+
value = attributes[col.name]
|
|
260
|
+
# changed sequence of next two lines - should check if value is nil before converting to yaml
|
|
261
|
+
next if value.blank?
|
|
262
|
+
if klass.attribute_types[col.name].is_a? Type::Serialized
|
|
263
|
+
value = klass.attribute_types[col.name].serialize(value)
|
|
264
|
+
end
|
|
265
|
+
uncached do
|
|
266
|
+
unless lob_record = select_one(<<-SQL.strip.gsub(/\s+/, " "), "Writable Large Object")
|
|
267
|
+
SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)}
|
|
268
|
+
WHERE #{quote_column_name(klass.primary_key)} = #{id} FOR UPDATE
|
|
269
|
+
SQL
|
|
270
|
+
raise ActiveRecord::RecordNotFound, "statement #{sql} returned no rows"
|
|
271
|
+
end
|
|
272
|
+
lob = lob_record[col.name]
|
|
273
|
+
@connection.write_lob(lob, value.to_s, col.type == :binary)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
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 e.message =~ /ORA-01920/ # 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
|
+
connection.execute "GRANT unlimited tablespace TO #{@config['username']}"
|
|
31
|
+
connection.execute "GRANT create session TO #{@config['username']}"
|
|
32
|
+
connection.execute "GRANT create table TO #{@config['username']}"
|
|
33
|
+
connection.execute "GRANT create view TO #{@config['username']}"
|
|
34
|
+
connection.execute "GRANT create sequence TO #{@config['username']}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def drop
|
|
38
|
+
establish_connection(@config)
|
|
39
|
+
connection.execute_structure_dump(connection.full_drop)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def purge
|
|
43
|
+
drop
|
|
44
|
+
connection.execute("PURGE RECYCLEBIN") rescue nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def structure_dump(filename, extra_flags)
|
|
48
|
+
establish_connection(@config)
|
|
49
|
+
File.open(filename, "w:utf-8") { |f| f << connection.structure_dump }
|
|
50
|
+
if @config["structure_dump"] == "db_stored_code"
|
|
51
|
+
File.open(filename, "a") { |f| f << connection.structure_dump_db_stored_code }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def structure_load(filename, extra_flags)
|
|
56
|
+
establish_connection(@config)
|
|
57
|
+
connection.execute_structure_dump(File.read(filename))
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
ActiveRecord::Tasks::DatabaseTasks.register_task(/(oci|oracle)/, ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::DatabaseTasks)
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
|
|
35
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
|
|
36
|
+
super
|
|
37
|
+
ensure
|
|
38
|
+
log_dbms_output if dbms_output_enabled?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def set_dbms_output_plsql_connection
|
|
42
|
+
raise OracleEnhanced::ConnectionException, "ruby-plsql gem is required for logging DBMS output" unless self.respond_to?(:plsql)
|
|
43
|
+
# do not reset plsql connection if it is the same (as resetting will clear PL/SQL metadata cache)
|
|
44
|
+
unless plsql(:dbms_output).connection && plsql(:dbms_output).connection.raw_connection == raw_connection
|
|
45
|
+
plsql(:dbms_output).connection = raw_connection
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def log_dbms_output
|
|
50
|
+
while true do
|
|
51
|
+
result = plsql(:dbms_output).sys.dbms_output.get_line(line: "", status: 0)
|
|
52
|
+
break unless result[:status] == 0
|
|
53
|
+
@logger.debug "DBMS_OUTPUT: #{result[:line]}" if @logger
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|