activerecord-oracle_enhanced-adapter 1.6.9 → 1.7.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -11
  3. data/History.md +126 -14
  4. data/README.md +9 -6
  5. data/RUNNING_TESTS.md +1 -1
  6. data/Rakefile +1 -16
  7. data/VERSION +1 -1
  8. data/activerecord-oracle_enhanced-adapter.gemspec +15 -52
  9. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +8 -22
  10. data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +53 -45
  11. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +6 -1
  12. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +23 -62
  13. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +46 -56
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +35 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +34 -21
  16. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +36 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +1 -1
  18. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +174 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +17 -8
  20. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +17 -11
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +160 -178
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +42 -94
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +50 -54
  24. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +15 -11
  25. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +197 -301
  26. data/lib/active_record/oracle_enhanced/type/integer.rb +3 -2
  27. data/lib/active_record/oracle_enhanced/type/national_character_string.rb +25 -0
  28. data/lib/active_record/oracle_enhanced/type/raw.rb +14 -2
  29. data/lib/active_record/oracle_enhanced/type/string.rb +28 -0
  30. data/lib/active_record/oracle_enhanced/type/text.rb +32 -0
  31. data/lib/activerecord-oracle_enhanced-adapter.rb +12 -17
  32. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +113 -135
  33. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +51 -59
  34. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -41
  35. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +6 -6
  36. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +281 -233
  37. data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +7 -7
  38. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +10 -10
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +22 -22
  40. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +2 -2
  41. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +36 -37
  42. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +86 -46
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +194 -294
  44. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +53 -39
  45. data/spec/spec_helper.rb +0 -6
  46. metadata +42 -143
  47. data/.travis.yml +0 -39
  48. data/.travis/oracle/download.sh +0 -14
  49. data/.travis/oracle/install.sh +0 -31
  50. data/.travis/setup_accounts.sh +0 -9
  51. data/lib/active_record/connection_adapters/oracle_enhanced/dirty.rb +0 -40
  52. data/lib/active_record/oracle_enhanced/type/timestamp.rb +0 -11
  53. data/spec/spec_config.yaml.template +0 -11
  54. data/spec/support/alter_system_user_password.sql +0 -2
  55. data/spec/support/create_oracle_enhanced_users.sql +0 -31
@@ -0,0 +1,36 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module OracleEnhanced
4
+ module OCIQuoting
5
+ def _type_cast(value)
6
+ case value
7
+ when ActiveModel::Type::Binary::Data
8
+ lob_value = value == '' ? ' ' : value
9
+ bind_type = OCI8::BLOB
10
+ ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
11
+ ora_value.size = 0 if value == ''
12
+ ora_value
13
+ when ActiveRecord::OracleEnhanced::Type::Text::Data
14
+ lob_value = value.to_s == '' ? ' ' : value.to_s
15
+ bind_type = OCI8::CLOB
16
+ ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
17
+ ora_value.size = 0 if value.to_s == ''
18
+ ora_value
19
+ else
20
+ super
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ module ActiveRecord
29
+ module ConnectionAdapters
30
+ module OracleEnhanced
31
+ module Quoting
32
+ prepend OCIQuoting
33
+ end
34
+ end
35
+ end
36
+ end
@@ -152,7 +152,7 @@ module ActiveRecord #:nodoc:
152
152
  if partial_writes?
153
153
  # Serialized attributes should always be written in case they've been
154
154
  # changed in place.
155
- update_using_custom_method(changed | (attributes.keys & self.class.columns.select {|column| column.cast_type.is_a?(Type::Serialized)}))
155
+ update_using_custom_method(changed | (attributes.keys & self.class.columns.select {|column| column.is_a?(Type::Serialized)}))
156
156
  else
157
157
  update_using_custom_method(attribute_names)
158
158
  end
