activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/Gemfile +20 -11
  4. data/History.md +123 -4
  5. data/RUNNING_TESTS.md +79 -55
  6. data/Rakefile +13 -19
  7. data/VERSION +1 -1
  8. data/activerecord-oracle_enhanced-adapter.gemspec +16 -17
  9. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
  10. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +7 -59
  11. data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +6 -50
  12. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +11 -11
  13. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +117 -117
  14. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +30 -23
  15. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
  16. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +48 -70
  17. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -4
  18. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +51 -69
  19. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +4 -4
  20. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +76 -76
  21. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +13 -42
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +60 -64
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +33 -47
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +146 -159
  25. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +94 -132
  26. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +3 -3
  27. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +65 -100
  28. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
  29. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +250 -487
  30. data/lib/active_record/oracle_enhanced/type/boolean.rb +7 -10
  31. data/lib/active_record/oracle_enhanced/type/integer.rb +3 -4
  32. data/lib/active_record/oracle_enhanced/type/national_character_string.rb +1 -1
  33. data/lib/active_record/oracle_enhanced/type/raw.rb +2 -3
  34. data/lib/active_record/oracle_enhanced/type/string.rb +2 -2
  35. data/lib/active_record/oracle_enhanced/type/text.rb +2 -2
  36. data/lib/activerecord-oracle_enhanced-adapter.rb +2 -2
  37. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +57 -131
  38. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +32 -34
  39. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -42
  40. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +83 -85
  41. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +205 -286
  42. data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +14 -6
  43. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +3 -5
  44. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +42 -49
  45. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -3
  46. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +68 -71
  47. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +51 -92
  48. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +221 -327
  49. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +16 -18
  50. data/spec/spec_helper.rb +59 -57
  51. metadata +10 -10
@@ -5,16 +5,16 @@ module ActiveRecord
5
5
  def _type_cast(value)
6
6
  case value
7
7
  when ActiveModel::Type::Binary::Data
8
- lob_value = value == '' ? ' ' : value
8
+ lob_value = value == "" ? " " : value
9
9
  bind_type = OCI8::BLOB
10
10
  ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
11
- ora_value.size = 0 if value == ''
11
+ ora_value.size = 0 if value == ""
12
12
  ora_value
13
13
  when ActiveRecord::OracleEnhanced::Type::Text::Data
14
- lob_value = value.to_s == '' ? ' ' : value.to_s
14
+ lob_value = value.to_s == "" ? " " : value.to_s
15
15
  bind_type = OCI8::CLOB
16
16
  ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
17
- ora_value.size = 0 if value.to_s == ''
17
+ ora_value.size = 0 if value.to_s == ""
18
18
  ora_value
19
19
  else
20
20
  super
@@ -1,4 +1,4 @@
1
- require 'active_support'
1
+ require "active_support"
2
2
 
3
3
  module ActiveRecord #:nodoc:
4
4
  # Custom create, update, delete methods functionality.
@@ -96,99 +96,99 @@ module ActiveRecord #:nodoc:
96
96
 
97
97
  private
98
98
 
99
- # Creates a record with custom create method
100
- # and returns its id.
101
- def _create_record
102
- # check if class has custom create method
103
- if self.class.custom_create_method
104
- # run before/after callbacks defined in model
105
- run_callbacks(:create) do
106
- # timestamp
107
- if self.record_timestamps
108
- current_time = current_time_from_proper_timezone
109
-
110
- all_timestamp_attributes.each do |column|
111
- if respond_to?(column) && respond_to?("#{column}=") && self.send(column).nil?
112
- write_attribute(column.to_s, current_time)
99
+ # Creates a record with custom create method
100
+ # and returns its id.
101
+ def _create_record
102
+ # check if class has custom create method
103
+ if self.class.custom_create_method
104
+ # run before/after callbacks defined in model
105
+ run_callbacks(:create) do
106
+ # timestamp
107
+ if self.record_timestamps
108
+ current_time = current_time_from_proper_timezone
109
+
110
+ all_timestamp_attributes_in_model.each do |column|
111
+ if respond_to?(column) && respond_to?("#{column}=") && self.send(column).nil?
112
+ write_attribute(column.to_s, current_time)
113
+ end
113
114
  end
114
115
  end
116
+ # run
117
+ create_using_custom_method
115
118
  end
116
- # run
117
- create_using_custom_method
119
+ else
120
+ super
118
121
  end
119
- else
120
- super
121
122
  end
122
- end
123
123
 
124
- def create_using_custom_method
125
- log_custom_method("custom create method", "#{self.class.name} Create") do
126
- self.id = instance_eval(&self.class.custom_create_method)
124
+ def create_using_custom_method
125
+ log_custom_method("custom create method", "#{self.class.name} Create") do
126
+ self.id = instance_eval(&self.class.custom_create_method)
127
+ end
128
+ @new_record = false
129
+ # Starting from ActiveRecord 3.0.3 @persisted is used instead of @new_record
130
+ @persisted = true
131
+ id
127
132
  end
