oracle_enhanced 1.2.5

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 (38) hide show
  1. data/.gitignore +10 -0
  2. data/History.txt +182 -0
  3. data/License.txt +20 -0
  4. data/Manifest.txt +32 -0
  5. data/README.rdoc +77 -0
  6. data/Rakefile +49 -0
  7. data/VERSION +1 -0
  8. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced.rake +51 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1661 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +121 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +64 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +393 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +389 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +163 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_reserved_words.rb +126 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +168 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +213 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +224 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +11 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  24. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +477 -0
  25. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_structure_dumper_spec.rb +267 -0
  26. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +206 -0
  27. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +40 -0
  28. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +107 -0
  29. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +984 -0
  30. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +67 -0
  31. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +93 -0
  32. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +370 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +203 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_schema_spec.rb +784 -0
  36. data/spec/spec.opts +6 -0
  37. data/spec/spec_helper.rb +114 -0
  38. metadata +140 -0
@@ -0,0 +1,126 @@
1
+ module ActiveRecord #:nodoc:
2
+ module ConnectionAdapters #:nodoc:
3
+ module OracleEnhancedReservedWords #:nodoc:
4
+
5
+ RESERVED_WORDS = {
6
+ "ACCESS" => true,
7
+ "ADD" => true,
8
+ "ALL" => true,
9
+ "ALTER" => true,
10
+ "AND" => true,
11
+ "ANY" => true,
12
+ "AS" => true,
13
+ "ASC" => true,
14
+ "AUDIT" => true,
15
+ "BETWEEN" => true,
16
+ "BY" => true,
17
+ "CHAR" => true,
18
+ "CHECK" => true,
19
+ "CLUSTER" => true,
20
+ "COLUMN" => true,
21
+ "COMMENT" => true,
22
+ "COMPRESS" => true,
23
+ "CONNECT" => true,
24
+ "CREATE" => true,
25
+ "CURRENT" => true,
26
+ "DATE" => true,
27
+ "DECIMAL" => true,
28
+ "DEFAULT" => true,
29
+ "DELETE" => true,
30
+ "DESC" => true,
31
+ "DISTINCT" => true,
32
+ "DROP" => true,
33
+ "ELSE" => true,
34
+ "EXCLUSIVE" => true,
35
+ "EXISTS" => true,
36
+ "FILE" => true,
37
+ "FLOAT" => true,
38
+ "FOR" => true,
39
+ "FROM" => true,
40
+ "GRANT" => true,
41
+ "GROUP" => true,
42
+ "HAVING" => true,
43
+ "IDENTIFIED" => true,
44
+ "IMMEDIATE" => true,
45
+ "IN" => true,
46
+ "INCREMENT" => true,
47
+ "INDEX" => true,
48
+ "INITIAL" => true,
49
+ "INSERT" => true,
50
+ "INTEGER" => true,
51
+ "INTERSECT" => true,
52
+ "INTO" => true,
53
+ "IS" => true,
54
+ "LEVEL" => true,
55
+ "LIKE" => true,
56
+ "LOCK" => true,
57
+ "LONG" => true,
58
+ "MAXEXTENTS" => true,
59
+ "MINUS" => true,
60
+ "MLSLABEL" => true,
61
+ "MODE" => true,
62
+ "MODIFY" => true,
63
+ "NOAUDIT" => true,
64
+ "NOCOMPRESS" => true,
65
+ "NOT" => true,
66
+ "NOWAIT" => true,
67
+ "NULL" => true,
68
+ "NUMBER" => true,
69
+ "OF" => true,
70
+ "OFFLINE" => true,
71
+ "ON" => true,
72
+ "ONLINE" => true,
73
+ "OPTION" => true,
74
+ "OR" => true,
75
+ "ORDER" => true,
76
+ "PCTFREE" => true,
77
+ "PRIOR" => true,
78
+ "PRIVILEGES" => true,
79
+ "PUBLIC" => true,
80
+ "RAW" => true,
81
+ "RENAME" => true,
82
+ "RESOURCE" => true,
83
+ "REVOKE" => true,
84
+ "ROW" => true,
85
+ "ROWID" => true,
86
+ "ROWNUM" => true,
87
+ "ROWS" => true,
88
+ "SELECT" => true,
89
+ "SESSION" => true,
90
+ "SET" => true,
91
+ "SHARE" => true,
92
+ "SIZE" => true,
93
+ "SMALLINT" => true,
94
+ "START" => true,
95
+ "SUCCESSFUL" => true,
96
+ "SYNONYM" => true,
97
+ "SYSDATE" => true,
98
+ "TABLE" => true,
99
+ "THEN" => true,
100
+ "TO" => true,
101
+ "TRIGGER" => true,
102
+ "UID" => true,
103
+ "UNION" => true,
104
+ "UNIQUE" => true,
105
+ "UPDATE" => true,
106
+ "USER" => true,
107
+ "VALIDATE" => true,
108
+ "VALUES" => true,
109
+ "VARCHAR" => true,
110
+ "VARCHAR2" => true,
111
+ "VIEW" => true,
112
+ "WHENEVER" => true,
113
+ "WHERE" => true,
114
+ "WITH" => true
115
+ }
116
+
117
+ def quote_oracle_reserved_words(name)
118
+ RESERVED_WORDS[name.to_s.upcase].nil? ? name : "\"#{name}\""
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
125
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedReservedWords
126
+ end
@@ -0,0 +1,168 @@
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, :tablespace, :columns) #:nodoc:
10
+ end
11
+
12
+ module OracleEnhancedSchemaDefinitions #:nodoc:
13
+ def self.included(base)
14
+ base::TableDefinition.class_eval do
15
+ include OracleEnhancedTableDefinition
16
+ end
17
+
18
+ # Available starting from ActiveRecord 2.1
19
+ base::Table.class_eval do
20
+ include OracleEnhancedTable
21
+ end if defined?(base::Table)
22
+ end
23
+ end
24
+
25
+ module OracleEnhancedTableDefinition
26
+ class ForeignKey < Struct.new(:base, :to_table, :options) #:nodoc:
27
+ def to_sql
28
+ base.foreign_key_definition(to_table, options)
29
+ end
30
+ alias to_s :to_sql
31
+ end
32
+
33
+ def self.included(base) #:nodoc:
34
+ base.class_eval do
35
+ alias_method_chain :references, :foreign_keys
36
+ alias_method_chain :to_sql, :foreign_keys
37
+ end
38
+ end
39
+
40
+ # Adds a :foreign_key option to TableDefinition.references.
41
+ # If :foreign_key is true, a foreign key constraint is added to the table.
42
+ # You can also specify a hash, which is passed as foreign key options.
43
+ #
44
+ # ===== Examples
45
+ # ====== Add goat_id column and a foreign key to the goats table.
46
+ # t.references(:goat, :foreign_key => true)
47
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
48
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
49
+ #
50
+ # Note: No foreign key is created if :polymorphic => true is used.
51
+ # Note: If no name is specified, the database driver creates one for you!
52
+ def references_with_foreign_keys(*args)
53
+ options = args.extract_options!
54
+ fk_options = options.delete(:foreign_key)
55
+
56
+ if fk_options && !options[:polymorphic]
57
+ fk_options = {} if fk_options == true
58
+ args.each { |to_table| foreign_key(to_table, fk_options) }
59
+ end
60
+
61
+ references_without_foreign_keys(*(args << options))
62
+ end
63
+
64
+ # Defines a foreign key for the table. +to_table+ can be a single Symbol, or
65
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
66
+ #
67
+ # ===== Examples
68
+ # ====== Creating a simple foreign key
69
+ # t.foreign_key(:people)
70
+ # ====== Defining the column
71
+ # t.foreign_key(:people, :column => :sender_id)
72
+ # ====== Creating a named foreign key
73
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
74
+ # ====== Defining the column of the +to_table+.
75
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
76
+ def foreign_key(to_table, options = {})
77
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
78
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
79
+ foreign_keys << ForeignKey.new(@base, to_table, options)
80
+ else
81
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
82
+ end
83
+ end
84
+
85
+ def to_sql_with_foreign_keys #:nodoc:
86
+ sql = to_sql_without_foreign_keys
87
+ sql << ', ' << (foreign_keys * ', ') unless foreign_keys.blank?
88
+ sql
89
+ end
90
+
91
+ private
92
+ def foreign_keys
93
+ @foreign_keys ||= []
94
+ end
95
+ end
96
+
97
+ module OracleEnhancedTable
98
+ def self.included(base) #:nodoc:
99
+ base.class_eval do
100
+ alias_method_chain :references, :foreign_keys
101
+ end
102
+ end
103
+
104
+ # Adds a new foreign key to the table. +to_table+ can be a single Symbol, or
105
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
106
+ #
107
+ # ===== Examples
108
+ # ====== Creating a simple foreign key
109
+ # t.foreign_key(:people)
110
+ # ====== Defining the column
111
+ # t.foreign_key(:people, :column => :sender_id)
112
+ # ====== Creating a named foreign key
113
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
114
+ # ====== Defining the column of the +to_table+.
115
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
116
+ def foreign_key(to_table, options = {})
117
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
118
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
119
+ @base.add_foreign_key(@table_name, to_table, options)
120
+ else
121
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
122
+ end
123
+ end
124
+
125
+ # Remove the given foreign key from the table.
126
+ #
127
+ # ===== Examples
128
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
129
+ # t.remove_foreign_key :companies
130
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
131
+ # remove_foreign_key :column => :branch_id
132
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
133
+ # remove_index :name => :party_foreign_key
134
+ def remove_foreign_key(options = {})
135
+ @base.remove_foreign_key(@table_name, options)
136
+ end
137
+
138
+ # Adds a :foreign_key option to TableDefinition.references.
139
+ # If :foreign_key is true, a foreign key constraint is added to the table.
140
+ # You can also specify a hash, which is passed as foreign key options.
141
+ #
142
+ # ===== Examples
143
+ # ====== Add goat_id column and a foreign key to the goats table.
144
+ # t.references(:goat, :foreign_key => true)
145
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
146
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
147
+ #
148
+ # Note: No foreign key is created if :polymorphic => true is used.
149
+ def references_with_foreign_keys(*args)
150
+ options = args.extract_options!
151
+ polymorphic = options[:polymorphic]
152
+ fk_options = options.delete(:foreign_key)
153
+
154
+ references_without_foreign_keys(*(args << options))
155
+ # references_without_foreign_keys adds {:type => :integer}
156
+ args.extract_options!
157
+ if fk_options && !polymorphic
158
+ fk_options = {} if fk_options == true
159
+ args.each { |to_table| foreign_key(to_table, fk_options) }
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+
166
+ ActiveRecord::ConnectionAdapters.class_eval do
167
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaDefinitions
168
+ end
@@ -0,0 +1,213 @@
1
+ module ActiveRecord #:nodoc:
2
+ module ConnectionAdapters #:nodoc:
3
+ module OracleEnhancedSchemaDumper #:nodoc:
4
+
5
+ def self.included(base) #:nodoc:
6
+ base.class_eval do
7
+ private
8
+ alias_method_chain :tables, :oracle_enhanced
9
+ alias_method_chain :indexes, :oracle_enhanced
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def tables_with_oracle_enhanced(stream)
16
+ sorted_tables = @connection.tables.sort
17
+ sorted_tables.each do |tbl|
18
+ # add table prefix or suffix for schema_migrations
19
+ next if [ActiveRecord::Migrator.proper_table_name('schema_migrations'), ignore_tables].flatten.any? do |ignored|
20
+ case ignored
21
+ when String; tbl == ignored
22
+ when Regexp; tbl =~ ignored
23
+ else
24
+ raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
25
+ end
26
+ end
27
+ # change table name inspect method
28
+ tbl.extend TableInspect
29
+ oracle_enhanced_table(tbl, stream)
30
+ # add primary key trigger if table has it
31
+ primary_key_trigger(tbl, stream)
32
+ end
33
+ sorted_tables.each do |tbl|
34
+ # add foreign keys if table has them
35
+ foreign_keys(tbl, stream)
36
+ end
37
+ # add synonyms in local schema
38
+ synonyms(stream)
39
+ end
40
+
41
+ def primary_key_trigger(table_name, stream)
42
+ if @connection.respond_to?(:has_primary_key_trigger?) && @connection.has_primary_key_trigger?(table_name)
43
+ pk, pk_seq = @connection.pk_and_sequence_for(table_name)
44
+ stream.print " add_primary_key_trigger #{table_name.inspect}"
45
+ stream.print ", :primary_key => \"#{pk}\"" if pk != 'id'
46
+ stream.print "\n\n"
47
+ end
48
+ end
49
+
50
+ def foreign_keys(table_name, stream)
51
+ if @connection.respond_to?(:foreign_keys) && (foreign_keys = @connection.foreign_keys(table_name)).any?
52
+ add_foreign_key_statements = foreign_keys.map do |foreign_key|
53
+ statement_parts = [ ('add_foreign_key ' + foreign_key.from_table.inspect) ]
54
+ statement_parts << foreign_key.to_table.inspect
55
+ statement_parts << (':name => ' + foreign_key.options[:name].inspect)
56
+
57
+ if foreign_key.options[:column] != "#{foreign_key.to_table.singularize}_id"
58
+ statement_parts << (':column => ' + foreign_key.options[:column].inspect)
59
+ end
60
+ if foreign_key.options[:primary_key] != 'id'
61
+ statement_parts << (':primary_key => ' + foreign_key.options[:primary_key].inspect)
62
+ end
63
+ unless foreign_key.options[:dependent].blank?
64
+ statement_parts << (':dependent => ' + foreign_key.options[:dependent].inspect)
65
+ end
66
+
67
+ ' ' + statement_parts.join(', ')
68
+ end
69
+
70
+ stream.puts add_foreign_key_statements.sort.join("\n")
71
+ stream.puts
72
+ end
73
+ end
74
+
75
+ def synonyms(stream)
76
+ if @connection.respond_to?(:synonyms)
77
+ syns = @connection.synonyms
78
+ syns.each do |syn|
79
+ table_name = syn.table_name
80
+ table_name = "#{syn.table_owner}.#{table_name}" if syn.table_owner
81
+ table_name = "#{table_name}@#{syn.db_link}" if syn.db_link
82
+ stream.print " add_synonym #{syn.name.inspect}, #{table_name.inspect}, :force => true"
83
+ stream.puts
84
+ end
85
+ stream.puts unless syns.empty?
86
+ end
87
+ end
88
+
89
+ def indexes_with_oracle_enhanced(table, stream)
90
+ if (indexes = @connection.indexes(table)).any?
91
+ add_index_statements = indexes.map do |index|
92
+ # use table.inspect as it will remove prefix and suffix
93
+ statment_parts = [ ('add_index ' + table.inspect) ]
94
+ statment_parts << index.columns.inspect
95
+ statment_parts << (':name => ' + index.name.inspect)
96
+ statment_parts << ':unique => true' if index.unique
97
+ statment_parts << ':tablespace => ' + index.tablespace.inspect if index.tablespace
98
+
99
+ ' ' + statment_parts.join(', ')
100
+ end
101
+
102
+ stream.puts add_index_statements.sort.join("\n")
103
+ stream.puts
104
+ end
105
+ end
106
+
107
+ def oracle_enhanced_table(table, stream)
108
+ columns = @connection.columns(table)
109
+ begin
110
+ tbl = StringIO.new
111
+
112
+ # first dump primary key column
113
+ if @connection.respond_to?(:pk_and_sequence_for)
114
+ pk, pk_seq = @connection.pk_and_sequence_for(table)
115
+ elsif @connection.respond_to?(:primary_key)
116
+ pk = @connection.primary_key(table)
117
+ end
118
+
119
+ tbl.print " create_table #{table.inspect}"
120
+
121
+ # addition to make temporary option work
122
+ tbl.print ", :temporary => true" if @connection.temporary_table?(table)
123
+
124
+ if columns.detect { |c| c.name == pk }
125
+ if pk != 'id'
126
+ tbl.print %Q(, :primary_key => "#{pk}")
127
+ end
128
+ else
129
+ tbl.print ", :id => false"
130
+ end
131
+ tbl.print ", :force => true"
132
+ tbl.puts " do |t|"
133
+
134
+ # then dump all non-primary key columns
135
+ column_specs = columns.map do |column|
136
+ raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
137
+ next if column.name == pk
138
+ spec = {}
139
+ spec[:name] = column.name.inspect
140
+ spec[:type] = column.type.to_s
141
+ spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
142
+ spec[:precision] = column.precision.inspect if !column.precision.nil?
143
+ spec[:scale] = column.scale.inspect if !column.scale.nil?
144
+ spec[:null] = 'false' if !column.null
145
+ spec[:default] = default_string(column.default) if column.has_default?
146
+ (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
147
+ spec
148
+ end.compact
149
+
150
+ # find all migration keys used in this table
151
+ keys = [:name, :limit, :precision, :scale, :default, :null] & column_specs.map(&:keys).flatten
152
+
153
+ # figure out the lengths for each column based on above keys
154
+ lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
155
+
156
+ # the string we're going to sprintf our values against, with standardized column widths
157
+ format_string = lengths.map{ |len| "%-#{len}s" }
158
+
159
+ # find the max length for the 'type' column, which is special
160
+ type_length = column_specs.map{ |column| column[:type].length }.max
161
+
162
+ # add column type definition to our format string
163
+ format_string.unshift " t.%-#{type_length}s "
164
+
165
+ format_string *= ''
166
+
167
+ column_specs.each do |colspec|
168
+ values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
169
+ values.unshift colspec[:type]
170
+ tbl.print((format_string % values).gsub(/,\s*$/, ''))
171
+ tbl.puts
172
+ end
173
+
174
+ tbl.puts " end"
175
+ tbl.puts
176
+
177
+ indexes(table, tbl)
178
+
179
+ tbl.rewind
180
+ stream.print tbl.read
181
+ rescue => e
182
+ stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
183
+ stream.puts "# #{e.message}"
184
+ stream.puts
185
+ end
186
+
187
+ stream
188
+ end
189
+
190
+
191
+ # remove table name prefix and suffix when doing #inspect (which is used in tables method)
192
+ module TableInspect #:nodoc:
193
+ def inspect
194
+ remove_prefix_and_suffix(self)
195
+ end
196
+
197
+ private
198
+ def remove_prefix_and_suffix(table_name)
199
+ if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix}(.*)#{ActiveRecord::Base.table_name_suffix}\Z/
200
+ "\"#{$1}\""
201
+ else
202
+ "\"#{table_name}\""
203
+ end
204
+ end
205
+ end
206
+
207
+ end
208
+ end
209
+ end
210
+
211
+ ActiveRecord::SchemaDumper.class_eval do
212
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaDumper
213
+ end