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.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +1971 -0
  3. data/License.txt +20 -0
  4. data/README.md +947 -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 +359 -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 +325 -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 +629 -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 +57 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +465 -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 +95 -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 +739 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +394 -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 +886 -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 +40 -0
  46. data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
  47. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +589 -0
  48. data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
  49. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
  50. data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
  51. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
  52. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
  53. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
  54. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
  55. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1318 -0
  56. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +485 -0
  57. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
  58. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
  59. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  60. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
  61. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
  62. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  63. data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
  64. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
  65. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  66. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +101 -0
  67. data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
  68. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  69. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  70. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
  71. data/spec/active_record/oracle_enhanced/type/text_spec.rb +295 -0
  72. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +107 -0
  73. data/spec/spec_config.yaml.template +11 -0
  74. data/spec/spec_helper.rb +225 -0
  75. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  76. data/spec/support/alter_system_user_password.sql +2 -0
  77. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  78. metadata +181 -0
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+
5
+ module ActiveRecord # :nodoc:
6
+ # Custom create, update, delete methods functionality.
7
+ #
8
+ # Example:
9
+ #
10
+ # class Employee < ActiveRecord::Base
11
+ # include ActiveRecord::OracleEnhancedProcedures
12
+ #
13
+ # set_create_method do
14
+ # plsql.employees_pkg.create_employee(
15
+ # :p_first_name => first_name,
16
+ # :p_last_name => last_name,
17
+ # :p_employee_id => nil
18
+ # )[:p_employee_id]
19
+ # end
20
+ #
21
+ # set_update_method do
22
+ # plsql.employees_pkg.update_employee(
23
+ # :p_employee_id => id,
24
+ # :p_first_name => first_name,
25
+ # :p_last_name => last_name
26
+ # )
27
+ # end
28
+ #
29
+ # set_delete_method do
30
+ # plsql.employees_pkg.delete_employee(
31
+ # :p_employee_id => id
32
+ # )
33
+ # end
34
+ # end
35
+ #
36
+ module OracleEnhancedProcedures # :nodoc:
37
+ module ClassMethods
38
+ # Specify custom create method which should be used instead of Rails generated INSERT statement.
39
+ # Provided block should return ID of new record.
40
+ # Example:
41
+ # set_create_method do
42
+ # plsql.employees_pkg.create_employee(
43
+ # :p_first_name => first_name,
44
+ # :p_last_name => last_name,
45
+ # :p_employee_id => nil
46
+ # )[:p_employee_id]
47
+ # end
48
+ def set_create_method(&block)
49
+ self.custom_create_method = block
50
+ end
51
+
52
+ # Specify custom update method which should be used instead of Rails generated UPDATE statement.
53
+ # Example:
54
+ # set_update_method do
55
+ # plsql.employees_pkg.update_employee(
56
+ # :p_employee_id => id,
57
+ # :p_first_name => first_name,
58
+ # :p_last_name => last_name
59
+ # )
60
+ # end
61
+ def set_update_method(&block)
62
+ self.custom_update_method = block
63
+ end
64
+
65
+ # Specify custom delete method which should be used instead of Rails generated DELETE statement.
66
+ # Example:
67
+ # set_delete_method do
68
+ # plsql.employees_pkg.delete_employee(
69
+ # :p_employee_id => id
70
+ # )
71
+ # end
72
+ def set_delete_method(&block)
73
+ self.custom_delete_method = block
74
+ end
75
+ end
76
+
77
+ def self.included(base)
78
+ base.class_eval do
79
+ extend ClassMethods
80
+ class_attribute :custom_create_method
81
+ class_attribute :custom_update_method
82
+ class_attribute :custom_delete_method
83
+ end
84
+ end
85
+
86
+ def destroy # :nodoc:
87
+ # check if class has custom delete method
88
+ if self.class.custom_delete_method
89
+ # wrap destroy in transaction
90
+ with_transaction_returning_status do
91
+ # run before/after callbacks defined in model
92
+ run_callbacks(:destroy) { destroy_using_custom_method }
93
+ end
94
+ else
95
+ super
96
+ end
97
+ end
98
+
99
+ private
100
+ # Creates a record with custom create method
101
+ # and returns its id.
102
+ def _create_record
103
+ # check if class has custom create method
104
+ if self.class.custom_create_method
105
+ # run before/after callbacks defined in model
106
+ run_callbacks(:create) do
107
+ # timestamp
108
+ if self.record_timestamps
109
+ current_time = current_time_from_proper_timezone
110
+
111
+ all_timestamp_attributes_in_model.each do |column|
112
+ if respond_to?(column) && respond_to?("#{column}=") && self.send(column).nil?
113
+ write_attribute(column.to_s, current_time)
114
+ end
115
+ end
116
+ end
117
+ # run
118
+ create_using_custom_method
119
+ end
120
+ else
121
+ super
122
+ end
123
+ end
124
+
125
+ def create_using_custom_method
126
+ log_custom_method("custom create method", "#{self.class.name} Create") do
127
+ self.id = instance_eval(&self.class.custom_create_method)
128
+ end
129
+ @new_record = false
130
+ # Starting from ActiveRecord 3.0.3 @persisted is used instead of @new_record
131
+ @persisted = true
132
+ id
133
+ end
134
+
135
+ # Updates the associated record with custom update method
136
+ # Returns the number of affected rows.
137
+ def _update_record(attribute_names = @attributes.keys)
138
+ # check if class has custom update method
139
+ if self.class.custom_update_method
140
+ # run before/after callbacks defined in model
141
+ run_callbacks(:update) do
142
+ # timestamp
143
+ if should_record_timestamps?
144
+ current_time = current_time_from_proper_timezone
145
+
146
+ timestamp_attributes_for_update_in_model.each do |column|
147
+ column = column.to_s
148
+ next if will_save_change_to_attribute?(column)
149
+ write_attribute(column, current_time)
150
+ end
151
+ end
152
+ # update just dirty attributes
153
+ if partial_updates?
154
+ # Serialized attributes should always be written in case they've been
155
+ # changed in place.
156
+ update_using_custom_method(changed | (attributes.keys & self.class.columns.select { |column| column.is_a?(Type::Serialized) }))
157
+ else
158
+ update_using_custom_method(attributes.keys)
159
+ end
160
+ end
161
+ else
162
+ super
163
+ end
164
+ end
165
+
166
+ def update_using_custom_method(attribute_names)
167
+ return 0 if attribute_names.empty?
168
+ log_custom_method("custom update method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Update") do
169
+ instance_eval(&self.class.custom_update_method)
170
+ end
171
+ 1
172
+ end
173
+
174
+ # Deletes the record in the database with custom delete method
175
+ # and freezes this instance to reflect that no changes should
176
+ # be made (since they can't be persisted).
177
+ def destroy_using_custom_method
178
+ unless new_record? || @destroyed
179
+ log_custom_method("custom delete method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Destroy") do
180
+ instance_eval(&self.class.custom_delete_method)
181
+ end
182
+ end
183
+
184
+ @destroyed = true
185
+ freeze
186
+ end
187
+
188
+ def log_custom_method(*args, &block)
189
+ self.class.connection.send(:log, *args, &block)
190
+ end
191
+
192
+ alias_method :update_record, :_update_record if private_method_defined?(:_update_record)
193
+ alias_method :create_record, :_create_record if private_method_defined?(:_create_record)
194
+ end
195
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module OracleEnhanced
6
+ module Quoting
7
+ extend ActiveSupport::Concern
8
+ # QUOTING ==================================================
9
+ #
10
+ # see: abstract/quoting.rb
11
+ QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
12
+ QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
13
+
14
+ module ClassMethods # :nodoc:
15
+ def column_name_matcher
16
+ /
17
+ \A
18
+ (
19
+ (?:
20
+ # "table_name"."column_name" | function(one or no argument)
21
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
22
+ )
23
+ (?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
24
+ )
25
+ (?:\s*,\s*\g<1>)*
26
+ \z
27
+ /ix
28
+ end
29
+
30
+ def column_name_with_order_matcher
31
+ /
32
+ \A
33
+ (
34
+ (?:
35
+ # "table_name"."column_name" | function(one or no argument)
36
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
37
+ )
38
+ (?:\s+ASC|\s+DESC)?
39
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
40
+ )
41
+ (?:\s*,\s*\g<1>)*
42
+ \z
43
+ /ix
44
+ end
45
+
46
+ def quote_column_name(name) # :nodoc:
47
+ name = name.to_s
48
+ QUOTED_COLUMN_NAMES[name] ||= if /\A[a-z][a-z_0-9$#]*\Z/.match?(name)
49
+ "\"#{name.upcase}\""
50
+ else
51
+ # remove double quotes which cannot be used inside quoted identifier
52
+ "\"#{name.delete('"')}\""
53
+ end
54
+ end
55
+
56
+ def quote_table_name(name) # :nodoc:
57
+ name, _link = name.to_s.split("@")
58
+ QUOTED_TABLE_NAMES[name] ||= [name.split(".").map { |n| quote_column_name(n) }].join(".")
59
+ end
60
+ end
61
+
62
+ # This method is used in add_index to identify either column name (which is quoted)
63
+ # or function based index (in which case function expression is not quoted)
64
+ def quote_column_name_or_expression(name) # :nodoc:
65
+ name = name.to_s
66
+ case name
67
+ # if only valid lowercase column characters in name
68
+ when /^[a-z][a-z_0-9$#]*$/
69
+ "\"#{name.upcase}\""
70
+ when /^[a-z][a-z_0-9$#-]*$/i
71
+ "\"#{name}\""
72
+ # if other characters present then assume that it is expression
73
+ # which should not be quoted
74
+ else
75
+ name
76
+ end
77
+ end
78
+
79
+ # Names must be from 1 to 30 bytes long with these exceptions:
80
+ # * Names of databases are limited to 8 bytes.
81
+ # * Names of database links can be as long as 128 bytes.
82
+ #
83
+ # Nonquoted identifiers cannot be Oracle Database reserved words
84
+ #
85
+ # Nonquoted identifiers must begin with an alphabetic character from
86
+ # your database character set
87
+ #
88
+ # Nonquoted identifiers can contain only alphanumeric characters from
89
+ # your database character set and the underscore (_), dollar sign ($),
90
+ # and pound sign (#).
91
+ # Oracle strongly discourages you from using $ and # in nonquoted identifiers.
92
+ NONQUOTED_OBJECT_NAME = /[[:alpha:]][\w$#]{0,29}/
93
+ VALID_TABLE_NAME = /\A(?:#{NONQUOTED_OBJECT_NAME}\.)?#{NONQUOTED_OBJECT_NAME}?\Z/
94
+
95
+ # unescaped table name should start with letter and
96
+ # contain letters, digits, _, $ or #
97
+ # can be prefixed with schema name
98
+ # CamelCase table names should be quoted
99
+ def self.valid_table_name?(name) # :nodoc:
100
+ object_name = name.to_s
101
+ !!(object_name =~ VALID_TABLE_NAME && !mixed_case?(object_name))
102
+ end
103
+
104
+ def self.mixed_case?(name)
105
+ object_name = name.include?(".") ? name.split(".").second : name
106
+ !!(object_name =~ /[A-Z]/ && object_name =~ /[a-z]/)
107
+ end
108
+
109
+ def quote_string(s) # :nodoc:
110
+ s.gsub(/'/, "''")
111
+ end
112
+
113
+ def quote(value) # :nodoc:
114
+ case value
115
+ when Type::OracleEnhanced::CharacterString::Data then
116
+ "'#{quote_string(value.to_s)}'"
117
+ when Type::OracleEnhanced::NationalCharacterString::Data then
118
+ +"N" << "'#{quote_string(value.to_s)}'"
119
+ when ActiveModel::Type::Binary::Data then
120
+ "empty_blob()"
121
+ when Type::OracleEnhanced::Text::Data then
122
+ "empty_clob()"
123
+ when Type::OracleEnhanced::NationalCharacterText::Data then
124
+ "empty_nclob()"
125
+ else
126
+ super
127
+ end
128
+ end
129
+
130
+ def quoted_true # :nodoc:
131
+ return "'Y'" if emulate_booleans_from_strings
132
+ "1"
133
+ end
134
+
135
+ def unquoted_true # :nodoc:
136
+ return "Y" if emulate_booleans_from_strings
137
+ "1"
138
+ end
139
+
140
+ def quoted_false # :nodoc:
141
+ return "'N'" if emulate_booleans_from_strings
142
+ "0"
143
+ end
144
+
145
+ def unquoted_false # :nodoc:
146
+ return "N" if emulate_booleans_from_strings
147
+ "0"
148
+ end
149
+
150
+ def type_cast(value)
151
+ case value
152
+ when Type::OracleEnhanced::TimestampTz::Data, Type::OracleEnhanced::TimestampLtz::Data
153
+ if value.acts_like?(:time)
154
+ zone_conversion_method = ActiveRecord.default_timezone == :utc ? :getutc : :getlocal
155
+ value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
156
+ else
157
+ value
158
+ end
159
+ when Type::OracleEnhanced::NationalCharacterString::Data
160
+ value.to_s
161
+ when Type::OracleEnhanced::CharacterString::Data
162
+ value
163
+ else
164
+ super
165
+ end
166
+ end
167
+
168
+ private
169
+ def oracle_downcase(column_name)
170
+ return nil if column_name.nil?
171
+ /[a-z]/.match?(column_name) ? column_name : column_name.downcase
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ # if MRI or YARV or TruffleRuby
179
+ if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby"
180
+ require "active_record/connection_adapters/oracle_enhanced/oci_quoting"
181
+ # if JRuby
182
+ elsif RUBY_ENGINE == "jruby"
183
+ require "active_record/connection_adapters/oracle_enhanced/jdbc_quoting"
184
+ else
185
+ raise "Unsupported Ruby engine #{RUBY_ENGINE}"
186
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module OracleEnhanced
6
+ class SchemaCreation < SchemaCreation
7
+ private
8
+ def visit_ColumnDefinition(o)
9
+ if [:blob, :clob, :nclob].include?(sql_type = type_to_sql(o.type, **o.options).downcase.to_sym)
10
+ if (tablespace = default_tablespace_for(sql_type))
11
+ @lob_tablespaces ||= {}
12
+ @lob_tablespaces[o.name] = tablespace
13
+ end
14
+ end
15
+ o.cast_type = lookup_cast_type(sql_type)
16
+ super
17
+ end
18
+
19
+ def visit_TableDefinition(o)
20
+ create_sql = +"CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
21
+ statements = o.columns.map { |c| accept c }
22
+ statements << accept(o.primary_keys) if o.primary_keys
23
+
24
+ if use_foreign_keys?
25
+ statements.concat(o.foreign_keys.map { |fk| accept fk })
26
+ end
27
+
28
+ create_sql << "(#{statements.join(', ')})" if statements.present?
29
+
30
+ unless o.temporary
31
+ @lob_tablespaces.each do |lob_column, tablespace|
32
+ create_sql << " LOB (#{quote_column_name(lob_column)}) STORE AS (TABLESPACE #{tablespace}) \n"
33
+ end if defined?(@lob_tablespaces)
34
+ create_sql << " ORGANIZATION #{o.organization}" if o.organization
35
+ if (tablespace = o.tablespace || default_tablespace_for(:table))
36
+ create_sql << " TABLESPACE #{tablespace}"
37
+ end
38
+ end
39
+ add_table_options!(create_sql, o)
40
+ create_sql << " AS #{to_sql(o.as)}" if o.as
41
+ create_sql
42
+ end
43
+
44
+ def default_tablespace_for(type)
45
+ OracleEnhancedAdapter.default_tablespaces[type]
46
+ end
47
+
48
+ def add_column_options!(sql, options)
49
+ type = options[:type] || ((column = options[:column]) && column.type)
50
+ type = type && type.to_sym
51
+ # handle case of defaults for CLOB/NCLOB columns, which would otherwise get "quoted" incorrectly
52
+ if options_include_default?(options)
53
+ if type == :text
54
+ sql << " DEFAULT #{@conn.quote(options[:default])}"
55
+ elsif type == :ntext
56
+ sql << " DEFAULT #{@conn.quote(options[:default])}"
57
+ else
58
+ sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}"
59
+ end
60
+ end
61
+ # must explicitly add NULL or NOT NULL to allow change_column to work on migrations
62
+ if options[:null] == false
63
+ sql << " NOT NULL"
64
+ elsif options[:null] == true
65
+ sql << " NULL" unless type == :primary_key
66
+ end
67
+ # add AS expression for virtual columns
68
+ if options[:as].present?
69
+ sql << " AS (#{options[:as]})"
70
+ end
71
+ if options[:primary_key] == true
72
+ sql << " PRIMARY KEY"
73
+ end
74
+ end
75
+
76
+ def action_sql(action, dependency)
77
+ if action == "UPDATE"
78
+ raise ArgumentError, <<~MSG
79
+ '#{action}' is not supported by Oracle
80
+ MSG
81
+ end
82
+ case dependency
83
+ when :nullify then "ON #{action} SET NULL"
84
+ when :cascade then "ON #{action} CASCADE"
85
+ else
86
+ raise ArgumentError, <<~MSG
87
+ '#{dependency}' is not supported for #{action}
88
+ Supported values are: :nullify, :cascade
89
+ MSG
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module OracleEnhanced
6
+ module ColumnMethods
7
+ def primary_key(name, type = :primary_key, **options)
8
+ # This is a placeholder for future :auto_increment support
9
+ super
10
+ end
11
+
12
+ [
13
+ :raw,
14
+ :timestamptz,
15
+ :timestampltz,
16
+ :ntext
17
+ ].each do |column_type|
18
+ module_eval <<-CODE, __FILE__, __LINE__ + 1
19
+ def #{column_type}(*args, **options)
20
+ args.each { |name| column(name, :#{column_type}, **options) }
21
+ end
22
+ CODE
23
+ end
24
+ end
25
+
26
+ class ReferenceDefinition < ActiveRecord::ConnectionAdapters::ReferenceDefinition # :nodoc:
27
+ def initialize(
28
+ name,
29
+ polymorphic: false,
30
+ index: true,
31
+ foreign_key: false,
32
+ type: :integer,
33
+ **options)
34
+ super
35
+ end
36
+ end
37
+
38
+ class SynonymDefinition < Struct.new(:name, :table_owner, :table_name) # :nodoc:
39
+ end
40
+
41
+ class IndexDefinition < ActiveRecord::ConnectionAdapters::IndexDefinition
42
+ attr_accessor :parameters, :statement_parameters, :tablespace
43
+
44
+ def initialize(table, name, unique, columns, orders, type, parameters, statement_parameters, tablespace)
45
+ @parameters = parameters
46
+ @statement_parameters = statement_parameters
47
+ @tablespace = tablespace
48
+ super(table, name, unique, columns, orders: orders, type: type)
49
+ end
50
+ end
51
+
52
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
53
+ include OracleEnhanced::ColumnMethods
54
+
55
+ attr_accessor :tablespace, :organization
56
+ def initialize(
57
+ conn,
58
+ name,
59
+ temporary: false,
60
+ options: nil,
61
+ as: nil,
62
+ tablespace: nil,
63
+ organization: nil,
64
+ comment: nil,
65
+ **
66
+ )
67
+ @tablespace = tablespace
68
+ @organization = organization
69
+ super(conn, name, temporary: temporary, options: options, as: as, comment: comment)
70
+ end
71
+
72
+ def new_column_definition(name, type, **options) # :nodoc:
73
+ if type == :virtual
74
+ raise "No virtual column definition found." unless options[:as]
75
+ type = options[:type]
76
+ end
77
+ super
78
+ end
79
+
80
+ def references(*args, **options)
81
+ super(*args, type: :integer, **options)
82
+ end
83
+ alias :belongs_to :references
84
+
85
+ private
86
+ def valid_column_definition_options
87
+ super + [ :as, :sequence_name, :sequence_start_value, :type ]
88
+ end
89
+ end
90
+
91
+ class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
92
+ end
93
+
94
+ class Table < ActiveRecord::ConnectionAdapters::Table
95
+ include OracleEnhanced::ColumnMethods
96
+ end
97
+ end
98
+ end
99
+ end