activerecord-oracle_enhanced-adapter 1.5.6 → 1.6.9

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.travis/oracle/download.sh +14 -0
  3. data/.travis/oracle/install.sh +31 -0
  4. data/.travis/setup_accounts.sh +9 -0
  5. data/.travis.yml +39 -0
  6. data/Gemfile +8 -8
  7. data/History.md +189 -0
  8. data/README.md +388 -178
  9. data/RUNNING_TESTS.md +11 -6
  10. data/VERSION +1 -1
  11. data/activerecord-oracle_enhanced-adapter.gemspec +29 -26
  12. data/lib/active_record/connection_adapters/{oracle_enhanced_column.rb → oracle_enhanced/column.rb} +14 -63
  13. data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +66 -0
  14. data/lib/active_record/connection_adapters/{oracle_enhanced_connection.rb → oracle_enhanced/connection.rb} +2 -2
  15. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +347 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +260 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/dirty.rb +40 -0
  18. data/lib/active_record/connection_adapters/{oracle_enhanced_jdbc_connection.rb → oracle_enhanced/jdbc_connection.rb} +13 -4
  19. data/lib/active_record/connection_adapters/{oracle_enhanced_oci_connection.rb → oracle_enhanced/oci_connection.rb} +11 -5
  20. data/lib/active_record/connection_adapters/{oracle_enhanced_procedures.rb → oracle_enhanced/procedures.rb} +1 -1
  21. data/lib/active_record/connection_adapters/{oracle_enhanced_schema_creation.rb → oracle_enhanced/schema_creation.rb} +34 -35
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +95 -0
  23. data/lib/active_record/connection_adapters/{oracle_enhanced_schema_dumper.rb → oracle_enhanced/schema_dumper.rb} +14 -37
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +562 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +65 -0
  26. data/lib/active_record/connection_adapters/{oracle_enhanced_structure_dump.rb → oracle_enhanced/structure_dump.rb} +63 -14
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +171 -73
  29. data/lib/active_record/oracle_enhanced/type/integer.rb +13 -0
  30. data/lib/active_record/oracle_enhanced/type/raw.rb +13 -0
  31. data/lib/active_record/oracle_enhanced/type/timestamp.rb +11 -0
  32. data/lib/activerecord-oracle_enhanced-adapter.rb +1 -1
  33. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +127 -49
  34. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +46 -5
  35. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +11 -3
  36. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +3 -3
  37. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +151 -78
  38. data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +4 -4
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +10 -16
  40. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -1
  41. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +5 -5
  42. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +65 -181
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +114 -11
  44. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +17 -1
  45. data/spec/spec_config.yaml.template +11 -0
  46. data/spec/spec_helper.rb +31 -12
  47. data/spec/support/alter_system_user_password.sql +2 -0
  48. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  49. metadata +37 -27
  50. data/lib/active_record/connection_adapters/oracle_enhanced_column_dumper.rb +0 -77
  51. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +0 -350
  52. data/lib/active_record/connection_adapters/oracle_enhanced_database_statements.rb +0 -262
  53. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +0 -45
  54. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +0 -197
  55. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +0 -450
  56. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +0 -258
  57. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +0 -1
  58. /data/lib/active_record/connection_adapters/{oracle_enhanced_cpk.rb → oracle_enhanced/cpk.rb} +0 -0
  59. /data/lib/active_record/connection_adapters/{oracle_enhanced_database_tasks.rb → oracle_enhanced/database_tasks.rb} +0 -0
@@ -25,7 +25,9 @@ module ActiveRecord
25
25
  def initialize(config)
26
26
  @raw_connection = OCI8EnhancedAutoRecover.new(config, OracleEnhancedOCIFactory)
27
27
  # default schema owner
28
- @owner = config[:username].to_s.upcase
28
+ @owner = config[:schema]
29
+ @owner ||= config[:username]
30
+ @owner = @owner.to_s.upcase
29
31
  end
30
32
 
31
33
  def raw_oci_connection
@@ -237,12 +239,12 @@ module ActiveRecord
237
239
 
238
240
  def typecast_result_value(value, get_lob_value)
239
241
  case value
240
- when Fixnum, Bignum
242
+ when Integer
241
243
  value
242
244
  when String
243
245
  value
244
246
  when Float, BigDecimal
245
- # return Fixnum or Bignum if value is integer (to avoid issues with _before_type_cast values for id attributes)
247
+ # return Integer if value is integer (to avoid issues with _before_type_cast values for id attributes)
246
248
  value == (v_to_i = value.to_i) ? v_to_i : value
247
249
  when OraNumber
248
250
  # change OraNumber value (returned in early versions of ruby-oci8 2.0.x) to BigDecimal
@@ -306,6 +308,7 @@ module ActiveRecord
306
308
  username = config[:username] && config[:username].to_s
