activerecord-oracle_enhanced-adapter 1.8.2 → 5.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +190 -5
  3. data/README.md +10 -10
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +2 -0
  6. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +9 -71
  7. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +84 -73
  8. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +12 -12
  9. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +52 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +35 -7
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +2 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +59 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +379 -402
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +7 -1
  15. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +46 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +242 -247
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +9 -1
  18. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +3 -1
  19. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +25 -9
  20. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +9 -6
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +10 -5
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +48 -51
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +261 -59
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +2 -34
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +267 -222
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +33 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +2 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +136 -547
  29. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/boolean.rb +4 -2
  30. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/integer.rb +4 -2
  31. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  32. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/national_character_string.rb +5 -3
  33. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  34. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/raw.rb +4 -2
  35. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/string.rb +4 -2
  36. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/text.rb +4 -2
  37. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  38. data/lib/active_record/{oracle_enhanced/type → type/oracle_enhanced}/timestamptz.rb +4 -2
  39. data/lib/activerecord-oracle_enhanced-adapter.rb +2 -6
  40. data/spec/active_record/connection_adapters/{oracle_enhanced_emulate_oracle_adapter_spec.rb → emulation/oracle_adapter_spec.rb} +2 -0
  41. data/spec/active_record/connection_adapters/{oracle_enhanced_connection_spec.rb → oracle_enhanced/connection_spec.rb} +82 -38
  42. data/spec/active_record/connection_adapters/{oracle_enhanced_context_index_spec.rb → oracle_enhanced/context_index_spec.rb} +20 -16
  43. data/spec/active_record/connection_adapters/{oracle_enhanced_database_tasks_spec.rb → oracle_enhanced/database_tasks_spec.rb} +17 -5
  44. data/spec/active_record/connection_adapters/{oracle_enhanced_dbms_output_spec.rb → oracle_enhanced/dbms_output_spec.rb} +2 -0
  45. data/spec/active_record/connection_adapters/{oracle_enhanced_procedures_spec.rb → oracle_enhanced/procedures_spec.rb} +26 -33
  46. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +196 -0
  47. data/spec/active_record/connection_adapters/{oracle_enhanced_schema_dump_spec.rb → oracle_enhanced/schema_dumper_spec.rb} +61 -90
  48. data/spec/active_record/connection_adapters/{oracle_enhanced_schema_statements_spec.rb → oracle_enhanced/schema_statements_spec.rb} +95 -28
  49. data/spec/active_record/connection_adapters/{oracle_enhanced_structure_dump_spec.rb → oracle_enhanced/structure_dump_spec.rb} +48 -2
  50. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +202 -331
  51. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +15 -1106
  52. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  53. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +207 -0
  54. data/spec/active_record/{connection_adapters/oracle_enhanced_dirty_spec.rb → oracle_enhanced/type/dirty_spec.rb} +3 -1
  55. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  56. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +91 -0
  57. data/spec/active_record/oracle_enhanced/type/json_spec.rb +57 -0
  58. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  59. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  60. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +122 -0
  61. data/spec/active_record/oracle_enhanced/type/text_spec.rb +229 -0
  62. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +75 -0
  63. data/spec/spec_helper.rb +15 -1
  64. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  65. metadata +63 -48
  66. data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +0 -28
  67. data/lib/active_record/oracle_enhanced/type/json.rb +0 -8
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module OracleEnhanced
@@ -20,40 +22,6 @@ module ActiveRecord
20
22
  # call the same private method that is used for create_table :primary_key_trigger => true
21
23
  create_primary_key_trigger(table_name, options)
22
24
  end
