activerecord-oracle_enhanced-adapter 1.8.2 → 5.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +190 -5
  3. data/README.md +10 -10
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +2 -0
  6. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +9 -71
  7. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +84 -73
  8. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +12 -12
  9. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +52 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +35 -7
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +2 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +59 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +379 -402
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +7 -1
  15. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +46 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +242 -247
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +9 -1
  18. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +3 -1
  19. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +25 -9
  20. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +9 -6
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +10 -5
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +48 -51
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +261 -59
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +2 -34
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +267 -222
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +33 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +2 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +136 -547
  29. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/boolean.rb +4 -2
  30. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/integer.rb +4 -2
  31. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  32. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/national_character_string.rb +5 -3
  33. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  34. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/raw.rb +4 -2
  35. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/string.rb +4 -2
  36. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/text.rb +4 -2
  37. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  38. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/timestamptz.rb +4 -2
  39. data/lib/activerecord-oracle_enhanced-adapter.rb +2 -6
  40. data/spec/active_record/connection_adapters/{oracle_enhanced_emulate_oracle_adapter_spec.rb → emulation/oracle_adapter_spec.rb} +2 -0
  41. data/spec/active_record/connection_adapters/{oracle_enhanced_connection_spec.rb → oracle_enhanced/connection_spec.rb} +82 -38
  42. data/spec/active_record/connection_adapters/{oracle_enhanced_context_index_spec.rb → oracle_enhanced/context_index_spec.rb} +20 -16
  43. data/spec/active_record/connection_adapters/{oracle_enhanced_database_tasks_spec.rb → oracle_enhanced/database_tasks_spec.rb} +17 -5
  44. data/spec/active_record/connection_adapters/{oracle_enhanced_dbms_output_spec.rb → oracle_enhanced/dbms_output_spec.rb} +2 -0
  45. data/spec/active_record/connection_adapters/{oracle_enhanced_procedures_spec.rb → oracle_enhanced/procedures_spec.rb} +26 -33
  46. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +196 -0
  47. data/spec/active_record/connection_adapters/{oracle_enhanced_schema_dump_spec.rb → oracle_enhanced/schema_dumper_spec.rb} +61 -90
  48. data/spec/active_record/connection_adapters/{oracle_enhanced_schema_statements_spec.rb → oracle_enhanced/schema_statements_spec.rb} +95 -28
  49. data/spec/active_record/connection_adapters/{oracle_enhanced_structure_dump_spec.rb → oracle_enhanced/structure_dump_spec.rb} +48 -2
  50. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +202 -331
  51. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +15 -1106
  52. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  53. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +207 -0
  54. data/spec/active_record/{connection_adapters/oracle_enhanced_dirty_spec.rb → oracle_enhanced/type/dirty_spec.rb} +3 -1
  55. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  56. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +91 -0
  57. data/spec/active_record/oracle_enhanced/type/json_spec.rb +57 -0
  58. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  59. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  60. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +122 -0
  61. data/spec/active_record/oracle_enhanced/type/text_spec.rb +229 -0
  62. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +75 -0
  63. data/spec/spec_helper.rb +15 -1
  64. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  65. metadata +63 -48
  66. data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +0 -28
  67. data/lib/active_record/oracle_enhanced/type/json.rb +0 -8
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module OracleEnhanced
@@ -10,12 +12,18 @@ module ActiveRecord
10
12
  ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
11
13
  ora_value.size = 0 if value == ""
12
14
  ora_value
13
- when ActiveRecord::OracleEnhanced::Type::Text::Data
15
+ when Type::OracleEnhanced::Text::Data
14
16
  lob_value = value.to_s == "" ? " " : value.to_s
15
17
  bind_type = OCI8::CLOB
16
18
  ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
17
19
  ora_value.size = 0 if value.to_s == ""
18
20
  ora_value
21
+ when Type::OracleEnhanced::NationalCharacterText::Data
22
+ lob_value = value.to_s == "" ? " " : value.to_s
23
+ bind_type = OCI8::NCLOB
24
+ ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
25
+ ora_value.size = 0 if value.to_s == ""
26
+ ora_value
19
27
  else
20
28
  super
21
29
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support"
2
4
 
3
5
  module ActiveRecord #:nodoc:
@@ -144,7 +146,7 @@ module ActiveRecord #:nodoc:
144
146
 
145
147
  timestamp_attributes_for_update_in_model.each do |column|
146
148
  column = column.to_s
147
- next if attribute_changed?(column)
149
+ next if will_save_change_to_attribute?(column)
148
150
  write_attribute(column, current_time)
149
151
  end
150
152
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module OracleEnhanced
@@ -62,8 +64,8 @@ module ActiveRecord
62
64
  # and pound sign (#). Database links can also contain periods (.) and
63
65
  # "at" signs (@). Oracle strongly discourages you from using $ and # in
64
66
  # 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
