c3-activerecord-oracle_enhanced-adapter 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/History.txt +182 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +32 -0
  4. data/README.rdoc +77 -0
  5. data/Rakefile +49 -0
  6. data/VERSION +1 -0
  7. data/activerecord-oracle_enhanced-adapter.gemspec +79 -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 +1664 -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 +218 -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 +137 -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