activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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