+ NONQUOTED_OBJECT_NAME = /[[:alpha:]][\w$#]{0,29}/
68
+ NONQUOTED_DATABASE_LINK = /[[:alpha:]][\w$#\.@]{0,127}/
67
69
  VALID_TABLE_NAME = /\A(?:#{NONQUOTED_OBJECT_NAME}\.)?#{NONQUOTED_OBJECT_NAME}(?:@#{NONQUOTED_DATABASE_LINK})?\Z/
68
70
 
69
71
  # unescaped table name should start with letter and
@@ -71,8 +73,13 @@ module ActiveRecord
71
73
  # can be prefixed with schema name
72
74
  # CamelCase table names should be quoted
73
75
  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
+ object_name = name.to_s
77
+ !!(object_name =~ VALID_TABLE_NAME && !mixed_case?(object_name))
78
+ end
79
+
80
+ def self.mixed_case?(name)
81
+ object_name = name.include?(".") ? name.split(".").second : name
82
+ !!(object_name =~ /[A-Z]/ && object_name =~ /[a-z]/)
76
83
  end
77
84
 
78
85
  def quote_table_name(name) #:nodoc:
@@ -86,12 +93,14 @@ module ActiveRecord
86
93
 
87
94
  def _quote(value) #:nodoc:
88
95
  case value
89
- when ActiveRecord::OracleEnhanced::Type::NationalCharacterString::Data then
90
- "N" << "'#{quote_string(value.to_s)}'"
96
+ when Type::OracleEnhanced::NationalCharacterString::Data then
97
+ "N".dup << "'#{quote_string(value.to_s)}'"
91
98
  when ActiveModel::Type::Binary::Data then
92
99
  "empty_blob()"
93
- when ActiveRecord::OracleEnhanced::Type::Text::Data then
100
+ when Type::OracleEnhanced::Text::Data then
94
101
  "empty_clob()"
102
+ when Type::OracleEnhanced::NationalCharacterText::Data then
103
+ "empty_nclob()"
95
104
  else
96
105
  super
97
106
  end
@@ -119,19 +128,26 @@ module ActiveRecord
119
128
 
120
129
  def _type_cast(value)
121
130
  case value
122
- when ActiveRecord::OracleEnhanced::Type::TimestampTz::Data
131
+ when Type::OracleEnhanced::TimestampTz::Data, Type::OracleEnhanced::TimestampLtz::Data
123
132
  if value.acts_like?(:time)
124
133
  zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
125
134
  value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
126
135
  else
127
136
  value
128
137
  end
129
- when ActiveRecord::OracleEnhanced::Type::NationalCharacterString::Data
138
+ when Type::OracleEnhanced::NationalCharacterString::Data
130
139
  value.to_s
131
140
  else
132
141
  super
133
142
  end
134
143
  end
144
+
145
+ private
146
+
147
+ def oracle_downcase(column_name)
148
+ return nil if column_name.nil?
149
+ column_name =~ /[a-z]/ ? column_name : column_name.downcase
150
+ end
135
151
  end
136
152
  end
137
153
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module OracleEnhanced
@@ -5,7 +7,7 @@ module ActiveRecord
5
7
  private
6
8
 
7
9
  def visit_ColumnDefinition(o)
8
- if [:blob, :clob].include?(sql_type = type_to_sql(o.type, o.options).downcase.to_sym)
10
+ if [:blob, :clob, :nclob].include?(sql_type = type_to_sql(o.type, o.options).downcase.to_sym)
9
11
  if (tablespace = default_tablespace_for(sql_type))
10
12
  @lob_tablespaces ||= {}
11
13
  @lob_tablespaces[o.name] = tablespace
@@ -15,7 +17,7 @@ module ActiveRecord
15
17
  end
16
18
 
17
19
  def visit_TableDefinition(o)
18
- create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
20
+ create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} ".dup
19
21
  statements = o.columns.map { |c| accept c }
20
22
  statements << accept(o.primary_keys) if o.primary_keys
21
23
 
@@ -35,22 +37,23 @@ module ActiveRecord
35
37
  end
36
38
  end
37
39
  add_table_options!(create_sql, table_options(o))
38
- create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
40
+ create_sql << " AS #{to_sql(o.as)}" if o.as
39
41
  create_sql
40
42
  end
41
43
 
42
44
  def default_tablespace_for(type)
43
- (ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[type] ||
44
- ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[native_database_types[type][:name]]) rescue nil
45
+ OracleEnhancedAdapter.default_tablespaces[type]
45
46
  end
46
47
 
47
48
  def add_column_options!(sql, options)
48
49
  type = options[:type] || ((column = options[:column]) && column.type)
49
50
  type = type && type.to_sym
50
- # handle case of defaults for CLOB columns, which would otherwise get "quoted" incorrectly
51
+ # handle case of defaults for CLOB/NCLOB columns, which would otherwise get "quoted" incorrectly
51
52
  if options_include_default?(options)
52
53
  if type == :text
53
54
  sql << " DEFAULT #{@conn.quote(options[:default])}"
55
+ elsif type == :ntext
56
+ sql << " DEFAULT #{@conn.quote(options[:default])}"
54
57
  else
55
58
  sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}"
56
59
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module OracleEnhanced
@@ -8,7 +10,10 @@ module ActiveRecord
8
10
  end
9
11
 
10
12
  [
11
- :raw
13
+ :raw,
14
+ :timestamptz,
15
+ :timestampltz,
16
+ :ntext
12
17
  ].each do |column_type|
13
18
  module_eval <<-CODE, __FILE__, __LINE__ + 1
14
19
  def #{column_type}(*args, **options)
@@ -36,16 +41,16 @@ module ActiveRecord
36
41
  class IndexDefinition < ActiveRecord::ConnectionAdapters::IndexDefinition
37
42
  attr_accessor :parameters, :statement_parameters, :tablespace
38
43
 
39
- def initialize(table, name, unique, columns, lengths, orders, where, type, using, parameters, statement_parameters, tablespace)
44
+ def initialize(table, name, unique, columns, orders, type, parameters, statement_parameters, tablespace)
40
45
  @parameters = parameters
41
46
  @statement_parameters = statement_parameters
42
47
  @tablespace = tablespace
43
- super(table, name, unique, columns, lengths, orders, where, type, using)
48
+ super(table, name, unique, columns, orders: orders, type: type)
44
49
  end
45
50
  end
46
51
 
47
52
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
48
- include ActiveRecord::ConnectionAdapters::OracleEnhanced::ColumnMethods
53
+ include OracleEnhanced::ColumnMethods
49
54
 
50
55
  attr_accessor :tablespace, :organization
51
56
  def initialize(name, temporary = false, options = nil, as = nil, tablespace = nil, organization = nil, comment: nil)
@@ -67,7 +72,7 @@ module ActiveRecord
67
72
  end
68
73
 
69
74
  class Table < ActiveRecord::ConnectionAdapters::Table
70
- include ActiveRecord::ConnectionAdapters::OracleEnhanced::ColumnMethods
75
+ include OracleEnhanced::ColumnMethods
71
76
  end
72
77
  end
73
78
  end
@@ -1,18 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord #:nodoc:
2
4
  module ConnectionAdapters #:nodoc:
3
5
  module OracleEnhanced #:nodoc:
4
- module SchemaDumper #:nodoc:
6
+ class SchemaDumper < ConnectionAdapters::SchemaDumper #:nodoc:
5
7
  private
6
8
 
7
9
  def tables(stream)
8
- return super unless @connection.respond_to?(:materialized_views)
9
10
  # do not include materialized views in schema dump - they should be created separately after schema creation
10
11
  sorted_tables = (@connection.tables - @connection.materialized_views).sort
11
12
  sorted_tables.each do |tbl|
12
13
  # add table prefix or suffix for schema_migrations
13
14
  next if ignored? tbl
14
- # change table name inspect method
15
- tbl.extend TableInspect
16
15
  table(tbl, stream)
17
16
  # add primary key trigger if table has it
18
17
  primary_key_trigger(tbl, stream)
@@ -29,7 +28,7 @@ module ActiveRecord #:nodoc:
29
28
  end
30
29
 
31
30
  def primary_key_trigger(table_name, stream)
32
- if @connection.respond_to?(:has_primary_key_trigger?) && @connection.has_primary_key_trigger?(table_name)
31
+ if @connection.has_primary_key_trigger?(table_name)
33
32
  pk, _pk_seq = @connection.pk_and_sequence_for(table_name)
34
33
  stream.print " add_primary_key_trigger #{table_name.inspect}"
35
34
  stream.print ", primary_key: \"#{pk}\"" if pk != "id"
@@ -38,21 +37,19 @@ module ActiveRecord #:nodoc:
38
37
  end
39
38
 
40
39
  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?
40
+ syns = @connection.synonyms
41
+ syns.each do |syn|
42
+ next if ignored? syn.name
43
+ table_name = syn.table_name
44
+ table_name = "#{syn.table_owner}.#{table_name}" if syn.table_owner
45
+ table_name = "#{table_name}@#{syn.db_link}" if syn.db_link
46
+ stream.print " add_synonym #{syn.name.inspect}, #{table_name.inspect}, force: true"
47
+ stream.puts
52
48
  end
49
+ stream.puts unless syns.empty?
53
50
  end
54
51
 
55
- def indexes(table, stream)
52
+ def _indexes(table, stream)
56
53
  if (indexes = @connection.indexes(table)).any?
57
54
  add_index_statements = indexes.map do |index|
58
55
  case index.type
@@ -61,10 +58,10 @@ module ActiveRecord #:nodoc:
61
58
  statement_parts = []
62
59
  when "CTXSYS.CONTEXT"
63
60
  if index.statement_parameters
64
- statement_parts = [ ("add_context_index " + table.inspect) ]
61
+ statement_parts = [ ("add_context_index " + remove_prefix_and_suffix(table).inspect) ]
65
62
  statement_parts << index.statement_parameters
66
63
  else
67
- statement_parts = [ ("add_context_index " + table.inspect) ]
64
+ statement_parts = [ ("add_context_index " + remove_prefix_and_suffix(table).inspect) ]
68
65
  statement_parts << index.columns.inspect
69
66
  statement_parts << ("name: " + index.name.inspect)
70
67
  end
@@ -92,14 +89,12 @@ module ActiveRecord #:nodoc:
92
89
  end
93
90
 
94
91
  def index_parts(index)
95
- return super unless @connection.respond_to?(:temporary_table?)
96
92
  index_parts = super
97
93
  index_parts << "tablespace: #{index.tablespace.inspect}" if index.tablespace
98
94
  index_parts
99
95
  end
100
96
 
101
97
  def table(table, stream)
102
- return super unless @connection.respond_to?(:temporary_table?)
103
98
  columns = @connection.columns(table)
104
99
  begin
105
100
  tbl = StringIO.new
@@ -112,7 +107,7 @@ module ActiveRecord #:nodoc:
112
107
  pk = @connection.primary_key(table)
113
108
  end
114
109
 
115
- tbl.print " create_table #{table.inspect}"
110
+ tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
116
111
 
117
112
  # addition to make temporary option work
118
113
  tbl.print ", temporary: true" if @connection.temporary_table?(table)
@@ -121,7 +116,7 @@ module ActiveRecord #:nodoc:
121
116
  when String
122
117
  tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
123
118
  pkcol = columns.detect { |c| c.name == pk }
124
- pkcolspec = @connection.column_spec_for_primary_key(pkcol)
119
+ pkcolspec = column_spec_for_primary_key(pkcol)
125
120
  if pkcolspec.present?
126
121
  tbl.print ", #{format_colspec(pkcolspec)}"
127
122
  end
@@ -131,20 +126,18 @@ module ActiveRecord #:nodoc:
131
126
  tbl.print ", id: false"
132
127
  end
133
128
 
134
- tbl.print ", force: :cascade"
135
-
136
- table_comments = @connection.table_comment(table)
137
- unless table_comments.blank?
138
- tbl.print ", comment: #{table_comments.inspect}"
129
+ table_options = @connection.table_options(table)
130
+ if table_options.present?
131
+ tbl.print ", #{format_options(table_options)}"
139
132
  end
140
133
 
141
- tbl.puts " do |t|"
134
+ tbl.puts ", force: :cascade do |t|"
142
135
 
143
136
  # then dump all non-primary key columns
144
137
  columns.each do |column|
145
138
  raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
146
139
  next if column.name == pk
147
- type, colspec = @connection.column_spec(column)
140
+ type, colspec = column_spec(column)
148
141
  tbl.print " t.#{type} #{column.name.inspect}"
149
142
  tbl.print ", #{format_colspec(colspec)}" if colspec.present?
150
143
  tbl.puts
@@ -155,7 +148,7 @@ module ActiveRecord #:nodoc:
155
148
  tbl.puts " end"
156
149
  tbl.puts
157
150
 
158
- indexes(table, tbl)
151
+ _indexes(table, tbl)
159
152
 
160
153
  tbl.rewind
161
154
  stream.print tbl.read
@@ -164,34 +157,38 @@ module ActiveRecord #:nodoc:
164
157
  stream.puts "# #{e.message}"
165
158
  stream.puts
166
159
  end
160
+ end
161
+
162
+ def prepare_column_options(column)
163
+ spec = super
164
+
165
+ if @connection.supports_virtual_columns? && column.virtual?
166
+ spec[:as] = extract_expression_for_virtual_column(column)
167
+ spec = { type: schema_type(column).inspect }.merge!(spec) unless column.type == :decimal
168
+ end
167
169
 
168
- stream
170
+ spec
169
171
  end
170
172
 
171
- def remove_prefix_and_suffix(table)
172
- table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
173
+ def default_primary_key?(column)
174
+ schema_type(column) == :integer
173
175
  end
174
176
 
175
- # remove table name prefix and suffix when doing #inspect (which is used in tables method)
176
- module TableInspect #:nodoc:
177
- def inspect
178
- remove_prefix_and_suffix(self)
179
- end
177
+ def extract_expression_for_virtual_column(column)
178
+ column_name = column.name
179
+ table_name = column.table_name
180
+ @connection.select_value(<<-SQL.strip.gsub(/\s+/, " "), "Table comment", [bind_string("table_name", table_name.upcase), bind_string("column_name", column_name.upcase)]).inspect
181
+ select data_default from all_tab_columns
182
+ where owner = SYS_CONTEXT('userenv', 'session_user')
183
+ and table_name = :table_name
184
+ and column_name = :column_name
185
+ SQL
186
+ end
180
187
 
181
- private
182
- def remove_prefix_and_suffix(table_name)
183
- if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix.to_s.gsub('$', '\$')}(.*)#{ActiveRecord::Base.table_name_suffix.to_s.gsub('$', '\$')}\Z/
184
- "\"#{$1}\""
185
- else
186
- "\"#{table_name}\""
187
- end
188
- end
188
+ def bind_string(name, value)
189
+ ActiveRecord::Relation::QueryAttribute.new(name, value, Type::OracleEnhanced::String.new)
189
190
  end
