activerecord-oracle_enhanced-adapter 7.2.1-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.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +1977 -0
  3. data/License.txt +20 -0
  4. data/README.md +863 -0
  5. data/VERSION +1 -0
  6. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +7 -0
  7. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +24 -0
  8. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +137 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +344 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +47 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +295 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +63 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +71 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +561 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +45 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +457 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +195 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +186 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +94 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +99 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +197 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +738 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +366 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +34 -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 +865 -0
  29. data/lib/active_record/type/oracle_enhanced/boolean.rb +19 -0
  30. data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
  31. data/lib/active_record/type/oracle_enhanced/integer.rb +14 -0
  32. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  33. data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
  34. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  35. data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
  36. data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
  37. data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
  38. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  39. data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
  40. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  41. data/lib/arel/visitors/oracle.rb +216 -0
  42. data/lib/arel/visitors/oracle12.rb +121 -0
  43. data/lib/arel/visitors/oracle_common.rb +51 -0
  44. data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +24 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +36 -0
  46. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +574 -0
  47. data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
  48. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
  49. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
  50. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
  51. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
  52. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
  53. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1289 -0
  54. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +474 -0
  55. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
  56. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
  57. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  58. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
  59. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
  60. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  61. data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
  62. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
  63. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  64. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +99 -0
  65. data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
  66. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +56 -0
  67. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  68. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
  69. data/spec/active_record/oracle_enhanced/type/text_spec.rb +244 -0
  70. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +77 -0
  71. data/spec/spec_config.yaml.template +11 -0
  72. data/spec/spec_helper.rb +214 -0
  73. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  74. data/spec/support/alter_system_user_password.sql +2 -0
  75. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  76. metadata +177 -0