@@ -0,0 +1,174 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module OracleEnhanced
4
+ module Quoting
5
+ # QUOTING ==================================================
6
+ #
7
+ # see: abstract/quoting.rb
8
+
9
+ def quote_column_name(name) #:nodoc:
10
+ name = name.to_s
11
+ @quoted_column_names[name] ||= begin
12
+ # if only valid lowercase column characters in name
13
+ if name =~ /\A[a-z][a-z_0-9\$#]*\Z/
14
+ "\"#{name.upcase}\""
15
+ else
16
+ # remove double quotes which cannot be used inside quoted identifier
17
+ "\"#{name.gsub('"', '')}\""
18
+ end
19
+ end
20
+ end
21
+
22
+ # This method is used in add_index to identify either column name (which is quoted)
23
+ # or function based index (in which case function expression is not quoted)
24
+ def quote_column_name_or_expression(name) #:nodoc:
25
+ name = name.to_s
26
+ case name
27
+ # if only valid lowercase column characters in name
28
+ when /^[a-z][a-z_0-9\$#]*$/
29
+ "\"#{name.upcase}\""
30
+ when /^[a-z][a-z_0-9\$#\-]*$/i
31
+ "\"#{name}\""
32
+ # if other characters present then assume that it is expression
33
+ # which should not be quoted
34
+ else
35
+ name
36
+ end
37
+ end
38
+
39
+ # Used only for quoting database links as the naming rules for links
40
+ # differ from the rules for column names. Specifically, link names may
41
+ # include periods.
42
+ def quote_database_link(name)
43
+ case name
44
+ when NONQUOTED_DATABASE_LINK
45
+ %Q("#{name.upcase}")
46
+ else
47
+ name
48
+ end
49
+ end
50
+
51
+ # Names must be from 1 to 30 bytes long with these exceptions:
52
+ # * Names of databases are limited to 8 bytes.
53
+ # * Names of database links can be as long as 128 bytes.
54
+ #
55
+ # Nonquoted identifiers cannot be Oracle Database reserved words
56
+ #
57
+ # Nonquoted identifiers must begin with an alphabetic character from
58
+ # your database character set
59
+ #
60
+ # Nonquoted identifiers can contain only alphanumeric characters from
61
+ # your database character set and the underscore (_), dollar sign ($),
62
+ # and pound sign (#). Database links can also contain periods (.) and
63
+ # "at" signs (@). Oracle strongly discourages you from using $ and # in
64
+ # nonquoted identifiers.
65
+ NONQUOTED_OBJECT_NAME = /[A-Za-z][A-z0-9$#]{0,29}/
66
+ NONQUOTED_DATABASE_LINK = /[A-Za-z][A-z0-9$#\.@]{0,127}/
67
+ VALID_TABLE_NAME = /\A(?:#{NONQUOTED_OBJECT_NAME}\.)?#{NONQUOTED_OBJECT_NAME}(?:@#{NONQUOTED_DATABASE_LINK})?\Z/
68
+
69
+ # unescaped table name should start with letter and
70
+ # contain letters, digits, _, $ or #
71
+ # can be prefixed with schema name
72
+ # CamelCase table names should be quoted
73
+ def self.valid_table_name?(name) #:nodoc:
74
+ name = name.to_s
75
+ name =~ VALID_TABLE_NAME && !(name =~ /[A-Z]/ && name =~ /[a-z]/) ? true : false
76
+ end
77
+
78
+ def quote_table_name(name) #:nodoc:
79
+ name, link = name.to_s.split('@')
80
+ @quoted_table_names[name] ||= [name.split('.').map{|n| quote_column_name(n)}.join('.'), quote_database_link(link)].compact.join('@')
81
+ end
82
+
83
+ def quote_string(s) #:nodoc:
84
+ s.gsub(/'/, "''")
85
+ end
86
+
87
+ def quote(value, column = nil) #:nodoc:
88
+ super
89
+ end
90
+
91
+ def _quote(value) #:nodoc:
92
+ case value
93
+ when ActiveRecord::OracleEnhanced::Type::NationalCharacterString::Data then
94
+ "N" << "'#{quote_string(value.to_s)}'"
95
+ when ActiveModel::Type::Binary::Data then
96
+ %Q{empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'blob' }()}
97
+ when ActiveRecord::OracleEnhanced::Type::Text::Data then
98
+ %Q{empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'clob' }()}
99
+ else
100
+ super
101
+ end
102
+ end
103
+
104
+ def quoted_true #:nodoc:
105
+ return "'#{self.class.boolean_to_string(true)}'" if emulate_booleans_from_strings
106
+ "1"
107
+ end
108
+
109
+ def quoted_false #:nodoc:
110
+ return "'#{self.class.boolean_to_string(false)}'" if emulate_booleans_from_strings
111
+ "0"
112
+ end
113
+
114
+ def quote_date_with_to_date(value) #:nodoc:
115
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
116
+ `quote_date_with_to_date` will be deprecated in future version of Oracle enhanced adapter.
117
+ Also this method should not be called directly. Let Abstract adapter `_quote` method handle it.
118
+ MSG
119
+ # should support that composite_primary_keys gem will pass date as string
120
+ value = quoted_date(value) if value.acts_like?(:date) || value.acts_like?(:time)
121
+ "TO_DATE('#{value}','YYYY-MM-DD HH24:MI:SS')"
122
+ end
123
+
124
+ def quote_timestamp_with_to_timestamp(value) #:nodoc:
125
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
126
+ `quote_timestamp_with_to_timestamp` will be deprecated in future version of Oracle enhanced adapter.
127
+ Also this method should not be called directly. Let Abstract adapter `_quote` method handle it.
128
+ MSG
129
+ # add up to 9 digits of fractional seconds to inserted time
130
+ value = "#{quoted_date(value)}:#{("%.6f"%value.to_f).split('.')[1]}" if value.acts_like?(:time)
131
+ "TO_TIMESTAMP('#{value}','YYYY-MM-DD HH24:MI:SS:FF6')"
132
+ end
133
+
134
+ # Cast a +value+ to a type that the database understands.
135
+ def type_cast(value, column = nil)
136
+ super
137
+ end
138
+
139
+ def _type_cast(value)
140
+ case value
141
+ when true, false
142
+ #if emulate_booleans_from_strings || column && column.type == :string
143
+ if emulate_booleans_from_strings
144
+ self.class.boolean_to_string(value)
145
+ else
146
+ value ? 1 : 0
147
+ end
148
+ when Date, Time
149
+ if value.acts_like?(:time)
150
+ zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
151
+ value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
152
+ else
153
+ value
154
+ end
155
+ when ActiveRecord::OracleEnhanced::Type::NationalCharacterString::Data
156
+ value.to_s
157
+ else
158
+ super
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+
166
+ # if MRI or YARV
167
+ if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
168
+ require 'active_record/connection_adapters/oracle_enhanced/oci_quoting'
169
+ # if JRuby
170
+ elsif RUBY_ENGINE == 'jruby'
171
+ require 'active_record/connection_adapters/oracle_enhanced/jdbc_quoting'
172
+ else
173
+ raise "Unsupported Ruby engine #{RUBY_ENGINE}"
174
+ end
@@ -19,21 +19,27 @@ module ActiveRecord
19
19
  end
20
20
 
21
21
  def visit_TableDefinition(o)
22
- create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE "
23
- create_sql << "#{quote_table_name(o.name)} ("
24
- create_sql << o.columns.map { |c| accept c }.join(', ')
25
- create_sql << ")"
22
+ create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
23
+ statements = o.columns.map { |c| accept c }
24
+ statements << accept(o.primary_keys) if o.primary_keys
25
+
26
+ if supports_foreign_keys?
27
+ statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
28
+ end
29
+
30
+ create_sql << "(#{statements.join(', ')})" if statements.present?
26
31
 
27
32
  unless o.temporary
28
33
  @lob_tablespaces.each do |lob_column, tablespace|
29
34
  create_sql << " LOB (#{quote_column_name(lob_column)}) STORE AS (TABLESPACE #{tablespace}) \n"
30
35
  end if defined?(@lob_tablespaces)
31
- create_sql << " ORGANIZATION #{o.options[:organization]}" if o.options[:organization]
32
- if (tablespace = o.options[:tablespace] || default_tablespace_for(:table))
36
+ create_sql << " ORGANIZATION #{o.organization}" if o.organization
37
+ if (tablespace = o.tablespace || default_tablespace_for(:table))
33
38
  create_sql << " TABLESPACE #{tablespace}"
34
39
  end
35
40
  end
36
- create_sql << " #{o.options[:options]}"
41
+ add_table_options!(create_sql, table_options(o))
42
+ create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
37
43
  create_sql
38
44
  end
39
45
 
@@ -50,7 +56,7 @@ module ActiveRecord
50
56
  if type == :text
51
57
  sql << " DEFAULT #{@conn.quote(options[:default])}"
52
58
  else
53
- sql << " DEFAULT #{quote_value(options[:default], options[:column])}"
59
+ sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}"
54
60
  end
55
61
  end
56
62
  # must explicitly add NULL or NOT NULL to allow change_column to work on migrations
@@ -63,6 +69,9 @@ module ActiveRecord
63
69
  if options[:as].present?
64
70
  sql << " AS (#{options[:as]})"
65
71
  end
72
+ if options[:primary_key] == true
73
+ sql << " PRIMARY KEY"
74
+ end
66
75
  end
67
76
 
68
77
  def action_sql(action, dependency)
@@ -26,25 +26,26 @@ module ActiveRecord
26
26
  end
27
27
 
28
28
  class IndexDefinition < ActiveRecord::ConnectionAdapters::IndexDefinition
29
- attr_accessor :table, :name, :unique, :type, :parameters, :statement_parameters, :tablespace, :columns
29
+ attr_accessor :parameters, :statement_parameters, :tablespace
30
30
 
31
- def initialize(table, name, unique, type, parameters, statement_parameters, tablespace, columns)
32
- @table = table
33
- @name = name
34
- @unique = unique
35
- @type = type
31
+ def initialize(table, name, unique, columns, lengths, orders, where, type, using, parameters, statement_parameters, tablespace)
36
32
  @parameters = parameters
37
33
  @statement_parameters = statement_parameters
38
34
  @tablespace = tablespace
39
- @columns = columns
40
- super(table, name, unique, columns, nil, nil, nil, nil)
35
+ super(table, name, unique, columns, lengths, orders, where, type, using)
41
36
  end
42
37
  end
43
38
 
44
- class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
39
+ class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
40
+
41
+ end
45
42
 
46
- def raw(name, options={})
47
- column(name, :raw, options)
43
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
44
+ attr_accessor :tablespace, :organization
45
+ def initialize(name, temporary = false, options = nil, as = nil, tablespace = nil, organization = nil, comment: nil)
46
+ @tablespace = tablespace
47
+ @organization = organization
48
+ super(name, temporary, options, as, comment: comment)
48
49
  end
49
50
 
50
51
  def virtual(* args)
@@ -69,6 +70,11 @@ module ActiveRecord
69
70
  super(name, type, options)
70
71
  end
71
72
 
73
+ private
74
+ def create_column_definition(name, type)
75
+ OracleEnhanced::ColumnDefinition.new name, type
76
+ end
77
+
72
78
  end
73
79
 
74
80
  class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
@@ -1,225 +1,207 @@
1
1
  module ActiveRecord #:nodoc:
2
2
  module ConnectionAdapters #:nodoc:
3
- module OracleEnhancedSchemaDumper #:nodoc:
3
+ module OracleEnhanced #:nodoc:
4
+ module SchemaDumper #:nodoc:
4
5
 
5
- def self.included(base) #:nodoc:
6
- base.class_eval do
7
- private
8
- alias_method_chain :tables, :oracle_enhanced
9
- alias_method_chain :indexes, :oracle_enhanced
10
- alias_method_chain :foreign_keys, :oracle_enhanced
11
- end
12
- end
13
-
14
- private
6
+ private
15
7
 
16
- def ignore_table?(table)
17
- ['schema_migrations', ignore_tables].flatten.any? do |ignored|
18
- case ignored
19
- when String; remove_prefix_and_suffix(table) == ignored
20
- when Regexp; remove_prefix_and_suffix(table) =~ ignored
21
- else
22
- raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
8
+ def tables(stream)
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)
23
25
  end
24
- end
25
- end
26
26
 
27
- def tables_with_oracle_enhanced(stream)
28
- return tables_without_oracle_enhanced(stream) unless @connection.respond_to?(:materialized_views)
29
- # do not include materialized views in schema dump - they should be created separately after schema creation
30
- sorted_tables = (@connection.tables - @connection.materialized_views).sort
31
- sorted_tables.each do |tbl|
32
- # add table prefix or suffix for schema_migrations
33
- next if ignore_table? tbl
34
- # change table name inspect method
35
- tbl.extend TableInspect
36
- oracle_enhanced_table(tbl, stream)
37
- # add primary key trigger if table has it
38
- primary_key_trigger(tbl, stream)
39
- end
40
- # following table definitions
41
- # add foreign keys if table has them
42
- sorted_tables.each do |tbl|
43
- next if ignore_table? tbl
44
- foreign_keys(tbl, stream)
27
+ # add synonyms in local schema
28
+ synonyms(stream)
45
29
  end
46
30
 
47
- # add synonyms in local schema
48
- synonyms(stream)
49
- end
50
-
51
- def primary_key_trigger(table_name, stream)
52
- if @connection.respond_to?(:has_primary_key_trigger?) && @connection.has_primary_key_trigger?(table_name)
53
- pk, _pk_seq = @connection.pk_and_sequence_for(table_name)
54
- stream.print " add_primary_key_trigger #{table_name.inspect}"
55
- stream.print ", primary_key: \"#{pk}\"" if pk != 'id'
56
- 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
57
38
  end
58
- end
59
39
 
60
- def foreign_keys_with_oracle_enhanced(table_name, stream)
61
- return foreign_keys_without_oracle_enhanced(table_name, stream)
62
- end
63
-
64
- def synonyms(stream)
65
- if @connection.respond_to?(:synonyms)
66
- syns = @connection.synonyms
67
- syns.each do |syn|
68
- next if ignore_table? syn.name
69
- table_name = syn.table_name
70
- table_name = "#{syn.table_owner}.#{table_name}" if syn.table_owner
71
- table_name = "#{table_name}@#{syn.db_link}" if syn.db_link
72
- stream.print " add_synonym #{syn.name.inspect}, #{table_name.inspect}, force: true"
73
- stream.puts
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?
74
52
  end
75
- stream.puts unless syns.empty?
76
53
  end
77
- end
78
54
 
79
- def indexes_with_oracle_enhanced(table, stream)
80
- # return original method if not using oracle_enhanced
81
- if (rails_env = defined?(Rails.env) ? Rails.env : (defined?(RAILS_ENV) ? RAILS_ENV : nil)) &&
82
- ActiveRecord::Base.configurations[rails_env] &&
83
- ActiveRecord::Base.configurations[rails_env]['adapter'] != 'oracle_enhanced'
84
- return indexes_without_oracle_enhanced(table, stream)
85
- end
86
- if (indexes = @connection.indexes(table)).any?
87
- add_index_statements = indexes.map do |index|
88
- case index.type
89
- when nil
90
- # use table.inspect as it will remove prefix and suffix
91
- statement_parts = [ ('add_index ' + table.inspect) ]
92
- statement_parts << index.columns.inspect
93
- statement_parts << ('name: ' + index.name.inspect)
94
- statement_parts << 'unique: true' if index.unique
95
- statement_parts << 'tablespace: ' + index.tablespace.inspect if index.tablespace
96
- when 'CTXSYS.CONTEXT'
97
- if index.statement_parameters
98
- statement_parts = [ ('add_context_index ' + table.inspect) ]
99
- statement_parts << index.statement_parameters
100
- else
101
- statement_parts = [ ('add_context_index ' + table.inspect) ]
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) ]
102
62
  statement_parts << index.columns.inspect
103
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
70
+ else
71
+ statement_parts = [ ('add_context_index ' + table.inspect) ]
72
+ statement_parts << index.columns.inspect
73
+ statement_parts << ('name: ' + index.name.inspect)
74
+ end
75
+ else
76
+ # unrecognized index type
77
+ statement_parts = ["# unrecognized index #{index.name.inspect} with type #{index.type.inspect}"]
104
78
  end
105
- else
106
- # unrecognized index type
107
- statement_parts = ["# unrecognized index #{index.name.inspect} with type #{index.type.inspect}"]
79
+ ' ' + statement_parts.join(', ')
108
80
  end
109
- ' ' + statement_parts.join(', ')
110
- end
111
81
 
112
- stream.puts add_index_statements.sort.join("\n")
113
- stream.puts
82
+ stream.puts add_index_statements.sort.join("\n")
83
+ stream.puts
84
+ end
114
85
  end
115
- end
116
86
 
117
- def oracle_enhanced_table(table, stream)
118
- columns = @connection.columns(table)
119
- begin
120
- tbl = StringIO.new
87
+ def table(table, stream)
88
+ columns = @connection.columns(table)
89
+ begin
90
+ tbl = StringIO.new
121
91
 
122
- # first dump primary key column
123
- if @connection.respond_to?(:pk_and_sequence_for)
124
- pk, _pk_seq = @connection.pk_and_sequence_for(table)
125
- elsif @connection.respond_to?(:primary_key)
126
- pk = @connection.primary_key(table)
127
- end
92
+ # first dump primary key column
93
+ if @connection.respond_to?(:primary_keys)
94
+ pk = @connection.primary_keys(table)
95
+ pk = pk.first unless pk.size > 1
96
+ else
97
+ pk = @connection.primary_key(table)
98
+ end
128
99
 
129
- tbl.print " create_table #{table.inspect}"
100
+ tbl.print " create_table #{table.inspect}"
130
101
 
131
- # addition to make temporary option work
132
- tbl.print ", temporary: true" if @connection.temporary_table?(table)
102
+ # addition to make temporary option work
103
+ tbl.print ", temporary: true" if @connection.temporary_table?(table)
133
104
 
134
- table_comments = @connection.table_comment(table)
135
- unless table_comments.nil?
136
- tbl.print ", comment: #{table_comments.inspect}"
137
- end
105
+ table_comments = @connection.table_comment(table)
106
+ unless table_comments.nil?
107
+ tbl.print ", comment: #{table_comments.inspect}"
108
+ end
138
109
 
139
- if columns.detect { |c| c.name == pk }
140
- if pk != 'id'
141
- tbl.print %Q(, primary_key: "#{pk}")
110
+ case pk
111
+ when String
112
+ tbl.print ", primary_key: #{pk.inspect}" unless pk == 'id'
113
+ pkcol = columns.detect { |c| c.name == pk }
114
+ pkcolspec = @connection.column_spec_for_primary_key(pkcol)
115
+ if pkcolspec.present?
116
+ pkcolspec.each do |key, value|
117
+ tbl.print ", #{key}: #{value}"
118
+ end
119
+ end
120
+ when Array
121
+ tbl.print ", primary_key: #{pk.inspect}"
122
+ else
123
+ tbl.print ", id: false"
142
124
  end
143
- else
144
- tbl.print ", id: false"
145
- end
146
- tbl.print ", force: :cascade"
147
- tbl.puts " do |t|"
148
125
 
149
- # then dump all non-primary key columns
150
- column_specs = columns.map do |column|
151
- raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
152
- next if column.name == pk
153
- @connection.column_spec(column, @types)
154
- end.compact
126
+ tbl.print ", force: :cascade"
127
+ tbl.puts " do |t|"
128
+
129
+ # then dump all non-primary key columns
130
+ column_specs = columns.map do |column|
131
+ raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
132
+ next if column.name == pk
133
+ @connection.column_spec(column)
134
+ end.compact
135
+
136
+ # find all migration keys used in this table
137
+ #
138
+ # TODO `& column_specs.map(&:keys).flatten` should be executed
139
+ # in migration_keys_with_oracle_enhanced
140
+ keys = @connection.migration_keys & column_specs.map(&:keys).flatten
155
141
 
156
- # find all migration keys used in this table
157
- #
158
- # TODO `& column_specs.map(&:keys).flatten` should be executed
159
- # in migration_keys_with_oracle_enhanced
160
- keys = @connection.migration_keys & column_specs.map(&:keys).flatten
142
+ # figure out the lengths for each column based on above keys
143
+ lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
161
144
 
162
- # figure out the lengths for each column based on above keys
163
- lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
145
+ # the string we're going to sprintf our values against, with standardized column widths
146
+ format_string = lengths.map{ |len| "%-#{len}s" }
164
147
 
165
- # the string we're going to sprintf our values against, with standardized column widths
166
- format_string = lengths.map{ |len| "%-#{len}s" }
148
+ # find the max length for the 'type' column, which is special
149
+ type_length = column_specs.map{ |column| column[:type].length }.max
167
150
 
168
- # find the max length for the 'type' column, which is special
169
- type_length = column_specs.map{ |column| column[:type].length }.max
151
+ # add column type definition to our format string
152
+ format_string.unshift " t.%-#{type_length}s "
170
153
 
171
- # add column type definition to our format string
172
- format_string.unshift " t.%-#{type_length}s "
154
+ format_string *= ''
173
155
 
174
- format_string *= ''
156
+ # dirty hack to replace virtual_type: with type:
157
+ column_specs.each do |colspec|
158
+ values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
159
+ values.unshift colspec[:type]
160
+ tbl.print((format_string % values).gsub(/,\s*$/, '').gsub(/virtual_type:/, "type:"))
161
+ tbl.puts
162
+ end
175
163
 
176
- column_specs.each do |colspec|
177
- values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
178
- values.unshift colspec[:type]
179
- tbl.print((format_string % values).gsub(/,\s*$/, ''))
164
+ tbl.puts " end"
180
165
  tbl.puts
166
+
167
+ indexes(table, tbl)
168
+
169
+ tbl.rewind
170
+ stream.print tbl.read
171
+ rescue => e
172
+ stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
173
+ stream.puts "# #{e.message}"
174
+ stream.puts
181
175
  end
182
176
 
183
- tbl.puts " end"
184
- tbl.puts
185
-
186
- indexes(table, tbl)
187
-
188
- tbl.rewind
189
- stream.print tbl.read
190
- rescue => e
191
- stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
192
- stream.puts "# #{e.message}"
193
- stream.puts
177
+ stream
194
178
  end
195
-
196
- stream
197
- end
198
179
 
199
- def remove_prefix_and_suffix(table)
200
- table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
201
- end
202
-
203
- # remove table name prefix and suffix when doing #inspect (which is used in tables method)
204
- module TableInspect #:nodoc:
205
- def inspect
206
- remove_prefix_and_suffix(self)
180
+ def remove_prefix_and_suffix(table)
181
+ table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
207
182
  end
208
-
209
- private
210
- def remove_prefix_and_suffix(table_name)
211
- if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix.to_s.gsub('$','\$')}(.*)#{ActiveRecord::Base.table_name_suffix.to_s.gsub('$','\$')}\Z/
212
- "\"#{$1}\""
213
- else
214
- "\"#{table_name}\""
183
+
184
+ # remove table name prefix and suffix when doing #inspect (which is used in tables method)
185
+ module TableInspect #:nodoc:
186
+ def inspect
187
+ remove_prefix_and_suffix(self)
188
+ end
189
+
190
+ private
191
+ def remove_prefix_and_suffix(table_name)
192
+ if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix.to_s.gsub('$','\$')}(.*)#{ActiveRecord::Base.table_name_suffix.to_s.gsub('$','\$')}\Z/
193
+ "\"#{$1}\""
194
+ else
195
+ "\"#{table_name}\""
196
+ end
215
197
  end
216
198
  end
217
- end
218
199
 
200
+ end
219
201
  end
220
202
  end
221
- end
222
203
 
223
- ActiveRecord::SchemaDumper.class_eval do
224
- include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaDumper
204
+ class SchemaDumper #:nodoc:
205
+ prepend ConnectionAdapters::OracleEnhanced::SchemaDumper
206
+ end
225
207
  end