190
191
  end
191
192
  end
192
193
  end
193
-
194
- class SchemaDumper #:nodoc:
195
- prepend ConnectionAdapters::OracleEnhanced::SchemaDumper
196
- end
197
194
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "digest/sha1"
2
4
 
3
5
  module ActiveRecord
@@ -8,6 +10,148 @@ module ActiveRecord
8
10
  #
9
11
  # see: abstract/schema_statements.rb
10
12
 
13
+ def tables #:nodoc:
14
+ select_values(<<-SQL.strip.gsub(/\s+/, " "), "tables")
15
+ SELECT DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name)
16
+ FROM all_tables
17
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
18
+ AND secondary = 'N'
19
+ SQL
20
+ end
21
+
22
+ def data_sources
23
+ super | synonyms.map(&:name)
24
+ end
25
+
26
+ def table_exists?(table_name)
27
+ table_name = table_name.to_s
28
+ if table_name.include?("@")
29
+ # db link is not table
30
+ false
31
+ else
32
+ default_owner = current_schema
33
+ end
34
+ real_name = OracleEnhanced::Quoting.valid_table_name?(table_name) ?
35
+ table_name.upcase : table_name
36
+ if real_name.include?(".")
37
+ table_owner, table_name = real_name.split(".")
38
+ else
39
+ table_owner, table_name = default_owner, real_name
40
+ end
41
+
42
+ select_values(<<-SQL.strip.gsub(/\s+/, " "), "table exists", [bind_string("owner", table_owner), bind_string("table_name", table_name)]).any?
43
+ SELECT owner, table_name
44
+ FROM all_tables
45
+ WHERE owner = :owner
46
+ AND table_name = :table_name
47
+ SQL
48
+ end
49
+
50
+ def data_source_exists?(table_name)
51
+ (_owner, table_name, _db_link) = @connection.describe(table_name)
52
+ true
53
+ rescue
54
+ false
55
+ end
56
+
57
+ def views # :nodoc:
58
+ select_values(<<-SQL.strip.gsub(/\s+/, " "), "views")
59
+ SELECT LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
60
+ SQL
61
+ end
62
+
63
+ def materialized_views #:nodoc:
64
+ select_values(<<-SQL.strip.gsub(/\s+/, " "), "materialized views")
65
+ SELECT LOWER(mview_name) FROM all_mviews WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
66
+ SQL
67
+ end
68
+
69
+ # get synonyms for schema dump
70
+ def synonyms
71
+ result = select_all(<<-SQL.strip.gsub(/\s+/, " "), "synonyms")
72
+ SELECT synonym_name, table_owner, table_name, db_link
73
+ FROM all_synonyms where owner = SYS_CONTEXT('userenv', 'session_user')
74
+ SQL
75
+
76
+ result.collect do |row|
77
+ OracleEnhanced::SynonymDefinition.new(oracle_downcase(row["synonym_name"]),
78
+ oracle_downcase(row["table_owner"]), oracle_downcase(row["table_name"]), oracle_downcase(row["db_link"]))
79
+ end
80
+ end
81
+
82
+ def indexes(table_name) #:nodoc:
83
+ (owner, table_name, db_link) = @connection.describe(table_name)
84
+ default_tablespace_name = default_tablespace
85
+
86
+ result = select_all(<<-SQL.strip.gsub(/\s+/, " "), "indexes", [bind_string("owner", owner), bind_string("owner", owner)])
87
+ SELECT LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
88
+ i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
89
+ LOWER(i.tablespace_name) AS tablespace_name,
90
+ LOWER(c.column_name) AS column_name, e.column_expression,
91
+ atc.virtual_column
92
+ FROM all_indexes#{db_link} i
93
+ JOIN all_ind_columns#{db_link} c ON c.index_name = i.index_name AND c.index_owner = i.owner
94
+ LEFT OUTER JOIN all_ind_expressions#{db_link} e ON e.index_name = i.index_name AND
95
+ e.index_owner = i.owner AND e.column_position = c.column_position
96
+ LEFT OUTER JOIN all_tab_cols#{db_link} atc ON i.table_name = atc.table_name AND
97
+ c.column_name = atc.column_name AND i.owner = atc.owner AND atc.hidden_column = 'NO'
98
+ WHERE i.owner = :owner
99
+ AND i.table_owner = :owner
100
+ AND NOT EXISTS (SELECT uc.index_name FROM all_constraints uc
101
+ WHERE uc.index_name = i.index_name AND uc.owner = i.owner AND uc.constraint_type = 'P')
102
+ ORDER BY i.index_name, c.column_position
103
+ SQL
104
+
105
+ current_index = nil
106
+ all_schema_indexes = []
107
+
108
+ result.each do |row|
109
+ # have to keep track of indexes because above query returns dups
110
+ # there is probably a better query we could figure out
111
+ if current_index != row["index_name"]
112
+ statement_parameters = nil
113
+ if row["index_type"] == "DOMAIN" && row["ityp_owner"] == "CTXSYS" && row["ityp_name"] == "CONTEXT"
114
+ procedure_name = default_datastore_procedure(row["index_name"])
115
+ source = select_values(<<-SQL.strip.gsub(/\s+/, " "), "procedure", [bind_string("owner", owner), bind_string("procedure_name", procedure_name.upcase)]).join
116
+ SELECT text
117
+ FROM all_source#{db_link}
118
+ WHERE owner = :owner
119
+ AND name = :procedure_name
120
+ ORDER BY line
121
+ SQL
122
+ if source =~ /-- add_context_index_parameters (.+)\n/
123
+ statement_parameters = $1
124
+ end
125
+ end
126
+ all_schema_indexes << OracleEnhanced::IndexDefinition.new(
127
+ row["table_name"],
128
+ row["index_name"],
129
+ row["uniqueness"] == "UNIQUE",
130
+ [],
131
+ nil,
132
+ row["index_type"] == "DOMAIN" ? "#{row['ityp_owner']}.#{row['ityp_name']}" : nil,
133
+ row["parameters"],
134
+ statement_parameters,
135
+ row["tablespace_name"] == default_tablespace_name ? nil : row["tablespace_name"])
136
+ current_index = row["index_name"]
137
+ end
138
+
139
+ # Functional index columns and virtual columns both get stored as column expressions,
140
+ # but re-creating a virtual column index as an expression (instead of using the virtual column's name)
141
+ # results in a ORA-54018 error. Thus, we only want the column expression value returned
142
+ # when the column is not virtual.
143
+ if row["column_expression"] && row["virtual_column"] != "YES"
144
+ all_schema_indexes.last.columns << row["column_expression"]
145
+ else
146
+ all_schema_indexes.last.columns << row["column_name"].downcase
147
+ end
148
+ end
149
+
150
+ # Return the indexes just for the requested table, since AR is structured that way
151
+ table_name = table_name.downcase
152
+ all_schema_indexes.select { |i| i.table == table_name }
153
+ end
154
+
11
155
  # Additional options for +create_table+ method in migration files.
