activerecord-oracle_enhanced-adapter 8.1.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/History.md +1971 -0
- data/License.txt +20 -0
- data/README.md +947 -0
- data/VERSION +1 -0
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +7 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +24 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +137 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +359 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +47 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +325 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +63 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +71 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +629 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +57 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +465 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +195 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +186 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +99 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +197 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +739 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +394 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +886 -0
- data/lib/active_record/type/oracle_enhanced/boolean.rb +19 -0
- data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/integer.rb +14 -0
- data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
- data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
- data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
- data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
- data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
- data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
- data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
- data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
- data/lib/arel/visitors/oracle.rb +216 -0
- data/lib/arel/visitors/oracle12.rb +121 -0
- data/lib/arel/visitors/oracle_common.rb +51 -0
- data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +24 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +40 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +589 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1318 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +485 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
- data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
- data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
- data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
- data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
- data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
- data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +101 -0
- data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
- data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
- data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
- data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
- data/spec/active_record/oracle_enhanced/type/text_spec.rb +295 -0
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +107 -0
- data/spec/spec_config.yaml.template +11 -0
- data/spec/spec_helper.rb +225 -0
- data/spec/support/alter_system_set_open_cursors.sql +1 -0
- data/spec/support/alter_system_user_password.sql +2 -0
- data/spec/support/create_oracle_enhanced_users.sql +31 -0
- metadata +181 -0
|
@@ -0,0 +1,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
|