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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/Gemfile +20 -11
  4. data/History.md +123 -4
  5. data/RUNNING_TESTS.md +79 -55
  6. data/Rakefile +13 -19
  7. data/VERSION +1 -1
  8. data/activerecord-oracle_enhanced-adapter.gemspec +16 -17
  9. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
  10. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +7 -59
  11. data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +6 -50
  12. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +11 -11
  13. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +117 -117
  14. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +30 -23
  15. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
  16. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +48 -70
  17. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -4
  18. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +51 -69
  19. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +4 -4
  20. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +76 -76
  21. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +13 -42
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +60 -64
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +33 -47
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +146 -159
  25. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +94 -132
  26. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +3 -3
  27. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +65 -100
  28. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
  29. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +250 -487
  30. data/lib/active_record/oracle_enhanced/type/boolean.rb +7 -10
  31. data/lib/active_record/oracle_enhanced/type/integer.rb +3 -4
  32. data/lib/active_record/oracle_enhanced/type/national_character_string.rb +1 -1
  33. data/lib/active_record/oracle_enhanced/type/raw.rb +2 -3
  34. data/lib/active_record/oracle_enhanced/type/string.rb +2 -2
  35. data/lib/active_record/oracle_enhanced/type/text.rb +2 -2
  36. data/lib/activerecord-oracle_enhanced-adapter.rb +2 -2
  37. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +57 -131
  38. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +32 -34
  39. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -42
  40. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +83 -85
  41. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +205 -286
  42. data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +14 -6
  43. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +3 -5
  44. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +42 -49
  45. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -3
  46. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +68 -71
  47. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +51 -92
  48. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +221 -327
  49. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +16 -18
  50. data/spec/spec_helper.rb +59 -57
  51. metadata +10 -10
@@ -1,14 +1,32 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module OracleEnhanced
4
- class ForeignKeyDefinition < ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
5
- def name
6
- if options[:name].length > OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH
7
- ActiveSupport::Deprecation.warn "Foreign key name #{options[:name]} is too long. It will not get shorten in later version of Oracle enhanced adapter"
8
- 'c'+Digest::SHA1.hexdigest(options[:name])[0,OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH-1]
9
- else
10
- options[:name]
11
- end
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 virtual(* args)
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
- default = {:type => options[:type]}
49
- if options[:as]
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(name, type, options)
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
- def foreign_key(to_table, options = {})
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
- 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.data_sources - @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
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
- # add synonyms in local schema
28
- synonyms(stream)
29
- end
27
+ # add synonyms in local schema
28
+ synonyms(stream)
29
+ end
30
30
 
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"
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
- end
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
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
- end
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
- # use table.inspect as it will remove prefix and suffix
61
- statement_parts = [ ('add_index ' + table.inspect) ]
62
- statement_parts << index.columns.inspect
63
- statement_parts << ('name: ' + index.name.inspect)
64
- statement_parts << 'unique: true' if index.unique
65
- statement_parts << 'tablespace: ' + index.tablespace.inspect if index.tablespace
66
- when 'CTXSYS.CONTEXT'
67
- if index.statement_parameters
68
- statement_parts = [ ('add_context_index ' + table.inspect) ]
69
- statement_parts << index.statement_parameters
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
- statement_parts = [ ('add_context_index ' + table.inspect) ]
72
- statement_parts << index.columns.inspect
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
- else
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
- stream.puts add_index_statements.sort.join("\n")
83
- stream.puts
78
+ stream.puts add_index_statements.sort.join("\n")
79
+ stream.puts
80
+ end
84
81
  end
85
- end
86
-
87
- def table(table, stream)
88
- return super unless @connection.respond_to?(:temporary_table?)
89
- columns = @connection.columns(table)
90
- begin
91
- tbl = StringIO.new
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
- tbl.print " create_table #{table.inspect}"
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
- # addition to make temporary option work
104
- tbl.print ", temporary: true" if @connection.temporary_table?(table)
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
- table_comments = @connection.table_comment(table)
107
- unless table_comments.nil?
108
- tbl.print ", comment: #{table_comments.inspect}"
109
- end
110
-
111
- case pk
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
- tbl.print ", force: :cascade"
128
- tbl.puts " do |t|"
112
+ tbl.print " create_table #{table.inspect}"
129
113
 
130
- # then dump all non-primary key columns
131
- column_specs = columns.map do |column|
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
- # find all migration keys used in this table
138
- #
139
- # TODO `& column_specs.map(&:keys).flatten` should be executed
140
- # in migration_keys_with_oracle_enhanced
141
- keys = @connection.migration_keys & column_specs.map(&:keys).flatten
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
- # figure out the lengths for each column based on above keys
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
- # the string we're going to sprintf our values against, with standardized column widths
147
- format_string = lengths.map{ |len| "%-#{len}s" }
133
+ table_comments = @connection.table_comment(table)
134
+ unless table_comments.blank?
135
+ tbl.print ", comment: #{table_comments.inspect}"
136
+ end
148
137
 
149
- # find the max length for the 'type' column, which is special
150
- type_length = column_specs.map{ |column| column[:type].length }.max
138
+ tbl.puts " do |t|"
151
139
 
152
- # add column type definition to our format string
153
- format_string.unshift " t.%-#{type_length}s "
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
- format_string *= ''
150
+ indexes_in_create(table, tbl)
156
151
 
157
- # dirty hack to replace virtual_type: with type:
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
- tbl.puts " end"
166
- tbl.puts
155
+ indexes(table, tbl)
167
156
 
168
- indexes(table, tbl)
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
- tbl.rewind
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
- stream
179
- end
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
- private
192
- def remove_prefix_and_suffix(table_name)
193
- if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix.to_s.gsub('$','\$')}(.*)#{ActiveRecord::Base.table_name_suffix.to_s.gsub('$','\$')}\Z/
194
- "\"#{$1}\""
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