12
156
  #
13
157
  # You can specify individual starting value in table creation migration file, e.g.:
@@ -88,10 +232,6 @@ module ActiveRecord
88
232
  rebuild_primary_key_index_to_default_tablespace(table_name, options)
89
233
  end
90
234
 
91
- def create_table_definition(*args)
92
- ActiveRecord::ConnectionAdapters::OracleEnhanced::TableDefinition.new(*args)
93
- end
94
-
95
235
  def rename_table(table_name, new_name) #:nodoc:
96
236
  if new_name.to_s.length > table_name_length
97
237
  raise ArgumentError, "New table name '#{new_name}' is too long; the limit is #{table_name_length} characters"
@@ -108,16 +248,13 @@ module ActiveRecord
108
248
  execute "DROP SEQUENCE #{quote_table_name(seq_name)}" rescue nil
109
249
  rescue ActiveRecord::StatementInvalid => e
110
250
  raise e unless options[:if_exists]
111
- ensure
112
- clear_table_columns_cache(table_name)
113
- self.all_schema_indexes = nil
114
251
  end
115
252
 
116
253
  def insert_versions_sql(versions) # :nodoc:
117
254
  sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
118
255
 
119
256
  if supports_multi_insert?
120
- versions.inject("INSERT ALL\n") { |sql, version|
257
+ versions.inject("INSERT ALL\n".dup) { |sql, version|
121
258
  sql << "INTO #{sm_table} (version) VALUES (#{quote(version)})\n"
122
259
  } << "SELECT * FROM DUAL\n"
123
260
  else
@@ -141,8 +278,6 @@ module ActiveRecord
141
278
  execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(index_name)} #{index_type} (#{quoted_column_names})"
