activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.0.beta1
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 +4 -4
- data/.rspec +2 -0
- data/Gemfile +20 -11
- data/History.md +123 -4
- data/RUNNING_TESTS.md +79 -55
- data/Rakefile +13 -19
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +16 -17
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +7 -59
- data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +6 -50
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +11 -11
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +117 -117
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +30 -23
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +48 -70
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +51 -69
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +4 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +76 -76
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +13 -42
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +60 -64
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +33 -47
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +146 -159
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +94 -132
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +65 -100
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +250 -487
- data/lib/active_record/oracle_enhanced/type/boolean.rb +7 -10
- data/lib/active_record/oracle_enhanced/type/integer.rb +3 -4
- data/lib/active_record/oracle_enhanced/type/national_character_string.rb +1 -1
- data/lib/active_record/oracle_enhanced/type/raw.rb +2 -3
- data/lib/active_record/oracle_enhanced/type/string.rb +2 -2
- data/lib/active_record/oracle_enhanced/type/text.rb +2 -2
- data/lib/activerecord-oracle_enhanced-adapter.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +57 -131
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +32 -34
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -42
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +83 -85
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +205 -286
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +14 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +3 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +42 -49
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +68 -71
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +51 -92
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +221 -327
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +16 -18
- data/spec/spec_helper.rb +59 -57
- metadata +10 -10
@@ -1,14 +1,32 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionAdapters
|
3
3
|
module OracleEnhanced
|
4
|
-
|
5
|
-
def name
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
module ColumnMethods
|
5
|
+
def primary_key(name, type = :primary_key, **options)
|
6
|
+
# This is a placeholder for future :auto_increment support
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
[
|
11
|
+
:raw
|
12
|
+
].each do |column_type|
|
13
|
+
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
14
|
+
def #{column_type}(*args, **options)
|
15
|
+
args.each { |name| column(name, :#{column_type}, options) }
|
16
|
+
end
|
17
|
+
CODE
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class ReferenceDefinition < ActiveRecord::ConnectionAdapters::ReferenceDefinition # :nodoc:
|
22
|
+
def initialize(
|
23
|
+
name,
|
24
|
+
polymorphic: false,
|
25
|
+
index: true,
|
26
|
+
foreign_key: false,
|
27
|
+
type: :integer,
|
28
|
+
**options)
|
29
|
+
super
|
12
30
|
end
|
13
31
|
end
|
14
32
|
|
@@ -26,10 +44,9 @@ module ActiveRecord
|
|
26
44
|
end
|
27
45
|
end
|
28
46
|
|
29
|
-
class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
|
30
|
-
end
|
31
|
-
|
32
47
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
48
|
+
include ActiveRecord::ConnectionAdapters::OracleEnhanced::ColumnMethods
|
49
|
+
|
33
50
|
attr_accessor :tablespace, :organization
|
34
51
|
def initialize(name, temporary = false, options = nil, as = nil, tablespace = nil, organization = nil, comment: nil)
|
35
52
|
@tablespace = tablespace
|
@@ -37,51 +54,20 @@ module ActiveRecord
|
|
37
54
|
super(name, temporary, options, as, comment: comment)
|
38
55
|
end
|
39
56
|
|
40
|
-
def
|
41
|
-
options = args.extract_options!
|
42
|
-
column_names = args
|
43
|
-
column_names.each { |name| column(name, :virtual, options) }
|
44
|
-
end
|
45
|
-
|
46
|
-
def column(name, type, options = {})
|
57
|
+
def new_column_definition(name, type, **options) # :nodoc:
|
47
58
|
if type == :virtual
|
48
|
-
|
49
|
-
|
50
|
-
default[:as] = options[:as]
|
51
|
-
elsif options[:default]
|
52
|
-
warn "[DEPRECATION] virtual column `:default` option is deprecated. Please use `:as` instead."
|
53
|
-
default[:as] = options[:default]
|
54
|
-
else
|
55
|
-
raise "No virtual column definition found."
|
56
|
-
end
|
57
|
-
options[:default] = default
|
59
|
+
raise "No virtual column definition found." unless options[:as]
|
60
|
+
type = options[:type]
|
58
61
|
end
|
59
|
-
super
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
def create_column_definition(name, type)
|
64
|
-
OracleEnhanced::ColumnDefinition.new name, type
|
62
|
+
super
|
65
63
|
end
|
66
64
|
end
|
67
65
|
|
68
66
|
class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
|
69
|
-
def add_foreign_key(to_table, options)
|
70
|
-
@foreign_key_adds << OracleEnhanced::ForeignKeyDefinition.new(name, to_table, options)
|
71
|
-
end
|
72
67
|
end
|
73
68
|
|
74
69
|
class Table < ActiveRecord::ConnectionAdapters::Table
|
75
|
-
|
76
|
-
ActiveSupport::Deprecation.warn "`foreign_key` option will be deprecated. Please use `references` option"
|
77
|
-
to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
|
78
|
-
@base.add_foreign_key(@name, to_table, options)
|
79
|
-
end
|
80
|
-
|
81
|
-
def remove_foreign_key(options = {})
|
82
|
-
ActiveSupport::Deprecation.warn "`remove_foreign_key` option will be deprecated. Please use `remove_references` option"
|
83
|
-
@base.remove_foreign_key(@name, options)
|
84
|
-
end
|
70
|
+
include ActiveRecord::ConnectionAdapters::OracleEnhanced::ColumnMethods
|
85
71
|
end
|
86
72
|
end
|
87
73
|
end
|
@@ -4,199 +4,186 @@ module ActiveRecord #:nodoc:
|
|
4
4
|
module SchemaDumper #:nodoc:
|
5
5
|
private
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
7
|
+
def tables(stream)
|
8
|
+
return super unless @connection.respond_to?(:materialized_views)
|
9
|
+
# do not include materialized views in schema dump - they should be created separately after schema creation
|
10
|
+
sorted_tables = (@connection.tables - @connection.materialized_views).sort
|
11
|
+
sorted_tables.each do |tbl|
|
12
|
+
# add table prefix or suffix for schema_migrations
|
13
|
+
next if ignored? tbl
|
14
|
+
# change table name inspect method
|
15
|
+
tbl.extend TableInspect
|
16
|
+
table(tbl, stream)
|
17
|
+
# add primary key trigger if table has it
|
18
|
+
primary_key_trigger(tbl, stream)
|
19
|
+
end
|
20
|
+
# following table definitions
|
21
|
+
# add foreign keys if table has them
|
22
|
+
sorted_tables.each do |tbl|
|
23
|
+
next if ignored? tbl
|
24
|
+
foreign_keys(tbl, stream)
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
# add synonyms in local schema
|
28
|
+
synonyms(stream)
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
def primary_key_trigger(table_name, stream)
|
32
|
+
if @connection.respond_to?(:has_primary_key_trigger?) && @connection.has_primary_key_trigger?(table_name)
|
33
|
+
pk, _pk_seq = @connection.pk_and_sequence_for(table_name)
|
34
|
+
stream.print " add_primary_key_trigger #{table_name.inspect}"
|
35
|
+
stream.print ", primary_key: \"#{pk}\"" if pk != "id"
|
36
|
+
stream.print "\n\n"
|
37
|
+
end
|
37
38
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
39
|
+
|
40
|
+
def synonyms(stream)
|
41
|
+
if @connection.respond_to?(:synonyms)
|
42
|
+
syns = @connection.synonyms
|
43
|
+
syns.each do |syn|
|
44
|
+
next if ignored? syn.name
|
45
|
+
table_name = syn.table_name
|
46
|
+
table_name = "#{syn.table_owner}.#{table_name}" if syn.table_owner
|
47
|
+
table_name = "#{table_name}@#{syn.db_link}" if syn.db_link
|
48
|
+
stream.print " add_synonym #{syn.name.inspect}, #{table_name.inspect}, force: true"
|
49
|
+
stream.puts
|
50
|
+
end
|
51
|
+
stream.puts unless syns.empty?
|
50
52
|
end
|
51
|
-
stream.puts unless syns.empty?
|
52
53
|
end
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
54
|
+
|
55
|
+
def indexes(table, stream)
|
56
|
+
if (indexes = @connection.indexes(table)).any?
|
57
|
+
add_index_statements = indexes.map do |index|
|
58
|
+
case index.type
|
59
|
+
when nil
|
60
|
+
# do nothing here. see indexes_in_create
|
61
|
+
statement_parts = []
|
62
|
+
when "CTXSYS.CONTEXT"
|
63
|
+
if index.statement_parameters
|
64
|
+
statement_parts = [ ("add_context_index " + table.inspect) ]
|
65
|
+
statement_parts << index.statement_parameters
|
66
|
+
else
|
67
|
+
statement_parts = [ ("add_context_index " + table.inspect) ]
|
68
|
+
statement_parts << index.columns.inspect
|
69
|
+
statement_parts << ("name: " + index.name.inspect)
|
70
|
+
end
|
70
71
|
else
|
71
|
-
|
72
|
-
statement_parts
|
73
|
-
statement_parts << ('name: ' + index.name.inspect)
|
72
|
+
# unrecognized index type
|
73
|
+
statement_parts = ["# unrecognized index #{index.name.inspect} with type #{index.type.inspect}"]
|
74
74
|
end
|
75
|
-
|
76
|
-
# unrecognized index type
|
77
|
-
statement_parts = ["# unrecognized index #{index.name.inspect} with type #{index.type.inspect}"]
|
75
|
+
" " + statement_parts.join(", ")
|
78
76
|
end
|
79
|
-
' ' + statement_parts.join(', ')
|
80
|
-
end
|
81
77
|
|
82
|
-
|
83
|
-
|
78
|
+
stream.puts add_index_statements.sort.join("\n")
|
79
|
+
stream.puts
|
80
|
+
end
|
84
81
|
end
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
# first dump primary key column
|
94
|
-
if @connection.respond_to?(:primary_keys)
|
95
|
-
pk = @connection.primary_keys(table)
|
96
|
-
pk = pk.first unless pk.size > 1
|
97
|
-
else
|
98
|
-
pk = @connection.primary_key(table)
|
82
|
+
|
83
|
+
def indexes_in_create(table, stream)
|
84
|
+
if (indexes = @connection.indexes(table)).any?
|
85
|
+
index_statements = indexes.map do |index|
|
86
|
+
" t.index #{index_parts(index).join(', ')}" unless index.type == "CTXSYS.CONTEXT"
|
87
|
+
end
|
88
|
+
stream.puts index_statements.sort.join("\n")
|
99
89
|
end
|
90
|
+
end
|
100
91
|
|
101
|
-
|
92
|
+
def index_parts(index)
|
93
|
+
index_parts = super
|
94
|
+
index_parts << "tablespace: #{index.tablespace.inspect}" if index.tablespace
|
95
|
+
index_parts
|
96
|
+
end
|
102
97
|
|
103
|
-
|
104
|
-
|
98
|
+
def table(table, stream)
|
99
|
+
return super unless @connection.respond_to?(:temporary_table?)
|
100
|
+
columns = @connection.columns(table)
|
101
|
+
begin
|
102
|
+
tbl = StringIO.new
|
105
103
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
when String
|
113
|
-
tbl.print ", primary_key: #{pk.inspect}" unless pk == 'id'
|
114
|
-
pkcol = columns.detect { |c| c.name == pk }
|
115
|
-
pkcolspec = @connection.column_spec_for_primary_key(pkcol)
|
116
|
-
if pkcolspec.present?
|
117
|
-
pkcolspec.each do |key, value|
|
118
|
-
tbl.print ", #{key}: #{value}"
|
119
|
-
end
|
104
|
+
# first dump primary key column
|
105
|
+
if @connection.respond_to?(:primary_keys)
|
106
|
+
pk = @connection.primary_keys(table)
|
107
|
+
pk = pk.first unless pk.size > 1
|
108
|
+
else
|
109
|
+
pk = @connection.primary_key(table)
|
120
110
|
end
|
121
|
-
when Array
|
122
|
-
tbl.print ", primary_key: #{pk.inspect}"
|
123
|
-
else
|
124
|
-
tbl.print ", id: false"
|
125
|
-
end
|
126
111
|
|
127
|
-
|
128
|
-
tbl.puts " do |t|"
|
112
|
+
tbl.print " create_table #{table.inspect}"
|
129
113
|
|
130
|
-
|
131
|
-
|
132
|
-
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
133
|
-
next if column.name == pk
|
134
|
-
@connection.column_spec(column)
|
135
|
-
end.compact
|
114
|
+
# addition to make temporary option work
|
115
|
+
tbl.print ", temporary: true" if @connection.temporary_table?(table)
|
136
116
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
117
|
+
case pk
|
118
|
+
when String
|
119
|
+
tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
|
120
|
+
pkcol = columns.detect { |c| c.name == pk }
|
121
|
+
pkcolspec = @connection.column_spec_for_primary_key(pkcol)
|
122
|
+
if pkcolspec.present?
|
123
|
+
tbl.print ", #{format_colspec(pkcolspec)}"
|
124
|
+
end
|
125
|
+
when Array
|
126
|
+
tbl.print ", primary_key: #{pk.inspect}"
|
127
|
+
else
|
128
|
+
tbl.print ", id: false"
|
129
|
+
end
|
142
130
|
|
143
|
-
|
144
|
-
lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
|
131
|
+
tbl.print ", force: :cascade"
|
145
132
|
|
146
|
-
|
147
|
-
|
133
|
+
table_comments = @connection.table_comment(table)
|
134
|
+
unless table_comments.blank?
|
135
|
+
tbl.print ", comment: #{table_comments.inspect}"
|
136
|
+
end
|
148
137
|
|
149
|
-
|
150
|
-
type_length = column_specs.map{ |column| column[:type].length }.max
|
138
|
+
tbl.puts " do |t|"
|
151
139
|
|
152
|
-
|
153
|
-
|
140
|
+
# then dump all non-primary key columns
|
141
|
+
columns.each do |column|
|
142
|
+
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
143
|
+
next if column.name == pk
|
144
|
+
type, colspec = @connection.column_spec(column)
|
145
|
+
tbl.print " t.#{type} #{column.name.inspect}"
|
146
|
+
tbl.print ", #{format_colspec(colspec)}" if colspec.present?
|
147
|
+
tbl.puts
|
148
|
+
end
|
154
149
|
|
155
|
-
|
150
|
+
indexes_in_create(table, tbl)
|
156
151
|
|
157
|
-
|
158
|
-
column_specs.each do |colspec|
|
159
|
-
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
160
|
-
values.unshift colspec[:type]
|
161
|
-
tbl.print((format_string % values).gsub(/,\s*$/, '').gsub(/virtual_type:/, "type:"))
|
152
|
+
tbl.puts " end"
|
162
153
|
tbl.puts
|
163
|
-
end
|
164
154
|
|
165
|
-
|
166
|
-
tbl.puts
|
155
|
+
indexes(table, tbl)
|
167
156
|
|
168
|
-
|
157
|
+
tbl.rewind
|
158
|
+
stream.print tbl.read
|
159
|
+
rescue => e
|
160
|
+
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
161
|
+
stream.puts "# #{e.message}"
|
162
|
+
stream.puts
|
163
|
+
end
|
169
164
|
|
170
|
-
|
171
|
-
stream.print tbl.read
|
172
|
-
rescue => e
|
173
|
-
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
174
|
-
stream.puts "# #{e.message}"
|
175
|
-
stream.puts
|
165
|
+
stream
|
176
166
|
end
|
177
167
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
def remove_prefix_and_suffix(table)
|
182
|
-
table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
|
183
|
-
end
|
184
|
-
|
185
|
-
# remove table name prefix and suffix when doing #inspect (which is used in tables method)
|
186
|
-
module TableInspect #:nodoc:
|
187
|
-
def inspect
|
188
|
-
remove_prefix_and_suffix(self)
|
168
|
+
def remove_prefix_and_suffix(table)
|
169
|
+
table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
|
189
170
|
end
|
190
171
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
else
|
196
|
-
"\"#{table_name}\""
|
172
|
+
# remove table name prefix and suffix when doing #inspect (which is used in tables method)
|
173
|
+
module TableInspect #:nodoc:
|
174
|
+
def inspect
|
175
|
+
remove_prefix_and_suffix(self)
|
197
176
|
end
|
177
|
+
|
178
|
+
private
|
179
|
+
def remove_prefix_and_suffix(table_name)
|
180
|
+
if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix.to_s.gsub('$', '\$')}(.*)#{ActiveRecord::Base.table_name_suffix.to_s.gsub('$', '\$')}\Z/
|
181
|
+
"\"#{$1}\""
|
182
|
+
else
|
183
|
+
"\"#{table_name}\""
|
184
|
+
end
|
185
|
+
end
|
198
186
|
end
|
199
|
-
end
|
200
187
|
end
|
201
188
|
end
|
202
189
|
end
|