23
-
24
- # Add synonym to existing table or view or sequence. Can be used to create local synonym to
25
- # remote table in other schema or in other database
26
- # Examples:
27
- #
28
- # add_synonym :posts, "blog.posts"
29
- # add_synonym :posts_seq, "blog.posts_seq"
30
- # add_synonym :employees, "hr.employees@dblink", :force => true
31
- #
32
- def add_synonym(name, table_name, options = {})
33
- sql = "CREATE"
34
- if options[:force] == true
35
- sql << " OR REPLACE"
36
- end
37
- sql << " SYNONYM #{quote_table_name(name)} FOR #{quote_table_name(table_name)}"
38
- execute sql
39
- end
40
-
41
- # Remove existing synonym to table or view or sequence
42
- # Example:
43
- #
44
- # remove_synonym :posts, "blog.posts"
45
- #
46
- def remove_synonym(name)
47
- execute "DROP SYNONYM #{quote_table_name(name)}"
48
- end
49
-
50
- # get synonyms for schema dump
51
- def synonyms #:nodoc:
52
- select_all("SELECT synonym_name, table_owner, table_name, db_link FROM all_synonyms where owner = SYS_CONTEXT('userenv', 'session_user')").collect do |row|
53
- OracleEnhanced::SynonymDefinition.new(oracle_downcase(row["synonym_name"]),
54
- oracle_downcase(row["table_owner"]), oracle_downcase(row["table_name"]), oracle_downcase(row["db_link"]))
55
- end
56
- end
57
25
  end
58
26
  end
59
27
  end
@@ -1,78 +1,94 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord #:nodoc:
2
4
  module ConnectionAdapters #:nodoc:
3
- module OracleEnhancedStructureDump #:nodoc:
4
- # Statements separator used in structure dump to allow loading of structure dump also with SQL*Plus
5
- STATEMENT_TOKEN = "\n\n/\n\n"
5
+ module OracleEnhanced #:nodoc:
6
+ module StructureDump #:nodoc:
7
+ # Statements separator used in structure dump to allow loading of structure dump also with SQL*Plus
8
+ STATEMENT_TOKEN = "\n\n/\n\n"
6
9
 