142
279
  end
143
280
  end
144
- ensure
145
- self.all_schema_indexes = nil
146
281
  end
147
282
 
148
283
  def add_index_options(table_name, column_name, comment: nil, **options) #:nodoc:
@@ -176,8 +311,6 @@ module ActiveRecord
176
311
  #TODO: It should execute only when index_type == "UNIQUE"
177
312
  execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
178
313
  execute "DROP INDEX #{quote_column_name(index_name)}"
179
- ensure
180
- self.all_schema_indexes = nil
181
314
  end
182
315
 
183
316
  # returned shortened index name if default is too large
@@ -209,14 +342,9 @@ module ActiveRecord
209
342
  # as there's no way to determine the correct answer in that case.
210
343
  #
211
344
  # Will always query database and not index cache.
212
- def index_name_exists?(table_name, index_name, default = nil)
213
- unless default.nil?
214
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
215
- Passing default to #index_name_exists? is deprecated without replacement.
216
- MSG
217
- end
345
+ def index_name_exists?(table_name, index_name)
218
346
  (owner, table_name, db_link) = @connection.describe(table_name)
219
- result = select_value(<<-SQL)
347
+ result = select_value(<<-SQL.strip.gsub(/\s+/, " "), "index name exists")
220
348
  SELECT 1 FROM all_indexes#{db_link} i
