ctreatma-activerecord-oracle_enhanced-adapter 1.4.1.1

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 (47) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +51 -0
  3. data/History.md +269 -0
  4. data/License.txt +20 -0
  5. data/README.md +378 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +46 -0
  8. data/VERSION +1 -0
  9. data/activerecord-oracle_enhanced-adapter.gemspec +130 -0
  10. data/ctreatma-activerecord-oracle_enhanced-adapter.gemspec +129 -0
  11. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1390 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +106 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +136 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +119 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +328 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +553 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +492 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +213 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +252 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +373 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +265 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +290 -0
  30. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  31. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  32. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +749 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +310 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +426 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +19 -0
  37. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +113 -0
  38. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +1330 -0
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +69 -0
  40. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +121 -0
  41. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  42. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +374 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +380 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1112 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +323 -0
  46. data/spec/spec_helper.rb +185 -0
  47. metadata +287 -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,213 @@
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
+ column_sql = "#{base.quote_column_name(name)} AS (#{default})"
24
+ else
25
+ column_sql = to_sql_without_virtual_columns
26
+ if type==:primary_key
27
+ column_sql << base.table_definition_tablespace
28
+ end
29
+ end
30
+ column_sql
31
+ end
32
+
33
+ def lob?
34
+ ['CLOB', 'BLOB'].include?(sql_type)
35
+ end
36
+ end
37
+
38
+ module OracleEnhancedSchemaDefinitions #:nodoc:
39
+ def self.included(base)
40
+ base::TableDefinition.class_eval do
41
+ include OracleEnhancedTableDefinition
42
+ end
43
+
44
+ base::ColumnDefinition.class_eval do
45
+ include OracleEnhancedColumnDefinition
46
+ end
47
+
48
+ # Available starting from ActiveRecord 2.1
49
+ base::Table.class_eval do
50
+ include OracleEnhancedTable
51
+ end if defined?(base::Table)
52
+ end
53
+ end
54
+
55
+ module OracleEnhancedTableDefinition
56
+ class ForeignKey < Struct.new(:base, :to_table, :options) #:nodoc:
57
+ def to_sql
58
+ base.foreign_key_definition(to_table, options) << base.table_definition_tablespace
59
+ end
60
+ alias to_s :to_sql
61
+ end
62
+
63
+ def raw(name, options={})
64
+ column(name, :raw, options)
65
+ end
66
+
67
+ def self.included(base) #:nodoc:
68
+ base.class_eval do
69
+ alias_method_chain :references, :foreign_keys
70
+ alias_method_chain :to_sql, :foreign_keys
71
+
72
+ def virtual(* args)
73
+ options = args.extract_options!
74
+ column_names = args
75
+ column_names.each { |name| column(name, :virtual, options) }
76
+ end
77
+
78
+ end
79
+ end
80
+
81
+ # Adds a :foreign_key option to TableDefinition.references.
82
+ # If :foreign_key is true, a foreign key constraint is added to the table.
83
+ # You can also specify a hash, which is passed as foreign key options.
84
+ #
85
+ # ===== Examples
86
+ # ====== Add goat_id column and a foreign key to the goats table.
87
+ # t.references(:goat, :foreign_key => true)
88
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
89
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
90
+ #
91
+ # Note: No foreign key is created if :polymorphic => true is used.
92
+ # Note: If no name is specified, the database driver creates one for you!
93
+ def references_with_foreign_keys(*args)
94
+ options = args.extract_options!
95
+ fk_options = options.delete(:foreign_key)
96
+
97
+ if fk_options && !options[:polymorphic]
98
+ fk_options = {} if fk_options == true
99
+ args.each { |to_table| foreign_key(to_table, fk_options) }
100
+ end
101
+
102
+ references_without_foreign_keys(*(args << options))
103
+ end
104
+
105
+ # Defines a foreign key for the table. +to_table+ can be a single Symbol, or
106
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
107
+ #
108
+ # ===== Examples
109
+ # ====== Creating a simple foreign key
110
+ # t.foreign_key(:people)
111
+ # ====== Defining the column
112
+ # t.foreign_key(:people, :column => :sender_id)
113
+ # ====== Creating a named foreign key
114
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
115
+ # ====== Defining the column of the +to_table+.
116
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
117
+ def foreign_key(to_table, options = {})
118
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
119
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
120
+ foreign_keys << ForeignKey.new(@base, to_table, options)
121
+ else
122
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
123
+ end
124
+ end
125
+
126
+ def to_sql_with_foreign_keys #:nodoc:
127
+ sql = to_sql_without_foreign_keys
128
+ sql << ', ' << (foreign_keys * ', ') unless foreign_keys.blank?
129
+ sql
130
+ end
131
+
132
+ def lob_columns
133
+ columns.select(&:lob?)
134
+ end
135
+
136
+ private
137
+ def foreign_keys
138
+ @foreign_keys ||= []
139
+ end
140
+ end
141
+
142
+ module OracleEnhancedTable
143
+ def self.included(base) #:nodoc:
144
+ base.class_eval do
145
+ alias_method_chain :references, :foreign_keys
146
+ end
147
+ end
148
+
149
+ # Adds a new foreign key to the table. +to_table+ can be a single Symbol, or
150
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
151
+ #
152
+ # ===== Examples
153
+ # ====== Creating a simple foreign key
154
+ # t.foreign_key(:people)
155
+ # ====== Defining the column
156
+ # t.foreign_key(:people, :column => :sender_id)
157
+ # ====== Creating a named foreign key
158
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
159
+ # ====== Defining the column of the +to_table+.
160
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
161
+ def foreign_key(to_table, options = {})
162
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
163
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
164
+ @base.add_foreign_key(@table_name, to_table, options)
165
+ else
166
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
167
+ end
168
+ end
169
+
170
+ # Remove the given foreign key from the table.
171
+ #
172
+ # ===== Examples
173
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
174
+ # t.remove_foreign_key :companies
175
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
176
+ # remove_foreign_key :column => :branch_id
177
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
178
+ # remove_index :name => :party_foreign_key
179
+ def remove_foreign_key(options = {})
180
+ @base.remove_foreign_key(@table_name, options)
181
+ end
182
+
183
+ # Adds a :foreign_key option to TableDefinition.references.
184
+ # If :foreign_key is true, a foreign key constraint is added to the table.
185
+ # You can also specify a hash, which is passed as foreign key options.
186
+ #
187
+ # ===== Examples
188
+ # ====== Add goat_id column and a foreign key to the goats table.
189
+ # t.references(:goat, :foreign_key => true)
190
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
191
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
192
+ #
193
+ # Note: No foreign key is created if :polymorphic => true is used.
194
+ def references_with_foreign_keys(*args)
195
+ options = args.extract_options!
196
+ polymorphic = options[:polymorphic]
197
+ fk_options = options.delete(:foreign_key)
198
+
199
+ references_without_foreign_keys(*(args << options))
200
+ # references_without_foreign_keys adds {:type => :integer}
201
+ args.extract_options!
202
+ if fk_options && !polymorphic
203
+ fk_options = {} if fk_options == true
204
+ args.each { |to_table| foreign_key(to_table, fk_options) }
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ ActiveRecord::ConnectionAdapters.class_eval do
212
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaDefinitions
213
+ end