7
- def structure_dump #:nodoc:
8
- structure = select_values("SELECT sequence_name FROM all_sequences where sequence_owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY 1").map do |seq|
9
- "CREATE SEQUENCE \"#{seq}\""
10
- end
11
- select_values("SELECT table_name FROM all_tables t
12
- WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
13
- AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
14
- AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
15
- ORDER BY 1").each do |table_name|
16
- virtual_columns = virtual_columns_for(table_name)
17
- ddl = "CREATE#{ ' GLOBAL TEMPORARY' if temporary_table?(table_name)} TABLE \"#{table_name}\" (\n"
18
- cols = select_all("
19
- SELECT column_name, data_type, data_length, char_used, char_length, data_precision, data_scale, data_default, nullable
20
- FROM all_tab_columns
21
- WHERE table_name = '#{table_name}'
22
- AND owner = SYS_CONTEXT('userenv', 'session_user')
23
- ORDER BY column_id
24
- ").map do |row|
25
- if (v = virtual_columns.find { |col| col["column_name"] == row["column_name"] })
26
- structure_dump_virtual_column(row, v["data_default"])
27
- else
28
- structure_dump_column(row)
10
+ def structure_dump #:nodoc:
11
+ sequences = select(<<-SQL.strip.gsub(/\s+/, " "), "sequences to dump at structure dump")
12
+ SELECT sequence_name, min_value, max_value, increment_by, order_flag, cycle_flag
13
+ FROM all_sequences
14
+ where sequence_owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY 1
15
+ SQL
16
+
17
+ structure = sequences.map do |result|
18
+ "CREATE SEQUENCE #{quote_table_name(result["sequence_name"])} MINVALUE #{result["min_value"]} MAXVALUE #{result["max_value"]} INCREMENT BY #{result["increment_by"]} #{result["order_flag"] == 'Y' ? "ORDER" : "NOORDER"} #{result["cycle_flag"] == 'Y' ? "CYCLE" : "NOCYCLE"}"
19
+ end
20
+ tables = select_values(<<-SQL.strip.gsub(/\s+/, " "), "tables at structure dump")
21
+ SELECT table_name FROM all_tables t
22
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
23
+ AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv
24
+ WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
25
+ AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl
26
+ WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
27
+ ORDER BY 1
28
+ SQL
29
+ tables.each do |table_name|
30
+ virtual_columns = virtual_columns_for(table_name) if supports_virtual_columns?
31
+ ddl = "CREATE#{ ' GLOBAL TEMPORARY' if temporary_table?(table_name)} TABLE \"#{table_name}\" (\n".dup
32
+ columns = select_all(<<-SQL.strip.gsub(/\s+/, " "), "columns at structure dump")
33
+ SELECT column_name, data_type, data_length, char_used, char_length,
34
+ data_precision, data_scale, data_default, nullable
35
+ FROM all_tab_columns
36
+ WHERE table_name = '#{table_name}'
37
+ AND owner = SYS_CONTEXT('userenv', 'session_user')
38
+ ORDER BY column_id
39
+ SQL
40
+ cols = columns.map do |row|
41
+ if (v = virtual_columns.find { |col| col["column_name"] == row["column_name"] })
42
+ structure_dump_virtual_column(row, v["data_default"])
43
+ else
44
+ structure_dump_column(row)
45
+ end
29
46
  end
47
+ ddl << cols.map { |col| " #{col}" }.join(",\n")
48
+ ddl << structure_dump_primary_key(table_name)
49
+ ddl << "\n)"
50
+ structure << ddl
51
+ structure << structure_dump_indexes(table_name)
52
+ structure << structure_dump_unique_keys(table_name)
53
+ structure << structure_dump_table_comments(table_name)
54
+ structure << structure_dump_column_comments(table_name)
30
55
  end
31
- ddl << cols.map { |col| " #{col}" }.join(",\n")
32
- ddl << structure_dump_primary_key(table_name)
33
- ddl << "\n)"
34
- structure << ddl
35
- structure << structure_dump_indexes(table_name)
36
- structure << structure_dump_unique_keys(table_name)
37
- structure << structure_dump_table_comments(table_name)
38
- structure << structure_dump_column_comments(table_name)
39
- end
40
56
 
41
- join_with_statement_token(structure) << structure_dump_fk_constraints
42
- end
57
+ join_with_statement_token(structure) << structure_dump_fk_constraints
58
+ end
43
59
 
44
- def structure_dump_column(column) #:nodoc:
45
- col = "\"#{column['column_name']}\" #{column['data_type']}"
46
- if (column["data_type"] == "NUMBER") && !column["data_precision"].nil?
47
- col << "(#{column['data_precision'].to_i}"
48
- col << ",#{column['data_scale'].to_i}" if !column["data_scale"].nil?
49
- col << ")"
50
- elsif column["data_type"].include?("CHAR") || column["data_type"] == "RAW"
51
- length = column["char_used"] == "C" ? column["char_length"].to_i : column["data_length"].to_i
52
- col << "(#{length})"
60
+ def structure_dump_column(column) #:nodoc:
61
+ col = "\"#{column['column_name']}\" #{column['data_type']}".dup
62
+ if (column["data_type"] == "NUMBER") && !column["data_precision"].nil?
63
+ col << "(#{column['data_precision'].to_i}"
64
+ col << ",#{column['data_scale'].to_i}" if !column["data_scale"].nil?
65
+ col << ")"
66
+ elsif column["data_type"].include?("CHAR") || column["data_type"] == "RAW"
67
+ length = column["char_used"] == "C" ? column["char_length"].to_i : column["data_length"].to_i
68
+ col << "(#{length})"
69
+ end
70
+ col << " DEFAULT #{column['data_default']}" if !column["data_default"].nil?
71
+ col << " NOT NULL" if column["nullable"] == "N"
72
+ col
53
73
  end
54
- col << " DEFAULT #{column['data_default']}" if !column["data_default"].nil?
55
- col << " NOT NULL" if column["nullable"] == "N"
56
- col
57
- end
58
74
 
59
- def structure_dump_virtual_column(column, data_default) #:nodoc:
60
- data_default = data_default.gsub(/"/, "")
61
- col = "\"#{column['column_name']}\" #{column['data_type']}"
62
- if (column["data_type"] == "NUMBER") && !column["data_precision"].nil?
63
- col << "(#{column['data_precision'].to_i}"
64
- col << ",#{column['data_scale'].to_i}" if !column["data_scale"].nil?
65
- col << ")"
66
- elsif column["data_type"].include?("CHAR") || column["data_type"] == "RAW"
67
- length = column["char_used"] == "C" ? column["char_length"].to_i : column["data_length"].to_i
68
- col << "(#{length})"
75
+ def structure_dump_virtual_column(column, data_default) #:nodoc:
76
+ data_default = data_default.gsub(/"/, "")
77
+ col = "\"#{column['column_name']}\" #{column['data_type']}".dup
78
+ if (column["data_type"] == "NUMBER") && !column["data_precision"].nil?
79
+ col << "(#{column['data_precision'].to_i}"
80
+ col << ",#{column['data_scale'].to_i}" if !column["data_scale"].nil?
81
+ col << ")"
82
+ elsif column["data_type"].include?("CHAR") || column["data_type"] == "RAW"
83
+ length = column["char_used"] == "C" ? column["char_length"].to_i : column["data_length"].to_i
84
+ col << "(#{length})"
85
+ end
86
+ col << " GENERATED ALWAYS AS (#{data_default}) VIRTUAL"
69
87
  end
70
- col << " GENERATED ALWAYS AS (#{data_default}) VIRTUAL"
71
- end
72
88
 
73
- def structure_dump_primary_key(table) #:nodoc:
74
- opts = { name: "", cols: [] }
75
- pks = select_all(<<-SQL, "Primary Keys")
89
+ def structure_dump_primary_key(table) #:nodoc:
90
+ opts = { name: "", cols: [] }
91
+ pks = select_all(<<-SQL.strip.gsub(/\s+/, " "), "Primary Keys")
76
92
  SELECT a.constraint_name, a.column_name, a.position
77
93
  FROM all_cons_columns a
78
94
  JOIN all_constraints c
@@ -82,16 +98,16 @@ module ActiveRecord #:nodoc:
82
98
  AND a.owner = c.owner
83
99
  AND c.owner = SYS_CONTEXT('userenv', 'current_schema')
84
100
  SQL
85
- pks.each do |row|
86
- opts[:name] = row["constraint_name"]
87
- opts[:cols][row["position"] - 1] = row["column_name"]
101
+ pks.each do |row|
102
+ opts[:name] = row["constraint_name"]
103
+ opts[:cols][row["position"] - 1] = row["column_name"]
104
+ end
105
+ opts[:cols].length > 0 ? ",\n CONSTRAINT #{opts[:name]} PRIMARY KEY (#{opts[:cols].join(',')})" : ""
88
106
  end
89
- opts[:cols].length > 0 ? ",\n CONSTRAINT #{opts[:name]} PRIMARY KEY (#{opts[:cols].join(',')})" : ""
90
- end
91
107
 
92
- def structure_dump_unique_keys(table) #:nodoc:
93
- keys = {}
94
- uks = select_all(<<-SQL, "Primary Keys")
108
+ def structure_dump_unique_keys(table) #:nodoc:
109
+ keys = {}
110
+ uks = select_all(<<-SQL.strip.gsub(/\s+/, " "), "Primary Keys")
95
111
  SELECT a.constraint_name, a.column_name, a.position
96
112
  FROM all_cons_columns a
97
113
  JOIN all_constraints c
@@ -101,197 +117,229 @@ module ActiveRecord #:nodoc:
101
117
  AND a.owner = c.owner
102
118
  AND c.owner = SYS_CONTEXT('userenv', 'current_schema')
103
119
  SQL
104
- uks.each do |uk|
105
- keys[uk["constraint_name"]] ||= []
106
- keys[uk["constraint_name"]][uk["position"] - 1] = uk["column_name"]
107
- end
108
- keys.map do |k, v|
109
- "ALTER TABLE #{table.upcase} ADD CONSTRAINT #{k} UNIQUE (#{v.join(',')})"
110
- end
111
- end
112
-
113
- def structure_dump_indexes(table_name) #:nodoc:
114
- indexes(table_name).map do |options|
115
- column_names = options[:columns]
116
- options = { name: options[:name], unique: options[:unique] }
117
- index_name = index_name(table_name, column: column_names)
118
- if Hash === options # legacy support, since this param was a string
119
- index_type = options[:unique] ? "UNIQUE" : ""
120
- index_name = options[:name] || index_name
121
- else
122
- index_type = options
120
+ uks.each do |uk|
121
+ keys[uk["constraint_name"]] ||= []
122
+ keys[uk["constraint_name"]][uk["position"] - 1] = uk["column_name"]
123
+ end
124
+ keys.map do |k, v|
125
+ "ALTER TABLE #{table.upcase} ADD CONSTRAINT #{k} UNIQUE (#{v.join(',')})"
123
126
  end
124
- quoted_column_names = column_names.map { |e| quote_column_name_or_expression(e) }.join(", ")
125
- "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
126
127
  end
127
- end
128
128
 
129
- def structure_dump_fk_constraints #:nodoc:
130
- fks = select_all("SELECT table_name FROM all_tables WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1").map do |table|
131
- if respond_to?(:foreign_keys) && (foreign_keys = foreign_keys(table["table_name"])).any?
132
- foreign_keys.map do |fk|
133
- sql = "ALTER TABLE #{quote_table_name(fk.from_table)} ADD CONSTRAINT #{quote_column_name(fk.options[:name])} "
134
- sql << "#{foreign_key_definition(fk.to_table, fk.options)}"
129
+ def structure_dump_indexes(table_name) #:nodoc:
130
+ indexes(table_name).map do |options|
131
+ column_names = options.columns
132
+ options = { name: options.name, unique: options.unique }
133
+ index_name = index_name(table_name, column: column_names)
134
+ if Hash === options # legacy support, since this param was a string
135
+ index_type = options[:unique] ? "UNIQUE" : ""
136
+ index_name = options[:name] || index_name
137
+ else
138
+ index_type = options
135
139
  end
140
+ quoted_column_names = column_names.map { |e| quote_column_name_or_expression(e) }.join(", ")
141
+ "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
136
142
  end
137
- end.flatten.compact
138
- join_with_statement_token(fks)
139
- end
140
-
141
- def structure_dump_table_comments(table_name)
142
- comments = []
143
- comment = table_comment(table_name)
144
-
145
- unless comment.nil?
146
- comments << "COMMENT ON TABLE #{quote_table_name(table_name)} IS '#{quote_string(comment)}'"
147
143
  end
148
144
 
149
- join_with_statement_token(comments)
150
- end
145
+ def structure_dump_fk_constraints #:nodoc:
146
+ foreign_keys = select_all(<<-SQL.strip.gsub(/\s+/, " "), "foreign keys at structure dump")
147
+ SELECT table_name FROM all_tables
148
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
149
+ SQL
150
+ fks = foreign_keys.map do |table|
151
+ if respond_to?(:foreign_keys) && (foreign_keys = foreign_keys(table["table_name"])).any?
152
+ foreign_keys.map do |fk|
153
+ sql = "ALTER TABLE #{quote_table_name(fk.from_table)} ADD CONSTRAINT #{quote_column_name(fk.options[:name])} ".dup
154
+ sql << "#{foreign_key_definition(fk.to_table, fk.options)}"
155
+ end
156
+ end
157
+ end.flatten.compact
158
+ join_with_statement_token(fks)
159
+ end
151
160
 
152
- def structure_dump_column_comments(table_name)
153
- comments = []
154
- columns = select_values("SELECT column_name FROM user_tab_columns WHERE table_name = '#{table_name}' ORDER BY column_id")
161
+ def structure_dump_table_comments(table_name)
162
+ comments = []
163
+ comment = table_comment(table_name)
155
164
 
156
- columns.each do |column|
157
- comment = column_comment(table_name, column)
158
165
  unless comment.nil?
159
- comments << "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column)} IS '#{quote_string(comment)}'"
166
+ comments << "COMMENT ON TABLE #{quote_table_name(table_name)} IS '#{quote_string(comment)}'"
160
167
  end
161
- end
162
168
 
163
- join_with_statement_token(comments)
164
- end
169
+ join_with_statement_token(comments)
170
+ end
165
171
 
166
- def foreign_key_definition(to_table, options = {}) #:nodoc:
167
- column_sql = quote_column_name(options[:column] || "#{to_table.to_s.singularize}_id")
168
- references = options[:references] ? options[:references].first : nil
169
- references_sql = quote_column_name(options[:primary_key] || references || "id")
172
+ def structure_dump_column_comments(table_name)
173
+ comments = []
174
+ columns = select_values(<<-SQL.strip.gsub(/\s+/, " "), "column comments at structure dump")
175
+ SELECT column_name FROM user_tab_columns
176
+ WHERE table_name = '#{table_name}' ORDER BY column_id
177
+ SQL
170
178
 
171
- sql = "FOREIGN KEY (#{column_sql}) REFERENCES #{quote_table_name(to_table)}(#{references_sql})"
179
+ columns.each do |column|
180
+ comment = column_comment(table_name, column)
181
+ unless comment.nil?
182
+ comments << "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column)} IS '#{quote_string(comment)}'"
183
+ end
184
+ end
172
185
 
173
- case options[:dependent]
174
- when :nullify
175
- sql << " ON DELETE SET NULL"
176
- when :delete
177
- sql << " ON DELETE CASCADE"
186
+ join_with_statement_token(comments)
178
187
  end
179
- sql
180
- end
181
188
 
182
- # Extract all stored procedures, packages, synonyms and views.
183
- def structure_dump_db_stored_code #:nodoc:
184
- structure = []
185
- select_all("SELECT DISTINCT name, type
186
- FROM all_source
187
- WHERE type IN ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TRIGGER', 'TYPE')
188
- AND name NOT LIKE 'BIN$%'
189
- AND owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY type").each do |source|
190
- ddl = "CREATE OR REPLACE \n"
191
- select_all("
192
- SELECT text
193
- FROM all_source
194
- WHERE name = '#{source['name']}'
195
- AND type = '#{source['type']}'
196
- AND owner = SYS_CONTEXT('userenv', 'current_schema')
197
- ORDER BY line
198
- ").each do |row|
199
- ddl << row["text"]
189
+ def foreign_key_definition(to_table, options = {}) #:nodoc:
190
+ column_sql = quote_column_name(options[:column] || "#{to_table.to_s.singularize}_id")
191
+ references = options[:references] ? options[:references].first : nil
192
+ references_sql = quote_column_name(options[:primary_key] || references || "id")
193
+
194
+ sql = "FOREIGN KEY (#{column_sql}) REFERENCES #{quote_table_name(to_table)}(#{references_sql})"
195
+
196
+ case options[:dependent]
197
+ when :nullify
198
+ sql << " ON DELETE SET NULL"
199
+ when :delete
200
+ sql << " ON DELETE CASCADE"
200
201
  end
201
- ddl << ";" unless ddl.strip[-1, 1] == ";"
202
- structure << ddl
202
+ sql
203
203
  end
204
204
 
205
- # export views
206
- select_all("SELECT view_name, text FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY view_name ASC").each do |view|
207
- structure << "CREATE OR REPLACE FORCE VIEW #{view['view_name']} AS\n #{view['text']}"
208
- end
205
+ # Extract all stored procedures, packages, synonyms and views.
206
+ def structure_dump_db_stored_code #:nodoc:
207
+ structure = []
208
+ all_source = select_all(<<-SQL.strip.gsub(/\s+/, " "), "stored program at structure dump")
209
+ SELECT DISTINCT name, type
210
+ FROM all_source
211
+ WHERE type IN ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TRIGGER', 'TYPE')
212
+ AND name NOT LIKE 'BIN$%'
213
+ AND owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY type
214
+ SQL
215
+ all_source.each do |source|
216
+ ddl = "CREATE OR REPLACE \n".dup
217
+ texts = select_all(<<-SQL.strip.gsub(/\s+/, " "), "all source at structure dump")
218
+ SELECT text
219
+ FROM all_source
220
+ WHERE name = '#{source['name']}'
221
+ AND type = '#{source['type']}'
222
+ AND owner = SYS_CONTEXT('userenv', 'current_schema')
223
+ ORDER BY line
224
+ SQL
225
+ texts.each do |row|
226
+ ddl << row["text"]
227
+ end
228
+ ddl << ";" unless ddl.strip[-1, 1] == ";"
229
+ structure << ddl
230
+ end
209
231
 
210
- # export synonyms
211
- select_all("SELECT owner, synonym_name, table_name, table_owner
212
- FROM all_synonyms
213
- WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ").each do |synonym|
214
- structure << "CREATE OR REPLACE #{synonym['owner'] == 'PUBLIC' ? 'PUBLIC' : '' } SYNONYM #{synonym['synonym_name']}
215
- FOR #{synonym['table_owner']}.#{synonym['table_name']}"
216
- end
232
+ # export views
233
+ views = select_all(<<-SQL.strip.gsub(/\s+/, " "), "views at structure dump")
234
+ SELECT view_name, text FROM all_views
235
+ WHERE owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY view_name ASC
236
+ SQL
237
+ views.each do |view|
238
+ structure << "CREATE OR REPLACE FORCE VIEW #{view['view_name']} AS\n #{view['text']}"
239
+ end
217
240
 
218
- join_with_statement_token(structure)
219
- end
241
+ # export synonyms
242
+ synonyms = select_all(<<-SQL.strip.gsub(/\s+/, " "), "synonyms at structure dump")
243
+ SELECT owner, synonym_name, table_name, table_owner
244
+ FROM all_synonyms
245
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
246
+ SQL
247
+ synonyms.each do |synonym|
248
+ structure << "CREATE OR REPLACE #{synonym['owner'] == 'PUBLIC' ? 'PUBLIC' : '' } SYNONYM #{synonym['synonym_name']}
249
+ FOR #{synonym['table_owner']}.#{synonym['table_name']}"
250
+ end
220
251
 
221
- def structure_drop #:nodoc:
222
- statements = select_values("SELECT sequence_name FROM all_sequences where sequence_owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY 1").map do |seq|
223
- "DROP SEQUENCE \"#{seq}\""
252
+ join_with_statement_token(structure)
224
253
  end
225
- select_values("SELECT table_name from all_tables t
226
- WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
227
- AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
228
- AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
229
- ORDER BY 1").each do |table|
230
- statements << "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
254
+
255
+ def structure_drop #:nodoc:
256
+ sequences = select_values(<<-SQL.strip.gsub(/\s+/, " "), "sequences to drop at structure dump")
257
+ SELECT sequence_name FROM all_sequences where sequence_owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY 1
258
+ SQL
259
+ statements = sequences.map do |seq|
260
+ "DROP SEQUENCE \"#{seq}\""
261
+ end
262
+ tables = select_values(<<-SQL.strip.gsub(/\s+/, " "), "tables to drop at structure dump")
263
+ SELECT table_name from all_tables t
264
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
265
+ AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv
266
+ WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
267
+ AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl
268
+ WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
269
+ ORDER BY 1
270
+ SQL
271
+ tables.each do |table|
272
+ statements << "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
273
+ end
274
+ join_with_statement_token(statements)
231
275
  end
232
- join_with_statement_token(statements)
233
- end
234
276
 
235
- def temp_table_drop #:nodoc:
236
- join_with_statement_token(select_values(
237
- "SELECT table_name FROM all_tables
238
- WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N' AND temporary = 'Y' ORDER BY 1").map do |table|
239
- "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
240
- end)
241
- end
277
+ def temp_table_drop #:nodoc:
278
+ temporary_tables = select_values(<<-SQL.strip.gsub(/\s+/, " "), "temporary tables to drop at structure dump")
279
+ SELECT table_name FROM all_tables
280
+ WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
281
+ AND secondary = 'N' AND temporary = 'Y' ORDER BY 1
282
+ SQL
283
+ statements = temporary_tables.map do |table|
284
+ "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
285
+ end
286
+ join_with_statement_token(statements)
287
+ end
242
288
 
243
- def full_drop(preserve_tables = false) #:nodoc:
244
- s = preserve_tables ? [] : [structure_drop]
245
- s << temp_table_drop if preserve_tables
246
- s << drop_sql_for_feature("view")
247
- s << drop_sql_for_feature("materialized view")
248
- s << drop_sql_for_feature("synonym")
249
- s << drop_sql_for_feature("type")
250
- s << drop_sql_for_object("package")
251
- s << drop_sql_for_object("function")
252
- s << drop_sql_for_object("procedure")
253
- s.join
254
- end
289
+ def full_drop(preserve_tables = false) #:nodoc:
290
+ s = preserve_tables ? [] : [structure_drop]
291
+ s << temp_table_drop if preserve_tables
292
+ s << drop_sql_for_feature("view")
293
+ s << drop_sql_for_feature("materialized view")
294
+ s << drop_sql_for_feature("synonym")
295
+ s << drop_sql_for_feature("type")
296
+ s << drop_sql_for_object("package")
297
+ s << drop_sql_for_object("function")
298
+ s << drop_sql_for_object("procedure")
299
+ s.join
300
+ end
255
301
 
256
- def execute_structure_dump(string)
257
- string.split(STATEMENT_TOKEN).each do |ddl|
258
- execute(ddl) unless ddl.blank?
302
+ def execute_structure_dump(string)
303
+ string.split(STATEMENT_TOKEN).each do |ddl|
304
+ execute(ddl) unless ddl.blank?
305
+ end
259
306
  end
260
- end
261
307
 
262
308
  private
263
309
 
264
- # virtual columns are an 11g feature. This returns [] if feature is not
265
- # present or none are found.
310
+ # Called only if `supports_virtual_columns?` returns true
266
311
  # return [{'column_name' => 'FOOS', 'data_default' => '...'}, ...]
267
312
  def virtual_columns_for(table)
268
- begin
269
- select_all <<-SQL
313
+ select_all(<<-SQL.strip.gsub(/\s+/, " "), "virtual columns for")
270
314
  SELECT column_name, data_default
271
- FROM all_tab_cols
272
- WHERE virtual_column = 'YES'
273
- AND owner = SYS_CONTEXT('userenv', 'session_user')
274
- AND table_name = '#{table.upcase}'
315
+ FROM all_tab_cols
316
+ WHERE virtual_column = 'YES'
317
+ AND owner = SYS_CONTEXT('userenv', 'session_user')
318
+ AND table_name = '#{table.upcase}'
275
319
  SQL
276
- # feature not supported previous to 11g
277
- rescue ActiveRecord::StatementInvalid => _e
278
- []
279
- end
280
320
  end
281
321
 
282
322
  def drop_sql_for_feature(type)
283
323
  short_type = type == "materialized view" ? "mview" : type
284
- join_with_statement_token(
285
- select_values("SELECT #{short_type}_name FROM all_#{short_type.tableize} where owner = SYS_CONTEXT('userenv', 'session_user')").map do |name|
324
+ features = select_values(<<-SQL.strip.gsub(/\s+/, " "), "features to drop")
325
+ SELECT #{short_type}_name FROM all_#{short_type.tableize}
326
+ where owner = SYS_CONTEXT('userenv', 'session_user')
327
+ SQL
328
+ statements = features.map do |name|
286
329
  "DROP #{type.upcase} \"#{name}\""
287
- end)
330
+ end
331
+ join_with_statement_token(statements)
288
332
  end
289
333
 
290
334
  def drop_sql_for_object(type)
291
- join_with_statement_token(
292
- select_values("SELECT object_name FROM all_objects WHERE object_type = '#{type.upcase}' and owner = SYS_CONTEXT('userenv', 'session_user')").map do |name|
335
+ objects = select_values(<<-SQL.strip.gsub(/\s+/, " "), "objects to drop")
336
+ SELECT object_name FROM all_objects
337
+ WHERE object_type = '#{type.upcase}' and owner = SYS_CONTEXT('userenv', 'session_user')
338
+ SQL
339
+ statements = objects.map do |name|
293
340
  "DROP #{type.upcase} \"#{name}\""
294
- end)
341
+ end
342
+ join_with_statement_token(statements)
295
343
  end
296
344
 
297
345
  def join_with_statement_token(array)
@@ -299,10 +347,7 @@ module ActiveRecord #:nodoc:
299
347
  string << STATEMENT_TOKEN unless string.blank?
300
348
  string
301
349
  end
350
+ end
302
351
  end
303
352
  end
304
353
  end
305
-
306
- ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
307
- include ActiveRecord::ConnectionAdapters::OracleEnhancedStructureDump
308
- end