128
- @new_record = false
129
- # Starting from ActiveRecord 3.0.3 @persisted is used instead of @new_record
130
- @persisted = true
131
- id
132
- end
133
133
 
134
- # Updates the associated record with custom update method
135
- # Returns the number of affected rows.
136
- def _update_record(attribute_names = @attributes.keys)
137
- # check if class has custom update method
138
- if self.class.custom_update_method
139
- # run before/after callbacks defined in model
140
- run_callbacks(:update) do
141
- # timestamp
142
- if should_record_timestamps?
143
- current_time = current_time_from_proper_timezone
144
-
145
- timestamp_attributes_for_update_in_model.each do |column|
146
- column = column.to_s
147
- next if attribute_changed?(column)
148
- write_attribute(column, current_time)
134
+ # Updates the associated record with custom update method
135
+ # Returns the number of affected rows.
136
+ def _update_record(attribute_names = @attributes.keys)
137
+ # check if class has custom update method
138
+ if self.class.custom_update_method
139
+ # run before/after callbacks defined in model
140
+ run_callbacks(:update) do
141
+ # timestamp
142
+ if should_record_timestamps?
143
+ current_time = current_time_from_proper_timezone
144
+
145
+ timestamp_attributes_for_update_in_model.each do |column|
146
+ column = column.to_s
147
+ next if attribute_changed?(column)
148
+ write_attribute(column, current_time)
149
+ end
150
+ end
151
+ # update just dirty attributes
152
+ if partial_writes?
153
+ # Serialized attributes should always be written in case they've been
154
+ # changed in place.
155
+ update_using_custom_method(changed | (attributes.keys & self.class.columns.select { |column| column.is_a?(Type::Serialized) }))
156
+ else
157
+ update_using_custom_method(attributes.keys)
149
158
  end
150
159
  end
151
- # update just dirty attributes
152
- if partial_writes?
153
- # Serialized attributes should always be written in case they've been
154
- # changed in place.
155
- update_using_custom_method(changed | (attributes.keys & self.class.columns.select {|column| column.is_a?(Type::Serialized)}))
156
- else
157
- update_using_custom_method(attributes.keys)
158
- end
160
+ else
161
+ super
159
162
  end
160
- else
161
- super
162
163
  end
163
- end
164
164
 
165
- def update_using_custom_method(attribute_names)
166
- return 0 if attribute_names.empty?
167
- log_custom_method("custom update method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Update") do
168
- instance_eval(&self.class.custom_update_method)
165
+ def update_using_custom_method(attribute_names)
166
+ return 0 if attribute_names.empty?
167
+ log_custom_method("custom update method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Update") do
168
+ instance_eval(&self.class.custom_update_method)
169
+ end
170
+ 1
169
171
  end
170
- 1
171
- end
172
172
 
173
- # Deletes the record in the database with custom delete method
174
- # and freezes this instance to reflect that no changes should
175
- # be made (since they can't be persisted).
176
- def destroy_using_custom_method
177
- unless new_record? || @destroyed
178
- log_custom_method("custom delete method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Destroy") do
179
- instance_eval(&self.class.custom_delete_method)
173
+ # Deletes the record in the database with custom delete method
174
+ # and freezes this instance to reflect that no changes should
175
+ # be made (since they can't be persisted).
176
+ def destroy_using_custom_method
177
+ unless new_record? || @destroyed
178
+ log_custom_method("custom delete method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Destroy") do
179
+ instance_eval(&self.class.custom_delete_method)
180
+ end
180
181
  end
181
- end
182
182
 
183
- @destroyed = true
184
- freeze
185
- end
183
+ @destroyed = true
184
+ freeze
185
+ end
186
186
 
187
- def log_custom_method(*args)
188
- self.class.connection.send(:log, *args) { yield }
189
- end
187
+ def log_custom_method(*args)
188
+ self.class.connection.send(:log, *args) { yield }
189
+ end
190
190
 
191
- alias_method :update_record, :_update_record if private_method_defined?(:_update_record)
192
- alias_method :create_record, :_create_record if private_method_defined?(:_create_record)
191
+ alias_method :update_record, :_update_record if private_method_defined?(:_update_record)
192
+ alias_method :create_record, :_create_record if private_method_defined?(:_create_record)
193
193
  end
194
194
  end
@@ -76,76 +76,47 @@ module ActiveRecord
76
76
  end
77
77
 
78
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('@')
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
81
  end
82
82
 
83
83
  def quote_string(s) #:nodoc:
84
84
  s.gsub(/'/, "''")
85
85
  end
86
86
 
87
- def quote(value, column = nil) #:nodoc:
88
- super
89
- end
90
-
91
87
  def _quote(value) #:nodoc:
92
88
  case value
93
89
  when ActiveRecord::OracleEnhanced::Type::NationalCharacterString::Data then
94
- "N" << "'#{quote_string(value.to_s)}'"
90
+ "N" << "'#{quote_string(value.to_s)}'"
95
91
  when ActiveModel::Type::Binary::Data then
96
- %Q{empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'blob' }()}
92
+ "empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'blob' }()"
97
93
  when ActiveRecord::OracleEnhanced::Type::Text::Data then
98
- %Q{empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'clob' }()}
94
+ "empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'clob' }()"
99
95
  else
100
96
  super
101
97
  end
102
98
  end
103
99
 
104
100
  def quoted_true #:nodoc:
105
- return "'#{self.class.boolean_to_string(true)}'" if emulate_booleans_from_strings
101
+ return "'Y'" if emulate_booleans_from_strings
106
102
  "1".freeze
107
103
  end
108
104
 
109
105
  def unquoted_true #:nodoc:
110
- return "#{self.class.boolean_to_string(true)}" if emulate_booleans_from_strings
106
+ return "Y" if emulate_booleans_from_strings
111
107
  "1".freeze
112
108
  end
113
109
 
114
110
  def quoted_false #:nodoc:
115
- return "'#{self.class.boolean_to_string(false)}'" if emulate_booleans_from_strings
111
+ return "'N'" if emulate_booleans_from_strings
116
112
  "0".freeze
117
113
  end
118
114
 
119
115
  def unquoted_false #:nodoc:
120
- return "#{self.class.boolean_to_string(false)}" if emulate_booleans_from_strings
116
+ return "N" if emulate_booleans_from_strings
121
117
  "0".freeze
122
118
  end
123
119
 
124
- def quote_date_with_to_date(value) #:nodoc:
125
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
126
- `quote_date_with_to_date` 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
- # should support that composite_primary_keys gem will pass date as string
130
- value = quoted_date(value) if value.acts_like?(:date) || value.acts_like?(:time)
131
- "TO_DATE('#{value}','YYYY-MM-DD HH24:MI:SS')"
132
- end
133
-
134
- def quote_timestamp_with_to_timestamp(value) #:nodoc:
135
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
136
- `quote_timestamp_with_to_timestamp` will be deprecated in future version of Oracle enhanced adapter.
137
- Also this method should not be called directly. Let Abstract adapter `_quote` method handle it.
138
- MSG
139
- # add up to 9 digits of fractional seconds to inserted time
140
- value = "#{quoted_date(value)}:#{("%.6f"%value.to_f).split('.')[1]}" if value.acts_like?(:time)
141
- "TO_TIMESTAMP('#{value}','YYYY-MM-DD HH24:MI:SS:FF6')"
142
- end
143
-
144
- # Cast a +value+ to a type that the database understands.
145
- def type_cast(value, column = nil)
146
- super
147
- end
148
-
149
120
  def _type_cast(value)
150
121
  case value
151
122
  when Date, Time
@@ -167,11 +138,11 @@ module ActiveRecord
167
138
  end
168
139
 
169
140
  # if MRI or YARV
170
- if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
171
- require 'active_record/connection_adapters/oracle_enhanced/oci_quoting'
141
+ if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
142
+ require "active_record/connection_adapters/oracle_enhanced/oci_quoting"
172
143
  # if JRuby
173
- elsif RUBY_ENGINE == 'jruby'
174
- require 'active_record/connection_adapters/oracle_enhanced/jdbc_quoting'
144
+ elsif RUBY_ENGINE == "jruby"
145
+ require "active_record/connection_adapters/oracle_enhanced/jdbc_quoting"
175
146
  else
176
147
  raise "Unsupported Ruby engine #{RUBY_ENGINE}"
177
148
  end
@@ -4,92 +4,88 @@ module ActiveRecord
4
4
  class SchemaCreation < AbstractAdapter::SchemaCreation
5
5
  private
6
6
 
7
- def visit_ColumnDefinition(o)
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)
7
+ def visit_ColumnDefinition(o)
8
+ if [:blob, :clob].include?(sql_type = type_to_sql(o.type, o.options).downcase.to_sym)
13
9
  if (tablespace = default_tablespace_for(sql_type))
14
10
  @lob_tablespaces ||= {}
15
11
  @lob_tablespaces[o.name] = tablespace
16
12
  end
13
+ end
14
+ super
17
15
  end
18
- super
19
- end
20
16
 
21
- def visit_TableDefinition(o)
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
17
+ def visit_TableDefinition(o)
18
+ create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
19
+ statements = o.columns.map { |c| accept c }
20
+ statements << accept(o.primary_keys) if o.primary_keys
25
21
 
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
22
+ if supports_foreign_keys_in_create?
23
+ statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
24
+ end
29
25
 
