pmacs-activerecord-oracle_enhanced-adapter 1.4.2.rc1

Sign up to get free protection for your applications and to get access to all the features.
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