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.
Files changed (100) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +1162 -2
  3. data/README.md +567 -155
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +3 -1
  6. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +19 -0
  7. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +132 -0
  8. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +345 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +52 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +280 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +64 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +59 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +538 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +46 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +435 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +196 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +164 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +79 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +194 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +709 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +28 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +353 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +33 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +385 -1083
  29. data/lib/active_record/type/oracle_enhanced/boolean.rb +20 -0
  30. data/lib/active_record/type/oracle_enhanced/integer.rb +15 -0
  31. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  32. data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
  33. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  34. data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
  35. data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
  36. data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
  37. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  38. data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
  39. data/lib/activerecord-oracle_enhanced-adapter.rb +5 -13
  40. data/spec/active_record/connection_adapters/{oracle_enhanced_emulate_oracle_adapter_spec.rb → emulation/oracle_adapter_spec.rb} +5 -4
  41. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +469 -0
  42. data/spec/active_record/connection_adapters/{oracle_enhanced_context_index_spec.rb → oracle_enhanced/context_index_spec.rb} +140 -128
  43. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +112 -0
  44. data/spec/active_record/connection_adapters/{oracle_enhanced_dbms_output_spec.rb → oracle_enhanced/dbms_output_spec.rb} +13 -13
  45. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +365 -0
  46. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +196 -0
  47. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
  48. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1433 -0
  49. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +478 -0
  50. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +385 -550
  51. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +92 -1249
  52. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  53. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +208 -0
  54. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +139 -0
  55. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  56. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +91 -0
  57. data/spec/active_record/oracle_enhanced/type/json_spec.rb +57 -0
  58. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  59. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  60. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +122 -0
  61. data/spec/active_record/oracle_enhanced/type/text_spec.rb +229 -0
  62. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +75 -0
  63. data/spec/spec_config.yaml.template +11 -0
  64. data/spec/spec_helper.rb +100 -93
  65. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  66. data/spec/support/alter_system_user_password.sql +2 -0
  67. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  68. metadata +105 -152
  69. data/.rspec +0 -2
  70. data/Gemfile +0 -52
  71. data/RUNNING_TESTS.md +0 -45
  72. data/Rakefile +0 -59
  73. data/activerecord-oracle_enhanced-adapter.gemspec +0 -130
  74. data/lib/active_record/connection_adapters/oracle_enhanced.rake +0 -105
  75. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +0 -41
  76. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +0 -121
  77. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +0 -151
  78. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +0 -119
  79. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +0 -359
  80. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +0 -25
  81. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +0 -21
  82. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +0 -46
  83. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +0 -572
  84. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +0 -497
  85. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +0 -260
  86. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +0 -227
  87. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +0 -260
  88. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +0 -428
  89. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +0 -258
  90. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +0 -294
  91. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +0 -17
  92. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +0 -1
  93. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +0 -334
  94. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +0 -19
  95. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +0 -113
  96. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +0 -141
  97. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +0 -378
  98. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +0 -440
  99. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +0 -1400
  100. 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