221
349
  WHERE i.owner = '#{owner}'
222
350
  AND i.table_owner = '#{owner}'
@@ -229,12 +357,36 @@ module ActiveRecord
229
357
  def rename_index(table_name, old_name, new_name) #:nodoc:
230
358
  validate_index_length!(table_name, new_name)
231
359
  execute "ALTER INDEX #{quote_column_name(old_name)} rename to #{quote_column_name(new_name)}"
232
- ensure
233
- self.all_schema_indexes = nil
360
+ end
361
+
362
+ # Add synonym to existing table or view or sequence. Can be used to create local synonym to
363
+ # remote table in other schema or in other database
364
+ # Examples:
365
+ #
366
+ # add_synonym :posts, "blog.posts"
367
+ # add_synonym :posts_seq, "blog.posts_seq"
368
+ # add_synonym :employees, "hr.employees@dblink", :force => true
369
+ #
370
+ def add_synonym(name, table_name, options = {})
371
+ sql = "CREATE".dup
372
+ if options[:force] == true
373
+ sql << " OR REPLACE"
374
+ end
375
+ sql << " SYNONYM #{quote_table_name(name)} FOR #{quote_table_name(table_name)}"
376
+ execute sql
377
+ end
378
+
379
+ # Remove existing synonym to table or view or sequence
380
+ # Example:
381
+ #
382
+ # remove_synonym :posts, "blog.posts"
383
+ #
384
+ def remove_synonym(name)
385
+ execute "DROP SYNONYM #{quote_table_name(name)}"
234
386
  end
235
387
 
236
388
  def add_reference(table_name, *args)
237
- ActiveRecord::ConnectionAdapters::OracleEnhanced::ReferenceDefinition.new(*args).add_to(update_table_definition(table_name, self))
389
+ OracleEnhanced::ReferenceDefinition.new(*args).add_to(update_table_definition(table_name, self))
238
390
  end
239
391
 
240
392
  def add_column(table_name, column_name, type, options = {}) #:nodoc:
@@ -246,8 +398,6 @@ module ActiveRecord
246
398
  execute add_column_sql
247
399
  create_sequence_and_trigger(table_name, options) if type && type.to_sym == :primary_key
248
400
  change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
249
- ensure
250
- clear_table_columns_cache(table_name)
251
401
  end
252
402
 
253
403
  def aliased_types(name, fallback)
@@ -257,8 +407,6 @@ module ActiveRecord
257
407
  def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
258
408
  default = extract_new_default_value(default_or_changes)
259
409
  execute "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