307
309
  password = config[:password] && config[:password].to_s
308
310
  database = config[:database] && config[:database].to_s
311
+ schema = config[:schema] && config[:schema].to_s
309
312
  host, port = config[:host], config[:port]
310
313
  privilege = config[:privilege] && config[:privilege].to_sym
311
314
  async = config[:allow_concurrency]
@@ -314,8 +317,11 @@ module ActiveRecord
314
317
  # get session time_zone from configuration or from TZ environment variable
315
318
  time_zone = config[:time_zone] || ENV['TZ']
316
319
 
320
+ # using a connection string via DATABASE_URL
321
+ connection_string = if host == 'connection-string'
322
+ database
317
323
  # connection using host, port and database name
318
- connection_string = if host || port
324
+ elsif host || port
319
325
  host ||= 'localhost'
320
326
  host = "[#{host}]" if host =~ /^[^\[].*:/ # IPv6
321
327
  port ||= 1521
@@ -326,13 +332,13 @@ module ActiveRecord
326
332
  else
327
333
  database
328
334
  end
329
-
330
335
  conn = OCI8.new username, password, connection_string, privilege
331
336
  conn.autocommit = true
332
337
  conn.non_blocking = true if async
333
338
  conn.prefetch_rows = prefetch_rows
334
339
  conn.exec "alter session set cursor_sharing = #{cursor_sharing}" rescue nil
335
340
  conn.exec "alter session set time_zone = '#{time_zone}'" unless time_zone.blank?
341
+ conn.exec "alter session set current_schema = #{schema}" unless schema.blank?
336
342
 
337
343
  # Initialize NLS parameters
338
344
  OracleEnhancedAdapter::DEFAULT_NLS_PARAMETERS.each do |key, default_value|
@@ -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.serialized_attributes.keys))
155
+ update_using_custom_method(changed | (attributes.keys & self.class.columns.select {|column| column.cast_type.is_a?(Type::Serialized)}))
156
156
  else
157
157
  update_using_custom_method(attribute_names)
158
158
  end
@@ -1,53 +1,47 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
- class OracleEnhancedAdapter < AbstractAdapter
3
+ module OracleEnhanced
4
4
  class SchemaCreation < AbstractAdapter::SchemaCreation
5
5
  private
6
6
 
7
7
  def visit_ColumnDefinition(o)
8
- if o.type.to_sym == :virtual
9
- sql_type = type_to_sql(o.default[:type], o.limit, o.precision, o.scale) if o.default[:type]
10
- "#{quote_column_name(o.name)} #{sql_type} AS (#{o.default[:as]})"
11
- else
12
- super
8
+ case
9
+ when o.type.to_sym == :virtual
10
+ sql_type = type_to_sql(o.default[:type], o.limit, o.precision, o.scale) if o.default[:type]
11
+ return "#{quote_column_name(o.name)} #{sql_type} AS (#{o.default[:as]})"
12
+ when [:blob, :clob].include?(sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale).downcase.to_sym)
13
+ if (tablespace = default_tablespace_for(sql_type))
14
+ @lob_tablespaces ||= {}
15
+ @lob_tablespaces[o.name] = tablespace
16
+ end
13
17
  end
18
+ super
14
19
  end
15
20
 
16
21
  def visit_TableDefinition(o)
17
- tablespace = tablespace_for(:table, o.options[:tablespace])
18
22
  create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE "
19
23
  create_sql << "#{quote_table_name(o.name)} ("
20
24
  create_sql << o.columns.map { |c| accept c }.join(', ')
21
25
  create_sql << ")"
26
+
22
27
  unless o.temporary
28
+ @lob_tablespaces.each do |lob_column, tablespace|
29
+ create_sql << " LOB (#{quote_column_name(lob_column)}) STORE AS (TABLESPACE #{tablespace}) \n"
30
+ end if defined?(@lob_tablespaces)
23
31
  create_sql << " ORGANIZATION #{o.options[:organization]}" if o.options[:organization]
24
- create_sql << "#{tablespace}"
32
+ if (tablespace = o.options[:tablespace] || default_tablespace_for(:table))
33
+ create_sql << " TABLESPACE #{tablespace}"
34
+ end
25
35
  end
26
36
  create_sql << " #{o.options[:options]}"
27
37
  create_sql
28
38
  end
29
39
 
30
- def tablespace_for(obj_type, tablespace_option, table_name=nil, column_name=nil)
31
- tablespace_sql = ''
32
- if tablespace = (tablespace_option || default_tablespace_for(obj_type))
33
- tablespace_sql << if [:blob, :clob].include?(obj_type.to_sym)
34
- " LOB (#{quote_column_name(column_name)}) STORE AS #{column_name.to_s[0..10]}_#{table_name.to_s[0..14]}_ls (TABLESPACE #{tablespace})"
35
- else
36
- " TABLESPACE #{tablespace}"
37
- end
38
- end
39
- tablespace_sql
40
- end
41
-
42
40
  def default_tablespace_for(type)