@@ -0,0 +1,366 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord # :nodoc:
4
+ module ConnectionAdapters # :nodoc:
5
+ module OracleEnhanced # :nodoc:
6
+ module StructureDump # :nodoc:
7
+ # Statements separator used in structure dump to allow loading of structure dump also with SQL*Plus
8
+ STATEMENT_TOKEN = "\n\n/\n\n"
9
+
10
+ def structure_dump # :nodoc:
11
+ sequences = select(<<~SQL.squish, "SCHEMA")
12
+ SELECT
13
+ sequence_name, min_value, max_value, increment_by, order_flag, cycle_flag
14
+ FROM all_sequences
15
+ where sequence_owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
16
+ SQL
17
+
18
+ structure = sequences.map do |result|
19
+ "CREATE SEQUENCE #{quote_table_name(result["sequence_name"])} MINVALUE #{result["min_value"]} MAXVALUE #{result["max_value"]} INCREMENT BY #{result["increment_by"]} #{result["order_flag"] == 'Y' ? "ORDER" : "NOORDER"} #{result["cycle_flag"] == 'Y' ? "CYCLE" : "NOCYCLE"}"
20
+ end
21
+ tables = select_values(<<~SQL.squish, "SCHEMA")
22
+ SELECT table_name FROM all_tables t
23
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
24
+ AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv
25
+ WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
26
+ AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl
27
+ WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
28
+ ORDER BY 1
29
+ SQL
30
+ tables.each do |table_name|
31
+ virtual_columns = virtual_columns_for(table_name) if supports_virtual_columns?
32
+ ddl = +"CREATE#{ ' GLOBAL TEMPORARY' if temporary_table?(table_name)} TABLE \"#{table_name}\" (\n"
33
+ columns = select_all(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
34
+ SELECT column_name, data_type, data_length, char_used, char_length,
35
+ data_precision, data_scale, data_default, nullable
36
+ FROM all_tab_columns
37
+ WHERE table_name = :table_name
38
+ AND owner = SYS_CONTEXT('userenv', 'current_schema')
39
+ ORDER BY column_id
40
+ SQL
41
+ cols = columns.map do |row|
42
+ if (v = virtual_columns.find { |col| col["column_name"] == row["column_name"] })
43
+ structure_dump_virtual_column(row, v["data_default"])
44
+ else
45
+ structure_dump_column(row)
46
+ end
47
+ end
48
+ ddl << cols.map { |col| " #{col}" }.join(",\n")
49
+ ddl << structure_dump_primary_key(table_name)
50
+ ddl << "\n)"
51
+ structure << ddl
52
+ structure << structure_dump_indexes(table_name)
53
+ structure << structure_dump_unique_keys(table_name)
54
+ structure << structure_dump_table_comments(table_name)
55
+ structure << structure_dump_column_comments(table_name)
56
+ end
57
+
58
+ join_with_statement_token(structure) <<
59
+ structure_dump_fk_constraints <<
60
+ structure_dump_views
61
+ end
62
+
63
+ def structure_dump_column(column) # :nodoc:
64
+ col = +"\"#{column['column_name']}\" #{column['data_type']}"
65
+ if (column["data_type"] == "NUMBER") && !column["data_precision"].nil?
66
+ col << "(#{column['data_precision'].to_i}"
67
+ col << ",#{column['data_scale'].to_i}" if !column["data_scale"].nil?
68
+ col << ")"
69
+ elsif column["data_type"].include?("CHAR") || column["data_type"] == "RAW"
70
+ length = column["char_used"] == "C" ? column["char_length"].to_i : column["data_length"].to_i
71
+ col << "(#{length})"
72
+ end
73
+ col << " DEFAULT #{column['data_default']}" if !column["data_default"].nil?
74
+ col << " NOT NULL" if column["nullable"] == "N"
75
+ col
76
+ end
77
+
78
+ def structure_dump_virtual_column(column, data_default) # :nodoc:
79
+ data_default = data_default.delete('"')
80
+ col = +"\"#{column['column_name']}\" #{column['data_type']}"
81
+ if (column["data_type"] == "NUMBER") && !column["data_precision"].nil?
82
+ col << "(#{column['data_precision'].to_i}"
83
+ col << ",#{column['data_scale'].to_i}" if !column["data_scale"].nil?
84
+ col << ")"
85
+ elsif column["data_type"].include?("CHAR") || column["data_type"] == "RAW"
86
+ length = column["char_used"] == "C" ? column["char_length"].to_i : column["data_length"].to_i
87
+ col << "(#{length})"
88
+ end
89
+ col << " GENERATED ALWAYS AS (#{data_default}) VIRTUAL"
90
+ end
91
+
92
+ def structure_dump_primary_key(table) # :nodoc:
93
+ opts = { name: "", cols: [] }
94
+ pks = select_all(<<~SQL.squish, "SCHEMA")
95
+ SELECT a.constraint_name, a.column_name, a.position
96
+ FROM all_cons_columns a
97
+ JOIN all_constraints c
98
+ ON a.constraint_name = c.constraint_name
99
+ WHERE c.table_name = '#{table.upcase}'
100
+ AND c.constraint_type = 'P'
101
+ AND a.owner = c.owner
102
+ AND c.owner = SYS_CONTEXT('userenv', 'current_schema')
103
+ SQL
104
+ pks.each do |row|
105
+ opts[:name] = row["constraint_name"]
106
+ opts[:cols][row["position"] - 1] = row["column_name"]
107
+ end
108
+ opts[:cols].length > 0 ? ",\n CONSTRAINT #{opts[:name]} PRIMARY KEY (#{opts[:cols].join(',')})" : ""
109
+ end
110
+
111
+ def structure_dump_unique_keys(table) # :nodoc:
112
+ keys = {}
113
+ uks = select_all(<<~SQL.squish, "SCHEMA")
114
+ SELECT a.constraint_name, a.column_name, a.position
115
+ FROM all_cons_columns a
116
+ JOIN all_constraints c
117
+ ON a.constraint_name = c.constraint_name
118
+ WHERE c.table_name = '#{table.upcase}'
119
+ AND c.constraint_type = 'U'
120
+ AND a.owner = c.owner
121
+ AND c.owner = SYS_CONTEXT('userenv', 'current_schema')
122
+ SQL
123
+ uks.each do |uk|
124
+ keys[uk["constraint_name"]] ||= []
125
+ keys[uk["constraint_name"]][uk["position"] - 1] = uk["column_name"]
126
+ end
127
+ keys.map do |k, v|
128
+ "ALTER TABLE #{table.upcase} ADD CONSTRAINT #{k} UNIQUE (#{v.join(',')})"
129
+ end
130
+ end
131
+
132
+ def structure_dump_indexes(table_name) # :nodoc:
133
+ indexes(table_name).map do |options|
134
+ column_names = options.columns
135
+ options = { name: options.name, unique: options.unique }
136
+ index_name = index_name(table_name, column: column_names)
137
+ if Hash === options # legacy support, since this param was a string
138
+ index_type = options[:unique] ? "UNIQUE" : ""
139
+ index_name = options[:name] || index_name
140
+ else
141
+ index_type = options
142
+ end
143
+ quoted_column_names = column_names.map { |e| quote_column_name_or_expression(e) }.join(", ")
144
+ "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
145
+ end
146
+ end
147
+
148
+ def structure_dump_fk_constraints # :nodoc:
149
+ foreign_keys = select_all(<<~SQL.squish, "SCHEMA")
150
+ SELECT table_name FROM all_tables
151
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
152
+ SQL
153
+ fks = foreign_keys.map do |table|
154
+ if respond_to?(:foreign_keys) && (foreign_keys = foreign_keys(table["table_name"])).any?
155
+ foreign_keys.map do |fk|
156
+ sql = +"ALTER TABLE #{quote_table_name(fk.from_table)} ADD CONSTRAINT #{quote_column_name(fk.options[:name])} "
157
+ sql << "#{foreign_key_definition(fk.to_table, fk.options)}"
158
+ end
159
+ end
160
+ end.flatten.compact
161
+ join_with_statement_token(fks)
162
+ end
163
+
164
+ def structure_dump_table_comments(table_name)
165
+ comments = []
166
+ comment = table_comment(table_name)
167
+
168
+ unless comment.nil?
169
+ comments << "COMMENT ON TABLE #{quote_table_name(table_name)} IS '#{quote_string(comment)}'"
170
+ end
171
+
172
+ join_with_statement_token(comments)
173
+ end
174
+
175
+ def structure_dump_column_comments(table_name)
176
+ comments = []
177
+ columns = select_values(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
178
+ SELECT column_name FROM all_tab_columns
179
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
180
+ AND table_name = :table_name ORDER BY column_id
181
+ SQL
182
+
183
+ columns.each do |column|
184
+ comment = column_comment(table_name, column)
185
+ unless comment.nil?
186
+ comments << "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column)} IS '#{quote_string(comment)}'"
187
+ end
188
+ end
189
+
190
+ join_with_statement_token(comments)
191
+ end
192
+
193
+ def foreign_key_definition(to_table, options = {}) # :nodoc:
194
+ column_sql = quote_column_name(options[:column] || "#{to_table.to_s.singularize}_id")
195
+ references = options[:references] ? options[:references].first : nil
196
+ references_sql = quote_column_name(options[:primary_key] || references || "id")
197
+
198
+ sql = "FOREIGN KEY (#{column_sql}) REFERENCES #{quote_table_name(to_table)}(#{references_sql})"
199
+
200
+ case options[:dependent]
201
+ when :nullify
202
+ sql << " ON DELETE SET NULL"
203
+ when :delete
204
+ sql << " ON DELETE CASCADE"
205
+ end
206
+ sql
207
+ end
208
+
209
+ # Extract all stored procedures, packages, synonyms.
210
+ def structure_dump_db_stored_code # :nodoc:
211
+ structure = []
212
+ all_source = select_all(<<~SQL.squish, "SCHEMA")
213
+ SELECT DISTINCT name, type
214
+ FROM all_source
215
+ WHERE type IN ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TRIGGER', 'TYPE')
216
+ AND name NOT LIKE 'BIN$%'
217
+ AND owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY type
218
+ SQL
219
+ all_source.each do |source|
220
+ ddl = +"CREATE OR REPLACE \n"
221
+ texts = select_all(<<~SQL.squish, "all source at structure dump", [bind_string("source_name", source["name"]), bind_string("source_type", source["type"])])
222
+ SELECT text
223
+ FROM all_source
224
+ WHERE name = :source_name
225
+ AND type = :source_type
226
+ AND owner = SYS_CONTEXT('userenv', 'current_schema')
227
+ ORDER BY line
228
+ SQL
229
+ texts.each do |row|
230
+ ddl << row["text"]
231
+ end
232
+ ddl << ";" unless ddl.strip[-1, 1] == ";"
233
+ structure << ddl
234
+ end
235
+
236
+ # export synonyms
237
+ structure << structure_dump_synonyms
238
+
239
+ join_with_statement_token(structure)
240
+ end
241
+
242
+ def structure_dump_views # :nodoc:
243
+ structure = []
244
+ views = select_all(<<~SQL.squish, "SCHEMA")
245
+ SELECT view_name, text FROM all_views
246
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY view_name ASC
247
+ SQL
248
+ views.each do |view|
249
+ structure << "CREATE OR REPLACE FORCE VIEW #{view['view_name']} AS\n #{view['text']}"
250
+ end
251
+ join_with_statement_token(structure)
252
+ end
253
+
254
+ def structure_dump_synonyms # :nodoc:
255
+ structure = []
256
+ synonyms = select_all(<<~SQL.squish, "SCHEMA")
257
+ SELECT owner, synonym_name, table_name, table_owner
258
+ FROM all_synonyms
259
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
260
+ SQL
261
+ synonyms.each do |synonym|
262
+ structure << "CREATE OR REPLACE #{synonym['owner'] == 'PUBLIC' ? 'PUBLIC' : '' } SYNONYM #{synonym['synonym_name']}
263
+ FOR #{synonym['table_owner']}.#{synonym['table_name']}"
264
+ end
265
+ join_with_statement_token(structure)
266
+ end
267
+
268
+ def structure_drop # :nodoc:
269
+ sequences = select_values(<<~SQL.squish, "SCHEMA")
270
+ SELECT
271
+ sequence_name FROM all_sequences where sequence_owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
272
+ SQL
273
+ statements = sequences.map do |seq|
274
+ "DROP SEQUENCE \"#{seq}\""
275
+ end
276
+ tables = select_values(<<~SQL.squish, "SCHEMA")
277
+ SELECT table_name from all_tables t
278
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
279
+ AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv
280
+ WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
281
+ AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl
282
+ WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
283
+ ORDER BY 1
284
+ SQL
285
+ tables.each do |table|
286
+ statements << "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
287
+ end
288
+ join_with_statement_token(statements)
289
+ end
290
+
291
+ def temp_table_drop # :nodoc:
292
+ temporary_tables = select_values(<<~SQL.squish, "SCHEMA")
293
+ SELECT table_name FROM all_tables
294
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
295
+ AND secondary = 'N' AND temporary = 'Y' ORDER BY 1
296
+ SQL
297
+ statements = temporary_tables.map do |table|
298
+ "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
299
+ end
300
+ join_with_statement_token(statements)
301
+ end
302
+
303
+ def full_drop(preserve_tables = false) # :nodoc:
304
+ s = preserve_tables ? [] : [structure_drop]
305
+ s << temp_table_drop if preserve_tables
306
+ s << drop_sql_for_feature("view")
307
+ s << drop_sql_for_feature("materialized view")
308
+ s << drop_sql_for_feature("synonym")
309
+ s << drop_sql_for_feature("type")
310
+ s << drop_sql_for_object("package")
311
+ s << drop_sql_for_object("function")
312
+ s << drop_sql_for_object("procedure")
313
+ s.join
314
+ end
315
+
316
+ def execute_structure_dump(string)
317
+ string.split(STATEMENT_TOKEN).each do |ddl|
318
+ execute(ddl) unless ddl.blank?
319
+ end
320
+ end
321
+
322
+ private
323
+ # Called only if `supports_virtual_columns?` returns true
324
+ # return [{'column_name' => 'FOOS', 'data_default' => '...'}, ...]
325
+ def virtual_columns_for(table)
326
+ select_all(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table.upcase)])
327
+ SELECT column_name, data_default
328
+ FROM all_tab_cols
329
+ WHERE virtual_column = 'YES'
330
+ AND owner = SYS_CONTEXT('userenv', 'current_schema')
331
+ AND table_name = :table_name
332
+ SQL
333
+ end
334
+
335
+ def drop_sql_for_feature(type)
336
+ short_type = type == "materialized view" ? "mview" : type
337
+ features = select_values(<<~SQL.squish, "SCHEMA")
338
+ SELECT #{short_type}_name FROM all_#{short_type.tableize}
339
+ where owner = SYS_CONTEXT('userenv', 'current_schema')
340
+ SQL
341
+ statements = features.map do |name|
342
+ "DROP #{type.upcase} \"#{name}\""
343
+ end
344
+ join_with_statement_token(statements)
345
+ end
346
+
347
+ def drop_sql_for_object(type)
348
+ objects = select_values(<<~SQL.squish, "SCHEMA")
349
+ SELECT object_name FROM all_objects
350
+ WHERE object_type = '#{type.upcase}' and owner = SYS_CONTEXT('userenv', 'current_schema')
351
+ SQL
352
+ statements = objects.map do |name|
353
+ "DROP #{type.upcase} \"#{name}\""
354
+ end
355
+ join_with_statement_token(statements)
356
+ end
357
+
358
+ def join_with_statement_token(array)
359
+ string = array.join(STATEMENT_TOKEN)
360
+ string << STATEMENT_TOKEN unless string.blank?
361
+ string
362
+ end
363
+ end
364
+ end
365
+ end
366
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters # :nodoc:
5
+ module OracleEnhanced
6
+ class TypeMetadata < DelegateClass(ActiveRecord::ConnectionAdapters::SqlTypeMetadata) # :nodoc:
7
+ include Deduplicable
8
+
9
+ attr_reader :virtual
10
+
11
+ def initialize(type_metadata, virtual: nil)
12
+ super(type_metadata)
13
+ @type_metadata = type_metadata
14
+ @virtual = virtual
15
+ end
16
+
17
+ def ==(other)
18
+ other.is_a?(OracleEnhanced::TypeMetadata) &&
19
+ attributes_for_hash == other.attributes_for_hash
20
+ end
21
+ alias eql? ==
22
+
23
+ def hash
24
+ attributes_for_hash.hash
25
+ end
26
+
27
+ protected
28
+ def attributes_for_hash
29
+ [self.class, @type_metadata, virtual]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::VERSION = File.read(File.expand_path("../../../../../VERSION", __FILE__)).chomp