260
- ensure
261
- clear_table_columns_cache(table_name)
262
410
  end
263
411
 
264
412
  def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
@@ -291,28 +439,24 @@ module ActiveRecord
291
439
  execute(change_column_sql)
292
440
 
293
441
  change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
294
- ensure
295
- clear_table_columns_cache(table_name)
296
442
  end
297
443
 
298
444
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
299
445
  execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} to #{quote_column_name(new_column_name)}"
300
- self.all_schema_indexes = nil
301
446
  rename_column_indexes(table_name, column_name, new_column_name)
302
- ensure
303
- clear_table_columns_cache(table_name)
304
447
  end
305
448
 
306
449
  def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
307
450
  execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)} CASCADE CONSTRAINTS"
308
- ensure
309
- clear_table_columns_cache(table_name)
310
- self.all_schema_indexes = nil
311
451
  end
312
452
 
313
453
  def change_table_comment(table_name, comment)
314
454
  clear_cache!
315
- execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
455
+ if comment.nil?
456
+ execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS ''"
457
+ else
458
+ execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
459
+ end
316
460
  end
317
461
 
318
462
  def change_column_comment(table_name, column_name, comment) #:nodoc:
@@ -322,34 +466,40 @@ module ActiveRecord
322
466
 
323
467
  def table_comment(table_name) #:nodoc:
324
468
  (owner, table_name, db_link) = @connection.describe(table_name)
325
- select_value <<-SQL
469
+ select_value(<<-SQL.strip.gsub(/\s+/, " "), "Table comment", [bind_string("owner", owner), bind_string("table_name", table_name)])
326
470
  SELECT comments FROM all_tab_comments#{db_link}
327
- WHERE owner = '#{owner}'
328
- AND table_name = '#{table_name}'
471
+ WHERE owner = :owner
472
+ AND table_name = :table_name
329
473
  SQL
330
474
  end
331
475
 
476
+ def table_options(table_name) # :nodoc:
477
+ if comment = table_comment(table_name)
478
+ { comment: comment }
479
+ end
480
+ end
481
+
332
482
  def column_comment(table_name, column_name) #:nodoc:
333
483
  # TODO: it does not exist in Abstract adapter
334
484
  (owner, table_name, db_link) = @connection.describe(table_name)
335
- select_value <<-SQL
485
+ select_value(<<-SQL.strip.gsub(/\s+/, " "), "Column comment", [bind_string("owner", owner), bind_string("table_name", table_name), bind_string("column_name", column_name.upcase)])
336
486
  SELECT comments FROM all_col_comments#{db_link}
337
- WHERE owner = '#{owner}'
338
- AND table_name = '#{table_name}'
339
- AND column_name = '#{column_name.upcase}'
487
+ WHERE owner = :owner
488
+ AND table_name = :table_name
489
+ AND column_name = :column_name
340
490
  SQL
341
491
  end
342
492
 
343
493
  # Maps logical Rails types to Oracle-specific data types.
344
494
  def type_to_sql(type, limit: nil, precision: nil, scale: nil, **) #:nodoc:
345
- # Ignore options for :text and :binary columns
346
- return super(type) if ["text", "binary"].include?(type.to_s)
495
+ # Ignore options for :text, :ntext and :binary columns
496
+ return super(type) if ["text", "ntext", "binary"].include?(type.to_s)
347
497
 
348
498
  super
349
499
  end
350
500
 
351
501
  def tablespace(table_name)
352
- select_value <<-SQL
502
+ select_value(<<-SQL.strip.gsub(/\s+/, " "), "tablespace")
353
503
  SELECT tablespace_name
354
504
  FROM all_tables
355
505
  WHERE table_name='#{table_name.to_s.upcase}'
@@ -361,7 +511,7 @@ module ActiveRecord
361
511
  def foreign_keys(table_name) #:nodoc:
362
512
  (owner, desc_table_name, db_link) = @connection.describe(table_name)
363
513
 
364
- fk_info = select_all(<<-SQL, "Foreign Keys")
514
+ fk_info = select_all(<<-SQL.strip.gsub(/\s+/, " "), "Foreign Keys", [bind_string("owner", owner), bind_string("desc_table_name", desc_table_name)])
365
515
  SELECT r.table_name to_table
366
516
  ,rc.column_name references_column
367
517
  ,cc.column_name
@@ -369,8 +519,8 @@ module ActiveRecord
369
519
  ,c.delete_rule
370
520
  FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc,
371
521
  all_constraints#{db_link} r, all_cons_columns#{db_link} rc
372
- WHERE c.owner = '#{owner}'
373
- AND c.table_name = q'[#{desc_table_name}]'
522
+ WHERE c.owner = :owner
523
+ AND c.table_name = :desc_table_name
374
524
  AND c.constraint_type = 'R'
375
525
  AND cc.owner = c.owner
376
526
  AND cc.constraint_name = c.constraint_name
@@ -403,14 +553,13 @@ module ActiveRecord
403
553
  # REFERENTIAL INTEGRITY ====================================
404
554
 
405
555
  def disable_referential_integrity(&block) #:nodoc:
406
- sql_constraints = <<-SQL
556
+ old_constraints = select_all(<<-SQL.strip.gsub(/\s+/, " "), "Foreign Keys to disable and enable")
407
557
  SELECT constraint_name, owner, table_name
408
558
  FROM all_constraints
409
559
  WHERE constraint_type = 'R'
410
560
  AND status = 'ENABLED'