43
41
  (ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[type] ||
44
42
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[native_database_types[type][:name]]) rescue nil
45
43
  end
46
44
 
47
- def foreign_key_definition(to_table, options = {})
48
- @conn.foreign_key_definition(to_table, options)
49
- end
50
-
51
45
  def add_column_options!(sql, options)
52
46
  type = options[:type] || ((column = options[:column]) && column.type)
53
47
  type = type && type.to_sym
@@ -56,8 +50,7 @@ module ActiveRecord
56
50
  if type == :text
57
51
  sql << " DEFAULT #{@conn.quote(options[:default])}"
58
52
  else
59
- # from abstract adapter
60
- sql << " DEFAULT #{@conn.quote(options[:default], options[:column])}"
53
+ sql << " DEFAULT #{quote_value(options[:default], options[:column])}"
61
54
  end
62
55
  end
63
56
  # must explicitly add NULL or NOT NULL to allow change_column to work on migrations
@@ -72,18 +65,24 @@ module ActiveRecord
72
65
  end
73
66
  end
74
67
 
75
- # This method does not exist in SchemaCreation at Rails 4.0
76
- # It can be removed only when Oracle enhanced adapter supports Rails 4.1 and higher
77
- def options_include_default?(options)
78
- options.include?(:default) && !(options[:null] == false && options[:default].nil?)
68
+ def action_sql(action, dependency)
69
+ if action == 'UPDATE'
70
+ raise ArgumentError, <<-MSG.strip_heredoc
71
+ '#{action}' is not supported by Oracle
72
+ MSG
73
+ end
74
+ case dependency
75
+ when :nullify then "ON #{action} SET NULL"
76
+ when :cascade then "ON #{action} CASCADE"
77
+ else
78
+ raise ArgumentError, <<-MSG.strip_heredoc
79
+ '#{dependency}' is not supported for #{action}
80
+ Supported values are: :nullify, :cascade
81
+ MSG
82
+ end
79
83
  end
80
84
 
81
85
  end
82
-
83
- def schema_creation
84
- SchemaCreation.new self
85
- end
86
-
87
86
  end
88
87
  end
89
88
  end
@@ -0,0 +1,95 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ #TODO: Overriding `aliased_types` cause another database adapter behavior changes
4
+ #It should be addressed by supporting `create_table_definition`
5
+ class TableDefinition
6
+ private
7
+ def aliased_types(name, fallback)
8
+ fallback
9
+ end
10
+ end
11
+
12
+ module OracleEnhanced
13
+
14
+ class ForeignKeyDefinition < ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
15
+ def name
16
+ if options[:name].length > OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH
17
+ ActiveSupport::Deprecation.warn "Foreign key name #{options[:name]} is too long. It will not get shorten in later version of Oracle enhanced adapter"
18
+ 'c'+Digest::SHA1.hexdigest(options[:name])[0,OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH-1]
19
+ else
20
+ options[:name]
21
+ end
22
+ end
23
+ end
24
+
25
+ class SynonymDefinition < Struct.new(:name, :table_owner, :table_name, :db_link) #:nodoc:
26
+ end
27
+
28
+ class IndexDefinition < ActiveRecord::ConnectionAdapters::IndexDefinition
29
+ attr_accessor :table, :name, :unique, :type, :parameters, :statement_parameters, :tablespace, :columns
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
36
+ @parameters = parameters
37
+ @statement_parameters = statement_parameters
38
+ @tablespace = tablespace
39
+ @columns = columns
40
+ super(table, name, unique, columns, nil, nil, nil, nil)
41
+ end
42
+ end
43
+
44
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
45
+
46
+ def raw(name, options={})
47
+ column(name, :raw, options)
48
+ end
49
+
50
+ def virtual(* args)
51
+ options = args.extract_options!
52
+ column_names = args
53
+ column_names.each { |name| column(name, :virtual, options) }
54
+ end
55
+
56
+ def column(name, type, options = {})
57
+ if type == :virtual
58
+ default = {:type => options[:type]}
59
+ if options[:as]
60
+ default[:as] = options[:as]
61
+ elsif options[:default]
62
+ warn "[DEPRECATION] virtual column `:default` option is deprecated. Please use `:as` instead."
63
+ default[:as] = options[:default]
64
+ else
65
+ raise "No virtual column definition found."
66
+ end
67
+ options[:default] = default
68
+ end
69
+ super(name, type, options)
70
+ end
71
+
72
+ end
73
+
74
+ class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
75
+ def add_foreign_key(to_table, options)
76
+ @foreign_key_adds << OracleEnhanced::ForeignKeyDefinition.new(name, to_table, options)
77
+ end
78
+ end
79
+
80
+ class Table < ActiveRecord::ConnectionAdapters::Table
81
+ def foreign_key(to_table, options = {})
82
+ ActiveSupport::Deprecation.warn "`foreign_key` option will be deprecated. Please use `references` option"
83
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
84
+ @base.add_foreign_key(@name, to_table, options)
85
+ end
86
+
87
+ def remove_foreign_key(options = {})
88
+ ActiveSupport::Deprecation.warn "`remove_foreign_key` option will be deprecated. Please use `remove_references` option"
89
+ @base.remove_foreign_key(@name, options)
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -7,6 +7,7 @@ module ActiveRecord #:nodoc:
7
7
  private