30
- create_sql << "(#{statements.join(', ')})" if statements.present?
26
+ create_sql << "(#{statements.join(', ')})" if statements.present?
31
27
 
32
- unless o.temporary
33
- @lob_tablespaces.each do |lob_column, tablespace|
34
- create_sql << " LOB (#{quote_column_name(lob_column)}) STORE AS (TABLESPACE #{tablespace}) \n"
35
- end if defined?(@lob_tablespaces)
36
- create_sql << " ORGANIZATION #{o.organization}" if o.organization
37
- if (tablespace = o.tablespace || default_tablespace_for(:table))
38
- create_sql << " TABLESPACE #{tablespace}"
28
+ unless o.temporary
29
+ @lob_tablespaces.each do |lob_column, tablespace|
30
+ create_sql << " LOB (#{quote_column_name(lob_column)}) STORE AS (TABLESPACE #{tablespace}) \n"
31
+ end if defined?(@lob_tablespaces)
32
+ create_sql << " ORGANIZATION #{o.organization}" if o.organization
33
+ if (tablespace = o.tablespace || default_tablespace_for(:table))
34
+ create_sql << " TABLESPACE #{tablespace}"
35
+ end
39
36
  end
37
+ add_table_options!(create_sql, table_options(o))
38
+ create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
39
+ create_sql
40
40
  end
41
- add_table_options!(create_sql, table_options(o))
42
- create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
43
- create_sql
44
- end
45
41
 
46
- def default_tablespace_for(type)
47
- (ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[type] ||
48
- ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[native_database_types[type][:name]]) rescue nil
49
- end
42
+ 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
+ end
50
46
 
51
- def add_column_options!(sql, options)
52
- type = options[:type] || ((column = options[:column]) && column.type)
53
- type = type && type.to_sym
54
- # handle case of defaults for CLOB columns, which would otherwise get "quoted" incorrectly
55
- if options_include_default?(options)
56
- if type == :text
57
- sql << " DEFAULT #{@conn.quote(options[:default])}"
58
- else
59
- sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}"
47
+ def add_column_options!(sql, options)
48
+ type = options[:type] || ((column = options[:column]) && column.type)
49
+ type = type && type.to_sym
50
+ # handle case of defaults for CLOB columns, which would otherwise get "quoted" incorrectly
51
+ if options_include_default?(options)
52
+ if type == :text
53
+ sql << " DEFAULT #{@conn.quote(options[:default])}"
54
+ else
55
+ sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}"
56
+ end
57
+ end
58
+ # must explicitly add NULL or NOT NULL to allow change_column to work on migrations
59
+ if options[:null] == false
60
+ sql << " NOT NULL"
61
+ elsif options[:null] == true
62
+ sql << " NULL" unless type == :primary_key
63
+ end
64
+ # add AS expression for virtual columns
65
+ if options[:as].present?
66
+ sql << " AS (#{options[:as]})"
67
+ end
68
+ if options[:primary_key] == true
69
+ sql << " PRIMARY KEY"
60
70
  end
61
71
  end
62
- # must explicitly add NULL or NOT NULL to allow change_column to work on migrations
63
- if options[:null] == false
64
- sql << " NOT NULL"
65
- elsif options[:null] == true
66
- sql << " NULL" unless type == :primary_key
67
- end
68
- # add AS expression for virtual columns
69
- if options[:as].present?
70
- sql << " AS (#{options[:as]})"
71
- end
72
- if options[:primary_key] == true
73
- sql << " PRIMARY KEY"
74
- end
75
- end
76
72
 
77
- def action_sql(action, dependency)
78
- if action == 'UPDATE'
79
- raise ArgumentError, <<-MSG.strip_heredoc
73
+ def action_sql(action, dependency)
74
+ if action == "UPDATE"
75
+ raise ArgumentError, <<-MSG.strip_heredoc
80
76
  '#{action}' is not supported by Oracle
81
77
  MSG
82
- end
83
- case dependency
84
- when :nullify then "ON #{action} SET NULL"
85
- when :cascade then "ON #{action} CASCADE"
86
- else
87
- raise ArgumentError, <<-MSG.strip_heredoc
78
+ end
79
+ case dependency
80
+ when :nullify then "ON #{action} SET NULL"
81
+ when :cascade then "ON #{action} CASCADE"
82
+ else
83
+ raise ArgumentError, <<-MSG.strip_heredoc
88
84
  '#{dependency}' is not supported for #{action}
89
85
  Supported values are: :nullify, :cascade
90
86
  MSG
87
+ end
91
88
  end
92
- end
93
89
  end
94
90
  end
95
91
  end