411
561
  AND owner = SYS_CONTEXT('userenv', 'session_user')
412
562
  SQL
413
- old_constraints = select_all(sql_constraints)
414
563
  begin
415
564
  old_constraints.each do |constraint|
416
565
  execute "ALTER TABLE #{quote_table_name(constraint["table_name"])} DISABLE CONSTRAINT #{quote_table_name(constraint["constraint_name"])}"
@@ -424,19 +573,71 @@ module ActiveRecord
424
573
  end
425
574
 
426
575
  def create_alter_table(name)
427
- ActiveRecord::ConnectionAdapters::OracleEnhanced::AlterTable.new create_table_definition(name, false, {})
576
+ OracleEnhanced::AlterTable.new create_table_definition(name, false, {})
428
577
  end
429
578
 
430
579
  def update_table_definition(table_name, base)
431
- ActiveRecord::ConnectionAdapters::OracleEnhanced::Table.new(table_name, base)
580
+ OracleEnhanced::Table.new(table_name, base)
581
+ end
582
+
583
+ def create_schema_dumper(options)
584
+ OracleEnhanced::SchemaDumper.create(self, options)
432
585
  end
433
586
 
434
587
  private
435
588
 
589
+ def schema_creation
590
+ OracleEnhanced::SchemaCreation.new self
591
+ end
592
+
593
+ def create_table_definition(*args)
594
+ OracleEnhanced::TableDefinition.new(*args)
595
+ end
596
+
597
+ def new_column_from_field(table_name, field)
598
+ limit, scale = field["limit"], field["scale"]
599
+ if limit || scale
600
+ field["sql_type"] += "(#{(limit || 38).to_i}" + ((scale = scale.to_i) > 0 ? ",#{scale})" : ")")
601
+ end
602
+
603
+ if field["sql_type_owner"]
604
+ field["sql_type"] = field["sql_type_owner"] + "." + field["sql_type"]
605
+ end
606
+
607
+ is_virtual = field["virtual_column"] == "YES"
608
+
609
+ # clean up odd default spacing from Oracle
610
+ if field["data_default"] && !is_virtual
611
+ field["data_default"].sub!(/^(.*?)\s*$/, '\1')
612
+
613
+ # If a default contains a newline these cleanup regexes need to
614
+ # match newlines.
615
+ field["data_default"].sub!(/^'(.*)'$/m, '\1')
616
+ field["data_default"] = nil if field["data_default"] =~ /^(null|empty_[bc]lob\(\))$/i
617
+ # TODO: Needs better fix to fallback "N" to false
618
+ field["data_default"] = false if (field["data_default"] == "N" && OracleEnhancedAdapter.emulate_booleans_from_strings)
619
+ end
620
+
621
+ type_metadata = fetch_type_metadata(field["sql_type"], is_virtual)
622
+ default_value = extract_value_from_default(field["data_default"])
623
+ default_value = nil if is_virtual
624
+ OracleEnhanced::Column.new(oracle_downcase(field["name"]),
625
+ default_value,
626
+ type_metadata,
627
+ field["nullable"] == "Y",
628
+ table_name,
629
+ field["column_comment"]
630
+ )
631
+ end
632
+
633
+ def fetch_type_metadata(sql_type, virtual = nil)
634
+ OracleEnhanced::TypeMetadata.new(super(sql_type), virtual: virtual)
635
+ end
636
+
436
637
  def tablespace_for(obj_type, tablespace_option, table_name = nil, column_name = nil)
437
- tablespace_sql = ""
638
+ tablespace_sql = "".dup
438
639
  if tablespace = (tablespace_option || default_tablespace_for(obj_type))
439
- if [:blob, :clob].include?(obj_type.to_sym)
640
+ if [:blob, :clob, :nclob].include?(obj_type.to_sym)
440
641
  tablespace_sql << " LOB (#{quote_column_name(column_name)}) STORE AS #{column_name.to_s[0..10]}_#{table_name.to_s[0..14]}_ls (TABLESPACE #{tablespace})"
441
642
  else
442
643
  tablespace_sql << " TABLESPACE #{tablespace}"
@@ -468,7 +669,7 @@ module ActiveRecord
468
669
  seq_name = options[:sequence_name] || default_sequence_name(table_name)
469
670
  trigger_name = options[:trigger_name] || default_trigger_name(table_name)
470
671
  primary_key = options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)
471
- execute compress_lines(<<-SQL)
672
+ execute <<-SQL
472
673
  CREATE OR REPLACE TRIGGER #{quote_table_name(trigger_name)}
473
674
  BEFORE INSERT ON #{quote_table_name(table_name)} FOR EACH ROW
474
675
  BEGIN
@@ -491,11 +692,12 @@ module ActiveRecord
491
692
 
492
693
  return unless tablespace
493
694
 
494
- index_name = Base.connection.select_value(
495
- "SELECT index_name FROM all_constraints
496
- WHERE table_name = #{quote(table_name.upcase)}
695
+ index_name = select_value(<<-SQL.strip.gsub(/\s+/, " "), "Index name for primary key", [bind_string("table_name", table_name.upcase)])
696
+ SELECT index_name FROM all_constraints
697
+ WHERE table_name = :table_name
497
698
  AND constraint_type = 'P'
498
- AND owner = SYS_CONTEXT('userenv', 'current_schema')")
699
+ AND owner = SYS_CONTEXT('userenv', 'current_schema')
700
+ SQL
499
701
 
500
702
  return unless index_name
501
703