8
8
  alias_method_chain :tables, :oracle_enhanced
9
9
  alias_method_chain :indexes, :oracle_enhanced
10
+ alias_method_chain :foreign_keys, :oracle_enhanced
10
11
  end
11
12
  end
12
13
 
@@ -49,44 +50,15 @@ module ActiveRecord #:nodoc:
49
50
 
50
51
  def primary_key_trigger(table_name, stream)
51
52
  if @connection.respond_to?(:has_primary_key_trigger?) && @connection.has_primary_key_trigger?(table_name)
52
- pk, pk_seq = @connection.pk_and_sequence_for(table_name)
53
+ pk, _pk_seq = @connection.pk_and_sequence_for(table_name)
53
54
  stream.print " add_primary_key_trigger #{table_name.inspect}"
54
55
  stream.print ", primary_key: \"#{pk}\"" if pk != 'id'
55
56
  stream.print "\n\n"
56
57
  end
57
58
  end
58
59
 
59
- def foreign_keys(table_name, stream)
60
- if @connection.respond_to?(:foreign_keys) && (foreign_keys = @connection.foreign_keys(table_name)).any?
61
- add_foreign_key_statements = foreign_keys.map do |foreign_key|
62
- statement_parts = [ ('add_foreign_key ' + foreign_key.from_table.inspect) ]
63
- statement_parts << foreign_key.to_table.inspect
64
-
65
- if foreign_key.options[:columns].size == 1
66
- column = foreign_key.options[:columns].first
67
- if column != "#{foreign_key.to_table.singularize}_id"
68
- statement_parts << ('column: ' + column.inspect)
69
- end
70
-
71
- if foreign_key.options[:references].first != 'id'
72
- statement_parts << ('primary_key: ' + foreign_key.options[:references].first.inspect)
73
- end
74
- else
75
- statement_parts << ('columns: ' + foreign_key.options[:columns].inspect)
76
- end
77
-
78
- statement_parts << ('name: ' + foreign_key.options[:name].inspect)
79
-
80
- unless foreign_key.options[:dependent].blank?
81
- statement_parts << ('dependent: ' + foreign_key.options[:dependent].inspect)
82
- end
83
-
84
- ' ' + statement_parts.join(', ')
85
- end
86
-
87
- stream.puts add_foreign_key_statements.sort.join("\n")
88
- stream.puts
89
- end
60
+ def foreign_keys_with_oracle_enhanced(table_name, stream)
61
+ return foreign_keys_without_oracle_enhanced(table_name, stream)
90
62
  end
91
63
 
92
64
  def synonyms(stream)
@@ -149,16 +121,21 @@ module ActiveRecord #:nodoc:
149
121
 
150
122
  # first dump primary key column
151
123
  if @connection.respond_to?(:pk_and_sequence_for)
152
- pk, pk_seq = @connection.pk_and_sequence_for(table)
124
+ pk, _pk_seq = @connection.pk_and_sequence_for(table)
153
125
  elsif @connection.respond_to?(:primary_key)
154
126
  pk = @connection.primary_key(table)
155
127
  end
156
-
128
+
157
129
  tbl.print " create_table #{table.inspect}"
158
-
130
+
159
131
  # addition to make temporary option work
160
132
  tbl.print ", temporary: true" if @connection.temporary_table?(table)
161
-
133
+
134
+ table_comments = @connection.table_comment(table)
135
+ unless table_comments.nil?
136
+ tbl.print ", comment: #{table_comments.inspect}"
137
+ end
138
+
162
139
  if columns.detect { |c| c.name == pk }
163
140
  if pk != 'id'
164
141
  tbl.print %Q(, primary_key: "#{pk}")
@@ -166,7 +143,7 @@ module ActiveRecord #:nodoc:
166
143
  else
167
144
  tbl.print ", id: false"
168
145
  end
169
- tbl.print ", force: true"
146
+ tbl.print ", force: :cascade"
170
147
  tbl.puts " do |t|"
171
148
 
172
149
  # then dump all non-primary key columns