pmacs-activerecord-oracle_enhanced-adapter 1.4.2.rc1

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 (46) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +52 -0
  3. data/History.md +284 -0
  4. data/License.txt +20 -0
  5. data/README.md +403 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +59 -0
  8. data/VERSION +1 -0
  9. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1408 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +118 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +141 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +135 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +359 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +44 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +565 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +491 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +231 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +257 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +397 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +265 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +294 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  30. data/lib/pmacs-activerecord-oracle_enhanced-adapter.rb +25 -0
  31. data/pmacs-activerecord-oracle_enhanced-adapter.gemspec +131 -0
  32. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +778 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +332 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +427 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +19 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +113 -0
  37. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +1376 -0
  38. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +69 -0
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +141 -0
  40. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  41. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +378 -0
  42. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +438 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1280 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +339 -0
  45. data/spec/spec_helper.rb +187 -0
  46. metadata +302 -0
@@ -0,0 +1,260 @@
1
+ # define accessors before requiring ruby-plsql as these accessors are used in clob writing callback and should be
2
+ # available also if ruby-plsql could not be loaded
3
+ ActiveRecord::Base.class_eval do
4
+ if respond_to? :class_attribute
5
+ class_attribute :custom_create_method, :custom_update_method, :custom_delete_method
6
+ elsif respond_to? :class_inheritable_accessor
7
+ class_inheritable_accessor :custom_create_method, :custom_update_method, :custom_delete_method
8
+ end
9
+ end
10
+
11
+ require 'active_support'
12
+
13
+ module ActiveRecord #:nodoc:
14
+ module ConnectionAdapters #:nodoc:
15
+ module OracleEnhancedProcedures #:nodoc:
16
+
17
+ module ClassMethods
18
+ # Specify custom create method which should be used instead of Rails generated INSERT statement.
19
+ # Provided block should return ID of new record.
20
+ # Example:
21
+ # set_create_method do
22
+ # plsql.employees_pkg.create_employee(
23
+ # :p_first_name => first_name,
24
+ # :p_last_name => last_name,
25
+ # :p_employee_id => nil
26
+ # )[:p_employee_id]
27
+ # end
28
+ def set_create_method(&block)
29
+ include_with_custom_methods
30
+ self.custom_create_method = block
31
+ end
32
+
33
+ # Specify custom update method which should be used instead of Rails generated UPDATE statement.
34
+ # Example:
35
+ # set_update_method do
36
+ # plsql.employees_pkg.update_employee(
37
+ # :p_employee_id => id,
38
+ # :p_first_name => first_name,
39
+ # :p_last_name => last_name
40
+ # )
41
+ # end
42
+ def set_update_method(&block)
43
+ include_with_custom_methods
44
+ self.custom_update_method = block
45
+ end
46
+
47
+ # Specify custom delete method which should be used instead of Rails generated DELETE statement.
48
+ # Example:
49
+ # set_delete_method do
50
+ # plsql.employees_pkg.delete_employee(
51
+ # :p_employee_id => id
52
+ # )
53
+ # end
54
+ def set_delete_method(&block)
55
+ include_with_custom_methods
56
+ self.custom_delete_method = block
57
+ end
58
+
59
+ if ActiveRecord::VERSION::MAJOR < 3
60
+ def create_method_name_before_custom_methods #:nodoc:
61
+ if private_method_defined?(:create_without_timestamps) && defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::STRING.to_f >= 2.3
62
+ :create_without_timestamps
63
+ elsif private_method_defined?(:create_without_callbacks)
64
+ :create_without_callbacks
65
+ else
66
+ :create
67
+ end
68
+ end
69
+
70
+ def update_method_name_before_custom_methods #:nodoc:
71
+ if private_method_defined?(:update_without_dirty)
72
+ :update_without_dirty
73
+ elsif private_method_defined?(:update_without_timestamps) && defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::STRING.to_f >= 2.3
74
+ :update_without_timestamps
75
+ elsif private_method_defined?(:update_without_callbacks)
76
+ :update_without_callbacks
77
+ else
78
+ :update
79
+ end
80
+ end
81
+
82
+ def destroy_method_name_before_custom_methods #:nodoc:
83
+ if public_method_defined?(:destroy_without_callbacks)
84
+ :destroy_without_callbacks
85
+ else
86
+ :destroy
87
+ end
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def include_with_custom_methods
94
+ unless included_modules.include? InstanceMethods
95
+ include InstanceMethods
96
+ end
97
+ end
98
+ end
99
+
100
+ module InstanceMethods #:nodoc:
101
+ def self.included(base)
102
+ # alias methods just for ActiveRecord 2.x
103
+ # for ActiveRecord 3.0 will just redefine create, update, delete methods which call super
104
+ if ActiveRecord::VERSION::MAJOR < 3
105
+ base.instance_eval do
106
+ alias_method :create_without_custom_method, create_method_name_before_custom_methods
107
+ alias_method create_method_name_before_custom_methods, :create_with_custom_method
108
+ alias_method :update_without_custom_method, update_method_name_before_custom_methods
109
+ alias_method update_method_name_before_custom_methods, :update_with_custom_method
110
+ alias_method :destroy_without_custom_method, destroy_method_name_before_custom_methods
111
+ alias_method destroy_method_name_before_custom_methods, :destroy_with_custom_method
112
+ private :create, :update
113
+ public :destroy
114
+ end
115
+ end
116
+ end
117
+
118
+ if ActiveRecord::VERSION::MAJOR >= 3
119
+ def destroy #:nodoc:
120
+ # check if class has custom delete method
121
+ if self.class.custom_delete_method
122
+ # wrap destroy in transaction
123
+ with_transaction_returning_status do
124
+ # run before/after callbacks defined in model
125
+ _run_destroy_callbacks { destroy_using_custom_method }
126
+ end
127
+ else
128
+ super
129
+ end
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ # Creates a record with custom create method
136
+ # and returns its id.
137
+ if ActiveRecord::VERSION::MAJOR < 3
138
+ def create_with_custom_method
139
+ # check if class has custom create method
140
+ self.class.custom_create_method ? create_using_custom_method : create_without_custom_method
141
+ end
142
+ else # ActiveRecord 3.x
143
+ def create
144
+ # check if class has custom create method
145
+ if self.class.custom_create_method
146
+ set_timestamps_before_custom_create_method
147
+ # run before/after callbacks defined in model
148
+ _run_create_callbacks { create_using_custom_method }
149
+ else
150
+ super
151
+ end
152
+ end
153
+ end
154
+
155
+ def create_using_custom_method
156
+ self.class.connection.log_custom_method("custom create method", "#{self.class.name} Create") do
157
+ self.id = instance_eval(&self.class.custom_create_method)
158
+ end
159
+ @new_record = false
160
+ # Starting from ActiveRecord 3.0.3 @persisted is used instead of @new_record
161
+ @persisted = true
162
+ id
163
+ end
164
+
165
+ # Updates the associated record with custom update method
166
+ # Returns the number of affected rows.
167
+ if ActiveRecord::VERSION::MAJOR < 3
168
+ def update_with_custom_method(attribute_names = @attributes.keys)
169
+ # check if class has custom create method
170
+ self.class.custom_update_method ? update_using_custom_method(attribute_names) : update_without_custom_method(attribute_names)
171
+ end
172
+ else # ActiveRecord 3.x
173
+ def update(attribute_names = @attributes.keys)
174
+ # check if class has custom update method
175
+ if self.class.custom_update_method
176
+ set_timestamps_before_custom_update_method
177
+ # run before/after callbacks defined in model
178
+ _run_update_callbacks do
179
+ # update just dirty attributes
180
+ if partial_updates?
181
+ # Serialized attributes should always be written in case they've been
182
+ # changed in place.
183
+ update_using_custom_method(changed | (attributes.keys & self.class.serialized_attributes.keys))
184
+ else
185
+ update_using_custom_method(attribute_names)
186
+ end
187
+ end
188
+ else
189
+ super
190
+ end
191
+ end
192
+ end
193
+
194
+ def update_using_custom_method(attribute_names)
195
+ return 0 if attribute_names.empty?
196
+ self.class.connection.log_custom_method("custom update method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Update") do
197
+ instance_eval(&self.class.custom_update_method)
198
+ end
199
+ 1
200
+ end
201
+
202
+ # Deletes the record in the database with custom delete method
203
+ # and freezes this instance to reflect that no changes should
204
+ # be made (since they can't be persisted).
205
+ if ActiveRecord::VERSION::MAJOR < 3
206
+ def destroy_with_custom_method
207
+ # check if class has custom delete method
208
+ self.class.custom_delete_method ? destroy_using_custom_method : destroy_without_custom_method
209
+ end
210
+ end
211
+
212
+ def destroy_using_custom_method
213
+ unless new_record? || @destroyed
214
+ self.class.connection.log_custom_method("custom delete method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Destroy") do
215
+ instance_eval(&self.class.custom_delete_method)
216
+ end
217
+ end
218
+
219
+ @destroyed = true
220
+ freeze
221
+ end
222
+
223
+ if ActiveRecord::VERSION::MAJOR >= 3
224
+ def set_timestamps_before_custom_create_method
225
+ if record_timestamps
226
+ current_time = current_time_from_proper_timezone
227
+
228
+ write_attribute('created_at', current_time) if respond_to?(:created_at) && created_at.nil?
229
+ write_attribute('created_on', current_time) if respond_to?(:created_on) && created_on.nil?
230
+
231
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at) && updated_at.nil?
232
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on) && updated_on.nil?
233
+ end
234
+ end
235
+
236
+ def set_timestamps_before_custom_update_method
237
+ if record_timestamps && (!partial_updates? || changed?)
238
+ current_time = current_time_from_proper_timezone
239
+
240
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at)
241
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on)
242
+ end
243
+ end
244
+ end
245
+
246
+ end
247
+
248
+ end
249
+ end
250
+ end
251
+
252
+ ActiveRecord::Base.class_eval do
253
+ extend ActiveRecord::ConnectionAdapters::OracleEnhancedProcedures::ClassMethods
254
+ end
255
+
256
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
257
+ # public alias to log method which could be used from other objects
258
+ alias_method :log_custom_method, :log
259
+ public :log_custom_method
260
+ end
@@ -0,0 +1,231 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class OracleEnhancedForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
4
+ end
5
+
6
+ class OracleEnhancedSynonymDefinition < Struct.new(:name, :table_owner, :table_name, :db_link) #:nodoc:
7
+ end
8
+
9
+ class OracleEnhancedIndexDefinition < Struct.new(:table, :name, :unique, :type, :parameters, :statement_parameters,
10
+ :tablespace, :columns) #:nodoc:
11
+ end
12
+
13
+ module OracleEnhancedColumnDefinition
14
+ def self.included(base) #:nodoc:
15
+ base.class_eval do
16
+ alias_method_chain :to_sql, :virtual_columns
17
+ alias to_s :to_sql
18
+ end
19
+ end
20
+
21
+ def to_sql_with_virtual_columns
22
+ if type == :virtual
23
+ sql_type = base.type_to_sql(default[:type], limit, precision, scale) if default[:type]
24
+ "#{base.quote_column_name(name)} #{sql_type} AS (#{default[:as]})"
25
+ else
26
+ column_sql = to_sql_without_virtual_columns
27
+ if type==:primary_key
28
+ column_sql << base.table_definition_tablespace
29
+ end
30
+ end
31
+ column_sql
32
+ end
33
+
34
+ def lob?
35
+ ['CLOB', 'BLOB'].include?(sql_type)
36
+ end
37
+ end
38
+
39
+ module OracleEnhancedSchemaDefinitions #:nodoc:
40
+ def self.included(base)
41
+ base::TableDefinition.class_eval do
42
+ include OracleEnhancedTableDefinition
43
+ end
44
+
45
+ base::ColumnDefinition.class_eval do
46
+ include OracleEnhancedColumnDefinition
47
+ end
48
+
49
+ # Available starting from ActiveRecord 2.1
50
+ base::Table.class_eval do
51
+ include OracleEnhancedTable
52
+ end if defined?(base::Table)
53
+ end
54
+ end
55
+
56
+ module OracleEnhancedTableDefinition
57
+ class ForeignKey < Struct.new(:base, :to_table, :options) #:nodoc:
58
+ def to_sql
59
+ base.foreign_key_definition(to_table, options) << base.table_definition_tablespace
60
+ end
61
+ alias to_s :to_sql
62
+ end
63
+
64
+ def self.included(base) #:nodoc:
65
+ base.class_eval do
66
+ alias_method_chain :references, :foreign_keys
67
+ alias_method_chain :to_sql, :foreign_keys
68
+
69
+ alias_method_chain :column, :virtual_columns
70
+ end
71
+ end
72
+
73
+ def raw(name, options={})
74
+ column(name, :raw, options)
75
+ end
76
+
77
+ def virtual(* args)
78
+ options = args.extract_options!
79
+ column_names = args
80
+ column_names.each { |name| column(name, :virtual, options) }
81
+ end
82
+
83
+ def column_with_virtual_columns(name, type, options = {})
84
+ if type == :virtual
85
+ default = {:type => options[:type]}
86
+ if options[:as]
87
+ default[:as] = options[:as]
88
+ elsif options[:default]
89
+ warn "[DEPRECATION] virtual column `:default` option is deprecated. Please use `:as` instead."
90
+ default[:as] = options[:default]
91
+ else
92
+ raise "No virtual column definition found."
93
+ end
94
+ options[:default] = default
95
+ end
96
+ column_without_virtual_columns(name, type, options)
97
+ end
98
+
99
+ # Adds a :foreign_key option to TableDefinition.references.
100
+ # If :foreign_key is true, a foreign key constraint is added to the table.
101
+ # You can also specify a hash, which is passed as foreign key options.
102
+ #
103
+ # ===== Examples
104
+ # ====== Add goat_id column and a foreign key to the goats table.
105
+ # t.references(:goat, :foreign_key => true)
106
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
107
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
108
+ #
109
+ # Note: No foreign key is created if :polymorphic => true is used.
110
+ # Note: If no name is specified, the database driver creates one for you!
111
+ def references_with_foreign_keys(*args)
112
+ options = args.extract_options!
113
+ fk_options = options.delete(:foreign_key)
114
+
115
+ if fk_options && !options[:polymorphic]
116
+ fk_options = {} if fk_options == true
117
+ args.each { |to_table| foreign_key(to_table, fk_options) }
118
+ end
119
+
120
+ references_without_foreign_keys(*(args << options))
121
+ end
122
+
123
+ # Defines a foreign key for the table. +to_table+ can be a single Symbol, or
124
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
125
+ #
126
+ # ===== Examples
127
+ # ====== Creating a simple foreign key
128
+ # t.foreign_key(:people)
129
+ # ====== Defining the column
130
+ # t.foreign_key(:people, :column => :sender_id)
131
+ # ====== Creating a named foreign key
132
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
133
+ # ====== Defining the column of the +to_table+.
134
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
135
+ def foreign_key(to_table, options = {})
136
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
137
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
138
+ foreign_keys << ForeignKey.new(@base, to_table, options)
139
+ else
140
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
141
+ end
142
+ end
143
+
144
+ def to_sql_with_foreign_keys #:nodoc:
145
+ sql = to_sql_without_foreign_keys
146
+ sql << ', ' << (foreign_keys * ', ') unless foreign_keys.blank?
147
+ sql
148
+ end
149
+
150
+ def lob_columns
151
+ columns.select(&:lob?)
152
+ end
153
+
154
+ private
155
+ def foreign_keys
156
+ @foreign_keys ||= []
157
+ end
158
+ end
159
+
160
+ module OracleEnhancedTable
161
+ def self.included(base) #:nodoc:
162
+ base.class_eval do
163
+ alias_method_chain :references, :foreign_keys
164
+ end
165
+ end
166
+
167
+ # Adds a new foreign key to the table. +to_table+ can be a single Symbol, or
168
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
169
+ #
170
+ # ===== Examples
171
+ # ====== Creating a simple foreign key
172
+ # t.foreign_key(:people)
173
+ # ====== Defining the column
174
+ # t.foreign_key(:people, :column => :sender_id)
175
+ # ====== Creating a named foreign key
176
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
177
+ # ====== Defining the column of the +to_table+.
178
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
179
+ def foreign_key(to_table, options = {})
180
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
181
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
182
+ @base.add_foreign_key(@table_name, to_table, options)
183
+ else
184
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
185
+ end
186
+ end
187
+
188
+ # Remove the given foreign key from the table.
189
+ #
190
+ # ===== Examples
191
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
192
+ # t.remove_foreign_key :companies
193
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
194
+ # remove_foreign_key :column => :branch_id
195
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
196
+ # remove_index :name => :party_foreign_key
197
+ def remove_foreign_key(options = {})
198
+ @base.remove_foreign_key(@table_name, options)
199
+ end
200
+
201
+ # Adds a :foreign_key option to TableDefinition.references.
202
+ # If :foreign_key is true, a foreign key constraint is added to the table.
203
+ # You can also specify a hash, which is passed as foreign key options.
204
+ #
205
+ # ===== Examples
206
+ # ====== Add goat_id column and a foreign key to the goats table.
207
+ # t.references(:goat, :foreign_key => true)
208
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
209
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
210
+ #
211
+ # Note: No foreign key is created if :polymorphic => true is used.
212
+ def references_with_foreign_keys(*args)
213
+ options = args.extract_options!
214
+ polymorphic = options[:polymorphic]
215
+ fk_options = options.delete(:foreign_key)
216
+
217
+ references_without_foreign_keys(*(args << options))
218
+ # references_without_foreign_keys adds {:type => :integer}
219
+ args.extract_options!
220
+ if fk_options && !polymorphic
221
+ fk_options = {} if fk_options == true
222
+ args.each { |to_table| foreign_key(to_table, fk_options) }
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
228
+
229
+ ActiveRecord::ConnectionAdapters.class_eval do
230
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaDefinitions
231
+ end