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