oracle_enhanced 1.3.0.pre → 1.3.0.pre2
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.
- data/.gitignore +0 -1
- data/History.txt +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced.rake +3 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +223 -154
- data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +227 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +6 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +2 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +24 -9
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -1
- data/lib/{oracle_enhanced.rb → active_record/oracle_enhanced.rb} +0 -2
- data/oracle_enhanced.gemspec +7 -4
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +37 -10
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_structure_dumper_spec.rb +27 -20
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +292 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +24 -28
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +13 -11
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +70 -68
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +14 -1
- data/spec/spec_helper.rb +97 -24
- metadata +8 -5
@@ -0,0 +1,227 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module OracleEnhancedContextIndex
|
4
|
+
|
5
|
+
# Define full text index with CONTEXT index type
|
6
|
+
def add_context_index(table_name, column_name, options = {})
|
7
|
+
self.all_schema_indexes = nil
|
8
|
+
column_names = Array(column_name)
|
9
|
+
index_name = options[:name] || index_name(table_name, :column => options[:index_column] || column_names,
|
10
|
+
# CONEXT index name max length is 25
|
11
|
+
:identifier_max_length => 25)
|
12
|
+
|
13
|
+
quoted_column_name = quote_column_name(options[:index_column] || column_names.first)
|
14
|
+
if options[:index_column_trigger_on]
|
15
|
+
raise ArgumentError, "Option :index_column should be specified together with :index_column_cource option" \
|
16
|
+
unless options[:index_column]
|
17
|
+
create_index_column_trigger(table_name, index_name, options[:index_column], options[:index_column_trigger_on])
|
18
|
+
end
|
19
|
+
|
20
|
+
sql = "CREATE INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
21
|
+
sql << " (#{quoted_column_name})"
|
22
|
+
sql << " INDEXTYPE IS CTXSYS.CONTEXT"
|
23
|
+
parameters = []
|
24
|
+
if column_names.size > 1
|
25
|
+
procedure_name = default_datastore_procedure(index_name)
|
26
|
+
datastore_name = default_datastore_name(index_name)
|
27
|
+
create_datastore_procedure(table_name, procedure_name, column_names, options)
|
28
|
+
create_datastore_preference(datastore_name, procedure_name)
|
29
|
+
parameters << "DATASTORE #{datastore_name} SECTION GROUP CTXSYS.AUTO_SECTION_GROUP"
|
30
|
+
end
|
31
|
+
if options[:tablespace]
|
32
|
+
storage_name = default_storage_name(index_name)
|
33
|
+
create_storage_preference(storage_name, options[:tablespace])
|
34
|
+
parameters << "STORAGE #{storage_name}"
|
35
|
+
end
|
36
|
+
if options[:sync]
|
37
|
+
parameters << "SYNC(#{options[:sync]})"
|
38
|
+
end
|
39
|
+
unless parameters.empty?
|
40
|
+
sql << " PARAMETERS ('#{parameters.join(' ')}')"
|
41
|
+
end
|
42
|
+
execute sql
|
43
|
+
end
|
44
|
+
|
45
|
+
# Drop full text index with CONTEXT index type
|
46
|
+
def remove_context_index(table_name, options = {})
|
47
|
+
self.all_schema_indexes = nil
|
48
|
+
unless Hash === options # if column names passed as argument
|
49
|
+
options = {:column => Array(options)}
|
50
|
+
end
|
51
|
+
index_name = options[:name] || index_name(table_name,
|
52
|
+
:column => options[:index_column] || options[:column], :identifier_max_length => 25)
|
53
|
+
execute "DROP INDEX #{index_name}"
|
54
|
+
drop_ctx_preference(default_datastore_name(index_name))
|
55
|
+
drop_ctx_preference(default_storage_name(index_name))
|
56
|
+
procedure_name = default_datastore_procedure(index_name)
|
57
|
+
execute "DROP PROCEDURE #{quote_table_name(procedure_name)}" rescue nil
|
58
|
+
drop_index_column_trigger(index_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def create_datastore_procedure(table_name, procedure_name, column_names, options)
|
64
|
+
quoted_table_name = quote_table_name(table_name)
|
65
|
+
select_queries = column_names.select{|c| c.to_s =~ /^SELECT /i}
|
66
|
+
column_names = column_names - select_queries
|
67
|
+
keys, selected_columns = parse_select_queries(select_queries)
|
68
|
+
quoted_column_names = (column_names+keys).map{|col| quote_column_name(col)}
|
69
|
+
execute compress_lines(<<-SQL)
|
70
|
+
CREATE OR REPLACE PROCEDURE #{quote_table_name(procedure_name)}
|
71
|
+
(p_rowid IN ROWID,
|
72
|
+
p_clob IN OUT NOCOPY CLOB) IS
|
73
|
+
-- add_context_index_parameters #{(column_names+select_queries).inspect}#{!options.empty? ? ', ' << options.inspect[1..-2] : ''}
|
74
|
+
#{
|
75
|
+
selected_columns.map do |cols|
|
76
|
+
cols.map do |col|
|
77
|
+
raise ArgumentError, "Alias #{col} too large, should be 28 or less characters long" unless col.length <= 28
|
78
|
+
"l_#{col} VARCHAR2(32767);\n"
|
79
|
+
end.join
|
80
|
+
end.join
|
81
|
+
} BEGIN
|
82
|
+
FOR r1 IN (
|
83
|
+
SELECT #{quoted_column_names.join(', ')}
|
84
|
+
FROM #{quoted_table_name}
|
85
|
+
WHERE #{quoted_table_name}.ROWID = p_rowid
|
86
|
+
) LOOP
|
87
|
+
#{
|
88
|
+
(column_names.map do |col|
|
89
|
+
col = col.to_s
|
90
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+2}, '<#{col}>');\n" <<
|
91
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, LENGTH(r1.#{col}), r1.#{col});\n" <<
|
92
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+3}, '</#{col}>');\n"
|
93
|
+
end.join) <<
|
94
|
+
(selected_columns.zip(select_queries).map do |cols, query|
|
95
|
+
(cols.map do |col|
|
96
|
+
"l_#{col} := '';\n"
|
97
|
+
end.join) <<
|
98
|
+
"FOR r2 IN (\n" <<
|
99
|
+
query.gsub(/:(\w+)/,"r1.\\1") << "\n) LOOP\n" <<
|
100
|
+
(cols.map do |col|
|
101
|
+
"l_#{col} := l_#{col} || r2.#{col} || CHR(10);\n"
|
102
|
+
end.join) <<
|
103
|
+
"END LOOP;\n" <<
|
104
|
+
(cols.map do |col|
|
105
|
+
col = col.to_s
|
106
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+2}, '<#{col}>');\n" <<
|
107
|
+
"IF LENGTH(l_#{col}) > 0 THEN\n" <<
|
108
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, LENGTH(l_#{col}), l_#{col});\n" <<
|
109
|
+
"END IF;\n" <<
|
110
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+3}, '</#{col}>');\n"
|
111
|
+
end.join)
|
112
|
+
end.join)
|
113
|
+
}
|
114
|
+
END LOOP;
|
115
|
+
END;
|
116
|
+
SQL
|
117
|
+
end
|
118
|
+
|
119
|
+
def parse_select_queries(select_queries)
|
120
|
+
keys = []
|
121
|
+
selected_columns = []
|
122
|
+
select_queries.each do |query|
|
123
|
+
# get primary or foreign keys like :id or :something_id
|
124
|
+
keys << (query.scan(/:\w+/).map{|k| k[1..-1].downcase.to_sym})
|
125
|
+
select_part = query.scan(/^select\s.*\sfrom/i).first
|
126
|
+
selected_columns << select_part.scan(/\sas\s+(\w+)/i).map{|c| c.first}
|
127
|
+
end
|
128
|
+
[keys.flatten.uniq, selected_columns]
|
129
|
+
end
|
130
|
+
|
131
|
+
def create_datastore_preference(datastore_name, procedure_name)
|
132
|
+
drop_ctx_preference(datastore_name)
|
133
|
+
execute <<-SQL
|
134
|
+
BEGIN
|
135
|
+
CTX_DDL.CREATE_PREFERENCE('#{datastore_name}', 'USER_DATASTORE');
|
136
|
+
CTX_DDL.SET_ATTRIBUTE('#{datastore_name}', 'PROCEDURE', '#{procedure_name}');
|
137
|
+
END;
|
138
|
+
SQL
|
139
|
+
end
|
140
|
+
|
141
|
+
def create_storage_preference(storage_name, tablespace)
|
142
|
+
drop_ctx_preference(storage_name)
|
143
|
+
sql = "BEGIN\nCTX_DDL.CREATE_PREFERENCE('#{storage_name}', 'BASIC_STORAGE');\n"
|
144
|
+
['I_TABLE_CLAUSE', 'K_TABLE_CLAUSE', 'R_TABLE_CLAUSE',
|
145
|
+
'N_TABLE_CLAUSE', 'I_INDEX_CLAUSE', 'P_TABLE_CLAUSE'].each do |clause|
|
146
|
+
sql << "CTX_DDL.SET_ATTRIBUTE('#{storage_name}', '#{clause}', 'TABLESPACE #{tablespace}');\n"
|
147
|
+
end
|
148
|
+
sql << "END;\n"
|
149
|
+
execute sql
|
150
|
+
end
|
151
|
+
|
152
|
+
def drop_ctx_preference(preference_name)
|
153
|
+
execute "BEGIN CTX_DDL.DROP_PREFERENCE('#{preference_name}'); END;" rescue nil
|
154
|
+
end
|
155
|
+
|
156
|
+
def create_index_column_trigger(table_name, index_name, index_column, index_column_source)
|
157
|
+
trigger_name = default_index_column_trigger_name(index_name)
|
158
|
+
columns = Array(index_column_source)
|
159
|
+
quoted_column_names = columns.map{|col| quote_column_name(col)}.join(', ')
|
160
|
+
execute compress_lines(<<-SQL)
|
161
|
+
CREATE OR REPLACE TRIGGER #{quote_table_name(trigger_name)}
|
162
|
+
BEFORE UPDATE OF #{quoted_column_names} ON #{quote_table_name(table_name)} FOR EACH ROW
|
163
|
+
BEGIN
|
164
|
+
:new.#{quote_column_name(index_column)} := '1';
|
165
|
+
END;
|
166
|
+
SQL
|
167
|
+
end
|
168
|
+
|
169
|
+
def drop_index_column_trigger(index_name)
|
170
|
+
trigger_name = default_index_column_trigger_name(index_name)
|
171
|
+
execute "DROP TRIGGER #{quote_table_name(trigger_name)}" rescue nil
|
172
|
+
end
|
173
|
+
|
174
|
+
def default_datastore_procedure(index_name)
|
175
|
+
"#{index_name}_prc"
|
176
|
+
end
|
177
|
+
|
178
|
+
def default_datastore_name(index_name)
|
179
|
+
"#{index_name}_dst"
|
180
|
+
end
|
181
|
+
|
182
|
+
def default_storage_name(index_name)
|
183
|
+
"#{index_name}_sto"
|
184
|
+
end
|
185
|
+
|
186
|
+
def default_index_column_trigger_name(index_name)
|
187
|
+
"#{index_name}_trg"
|
188
|
+
end
|
189
|
+
|
190
|
+
module BaseClassMethods
|
191
|
+
# Declare that model table has context index defined.
|
192
|
+
# As a result <tt>contains</tt> class scope method is defined.
|
193
|
+
def has_context_index
|
194
|
+
extend ContextIndexClassMethods
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
module ContextIndexClassMethods
|
199
|
+
# Add context index condition.
|
200
|
+
case ::ActiveRecord::VERSION::MAJOR
|
201
|
+
when 3
|
202
|
+
def contains(column, query, options ={})
|
203
|
+
score_label = options[:label].to_i || 1
|
204
|
+
where("CONTAINS(#{connection.quote_column_name(column)}, ?, #{score_label}) > 0", query).
|
205
|
+
order("SCORE(#{score_label}) DESC")
|
206
|
+
end
|
207
|
+
when 2
|
208
|
+
def contains(column, query, options ={})
|
209
|
+
score_label = options[:label].to_i || 1
|
210
|
+
scoped(:conditions => ["CONTAINS(#{connection.quote_column_name(column)}, ?, #{score_label}) > 0", query],
|
211
|
+
:order => "SCORE(#{score_label}) DESC")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
|
222
|
+
include ActiveRecord::ConnectionAdapters::OracleEnhancedContextIndex
|
223
|
+
end
|
224
|
+
|
225
|
+
ActiveRecord::Base.class_eval do
|
226
|
+
extend ActiveRecord::ConnectionAdapters::OracleEnhancedContextIndex::BaseClassMethods
|
227
|
+
end
|
@@ -53,7 +53,7 @@ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' && RUBY_VERSION >= '1.9'
|
|
53
53
|
|
54
54
|
rescue LoadError
|
55
55
|
warning_message = "WARNING: Please install unicode_utils gem to support Unicode aware upcase and downcase for String#mb_chars"
|
56
|
-
if !
|
56
|
+
if !Rails.logger.nil?
|
57
57
|
Rails.logger.warn warning_message
|
58
58
|
else
|
59
59
|
STDERR.puts warning_message
|
@@ -32,7 +32,7 @@ module ActiveRecord #:nodoc:
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
if ActiveRecord::Base.
|
35
|
+
if ActiveRecord::Base.method_defined?(:changed?)
|
36
36
|
ActiveRecord::Base.class_eval do
|
37
37
|
include ActiveRecord::ConnectionAdapters::OracleEnhancedDirty::InstanceMethods
|
38
38
|
end
|
@@ -154,7 +154,7 @@ module ActiveRecord
|
|
154
154
|
@active = true
|
155
155
|
rescue NativeException => e
|
156
156
|
@active = false
|
157
|
-
if e.message =~ /^java\.sql\.
|
157
|
+
if e.message =~ /^java\.sql\.SQL(Recoverable)?Exception/
|
158
158
|
raise OracleEnhancedConnectionException, e.message
|
159
159
|
else
|
160
160
|
raise
|
@@ -169,7 +169,7 @@ module ActiveRecord
|
|
169
169
|
@active = true
|
170
170
|
rescue NativeException => e
|
171
171
|
@active = false
|
172
|
-
if e.message =~ /^java\.sql\.
|
172
|
+
if e.message =~ /^java\.sql\.SQL(Recoverable)?Exception/
|
173
173
|
raise OracleEnhancedConnectionException, e.message
|
174
174
|
else
|
175
175
|
raise
|
@@ -183,7 +183,7 @@ module ActiveRecord
|
|
183
183
|
begin
|
184
184
|
yield if block_given?
|
185
185
|
rescue NativeException => e
|
186
|
-
raise unless e.message =~ /^java\.sql\.
|
186
|
+
raise unless e.message =~ /^java\.sql\.SQL(Recoverable)?Exception: (Closed Connection|Io exception:|No more data to read from socket)/
|
187
187
|
@active = false
|
188
188
|
raise unless should_retry
|
189
189
|
should_retry = false
|
@@ -112,7 +112,7 @@ module ActiveRecord #:nodoc:
|
|
112
112
|
# check if class has custom create method
|
113
113
|
return create_without_custom_method unless self.class.custom_create_method
|
114
114
|
self.class.connection.log_custom_method("custom create method", "#{self.class.name} Create") do
|
115
|
-
self.id = self.class.custom_create_method
|
115
|
+
self.id = instance_eval &self.class.custom_create_method
|
116
116
|
end
|
117
117
|
@new_record = false
|
118
118
|
id
|
@@ -125,7 +125,7 @@ module ActiveRecord #:nodoc:
|
|
125
125
|
return update_without_custom_method unless self.class.custom_update_method
|
126
126
|
return 0 if attribute_names.empty?
|
127
127
|
self.class.connection.log_custom_method("custom update method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Update") do
|
128
|
-
self.class.custom_update_method
|
128
|
+
instance_eval &self.class.custom_update_method
|
129
129
|
end
|
130
130
|
1
|
131
131
|
end
|
@@ -138,7 +138,7 @@ module ActiveRecord #:nodoc:
|
|
138
138
|
return destroy_without_custom_method unless self.class.custom_delete_method
|
139
139
|
unless new_record?
|
140
140
|
self.class.connection.log_custom_method("custom delete method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Destroy") do
|
141
|
-
self.class.custom_delete_method
|
141
|
+
instance_eval &self.class.custom_delete_method
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -6,7 +6,8 @@ module ActiveRecord
|
|
6
6
|
class OracleEnhancedSynonymDefinition < Struct.new(:name, :table_owner, :table_name, :db_link) #:nodoc:
|
7
7
|
end
|
8
8
|
|
9
|
-
class OracleEnhancedIndexDefinition < Struct.new(:table, :name, :unique, :
|
9
|
+
class OracleEnhancedIndexDefinition < Struct.new(:table, :name, :unique, :type, :parameters, :statement_parameters,
|
10
|
+
:tablespace, :columns) #:nodoc:
|
10
11
|
end
|
11
12
|
|
12
13
|
module OracleEnhancedSchemaDefinitions #:nodoc:
|
@@ -13,7 +13,8 @@ module ActiveRecord #:nodoc:
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def tables_with_oracle_enhanced(stream)
|
16
|
-
|
16
|
+
# do not include materialized views in schema dump - they should be created separately after schema creation
|
17
|
+
sorted_tables = (@connection.tables - @connection.materialized_views).sort
|
17
18
|
sorted_tables.each do |tbl|
|
18
19
|
# add table prefix or suffix for schema_migrations
|
19
20
|
next if [ActiveRecord::Migrator.proper_table_name('schema_migrations'), ignore_tables].flatten.any? do |ignored|
|
@@ -89,14 +90,28 @@ module ActiveRecord #:nodoc:
|
|
89
90
|
def indexes_with_oracle_enhanced(table, stream)
|
90
91
|
if (indexes = @connection.indexes(table)).any?
|
91
92
|
add_index_statements = indexes.map do |index|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
93
|
+
case index.type
|
94
|
+
when nil
|
95
|
+
# use table.inspect as it will remove prefix and suffix
|
96
|
+
statement_parts = [ ('add_index ' + table.inspect) ]
|
97
|
+
statement_parts << index.columns.inspect
|
98
|
+
statement_parts << (':name => ' + index.name.inspect)
|
99
|
+
statement_parts << ':unique => true' if index.unique
|
100
|
+
statement_parts << ':tablespace => ' + index.tablespace.inspect if index.tablespace
|
101
|
+
when 'CTXSYS.CONTEXT'
|
102
|
+
if index.statement_parameters
|
103
|
+
statement_parts = [ ('add_context_index ' + table.inspect) ]
|
104
|
+
statement_parts << index.statement_parameters
|
105
|
+
else
|
106
|
+
statement_parts = [ ('add_context_index ' + table.inspect) ]
|
107
|
+
statement_parts << index.columns.inspect
|
108
|
+
statement_parts << (':name => ' + index.name.inspect)
|
109
|
+
end
|
110
|
+
else
|
111
|
+
# unrecognized index type
|
112
|
+
statement_parts = ["# unrecognized index #{index.name.inspect} with type #{index.type.inspect}"]
|
113
|
+
end
|
114
|
+
' ' + statement_parts.join(', ')
|
100
115
|
end
|
101
116
|
|
102
117
|
stream.puts add_index_statements.sort.join("\n")
|
@@ -1 +1 @@
|
|
1
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::VERSION =
|
1
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::VERSION = File.read(File.dirname(__FILE__)+'/../../../VERSION').chomp
|
data/oracle_enhanced.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{oracle_enhanced}
|
8
|
-
s.version = "1.3.0.
|
8
|
+
s.version = "1.3.0.pre2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Raimonds Simanovskis"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-18}
|
13
13
|
s.description = %q{Oracle "enhanced" ActiveRecord adapter contains useful additional methods for working with new and legacy Oracle databases.
|
14
14
|
This adapter is superset of original ActiveRecord Oracle adapter.
|
15
15
|
}
|
@@ -29,6 +29,7 @@ This adapter is superset of original ActiveRecord Oracle adapter.
|
|
29
29
|
"lib/active_record/connection_adapters/oracle_enhanced.rake",
|
30
30
|
"lib/active_record/connection_adapters/oracle_enhanced_adapter.rb",
|
31
31
|
"lib/active_record/connection_adapters/oracle_enhanced_connection.rb",
|
32
|
+
"lib/active_record/connection_adapters/oracle_enhanced_context_index.rb",
|
32
33
|
"lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb",
|
33
34
|
"lib/active_record/connection_adapters/oracle_enhanced_cpk.rb",
|
34
35
|
"lib/active_record/connection_adapters/oracle_enhanced_dirty.rb",
|
@@ -41,11 +42,12 @@ This adapter is superset of original ActiveRecord Oracle adapter.
|
|
41
42
|
"lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb",
|
42
43
|
"lib/active_record/connection_adapters/oracle_enhanced_tasks.rb",
|
43
44
|
"lib/active_record/connection_adapters/oracle_enhanced_version.rb",
|
44
|
-
"lib/oracle_enhanced.rb",
|
45
|
+
"lib/active_record/oracle_enhanced.rb",
|
45
46
|
"oracle_enhanced.gemspec",
|
46
47
|
"spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb",
|
47
48
|
"spec/active_record/connection_adapters/oracle_enhanced_adapter_structure_dumper_spec.rb",
|
48
49
|
"spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb",
|
50
|
+
"spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb",
|
49
51
|
"spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb",
|
50
52
|
"spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb",
|
51
53
|
"spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb",
|
@@ -58,7 +60,7 @@ This adapter is superset of original ActiveRecord Oracle adapter.
|
|
58
60
|
"spec/spec.opts",
|
59
61
|
"spec/spec_helper.rb"
|
60
62
|
]
|
61
|
-
s.homepage = %q{http://github.com/
|
63
|
+
s.homepage = %q{http://github.com/plukevdh/oracle-enhanced}
|
62
64
|
s.rdoc_options = ["--charset=UTF-8"]
|
63
65
|
s.require_paths = ["lib"]
|
64
66
|
s.rubygems_version = %q{1.3.6}
|
@@ -67,6 +69,7 @@ This adapter is superset of original ActiveRecord Oracle adapter.
|
|
67
69
|
"spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb",
|
68
70
|
"spec/active_record/connection_adapters/oracle_enhanced_adapter_structure_dumper_spec.rb",
|
69
71
|
"spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb",
|
72
|
+
"spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb",
|
70
73
|
"spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb",
|
71
74
|
"spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb",
|
72
75
|
"spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb",
|
@@ -112,7 +112,7 @@ describe "OracleEnhancedAdapter" do
|
|
112
112
|
before(:all) do
|
113
113
|
@conn.execute <<-SQL
|
114
114
|
CREATE TABLE test_employees (
|
115
|
-
id NUMBER,
|
115
|
+
id NUMBER PRIMARY KEY,
|
116
116
|
first_name VARCHAR2(20),
|
117
117
|
last_name VARCHAR2(25),
|
118
118
|
email VARCHAR2(25),
|
@@ -180,7 +180,7 @@ describe "OracleEnhancedAdapter" do
|
|
180
180
|
@conn.execute "DROP TABLE test_employees" rescue nil
|
181
181
|
@conn.execute <<-SQL
|
182
182
|
CREATE TABLE test_employees (
|
183
|
-
id NUMBER,
|
183
|
+
id NUMBER PRIMARY KEY,
|
184
184
|
first_name VARCHAR2(20),
|
185
185
|
last_name VARCHAR2(25),
|
186
186
|
hire_date DATE
|
@@ -198,12 +198,15 @@ describe "OracleEnhancedAdapter" do
|
|
198
198
|
end
|
199
199
|
|
200
200
|
before(:each) do
|
201
|
-
|
202
|
-
log_to @buffer
|
201
|
+
set_logger
|
203
202
|
@conn = ActiveRecord::Base.connection
|
204
203
|
@conn.clear_columns_cache
|
205
204
|
end
|
206
205
|
|
206
|
+
after(:each) do
|
207
|
+
clear_logger
|
208
|
+
end
|
209
|
+
|
207
210
|
describe "without column caching" do
|
208
211
|
|
209
212
|
before(:each) do
|
@@ -212,14 +215,26 @@ describe "OracleEnhancedAdapter" do
|
|
212
215
|
|
213
216
|
it "should get columns from database at first time" do
|
214
217
|
TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
|
215
|
-
@
|
218
|
+
@logger.logged(:debug).last.should =~ /select .* from all_tab_columns/im
|
216
219
|
end
|
217
220
|
|
218
221
|
it "should get columns from database at second time" do
|
219
222
|
TestEmployee.connection.columns('test_employees')
|
220
|
-
@
|
223
|
+
@logger.clear(:debug)
|
221
224
|
TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
|
222
|
-
@
|
225
|
+
@logger.logged(:debug).last.should =~ /select .* from all_tab_columns/im
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should get primary key from database at first time" do
|
229
|
+
TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
|
230
|
+
@logger.logged(:debug).last.should =~ /select .* from all_constraints/im
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should get primary key from database at first time" do
|
234
|
+
TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
|
235
|
+
@logger.clear(:debug)
|
236
|
+
TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
|
237
|
+
@logger.logged(:debug).last.should =~ /select .* from all_constraints/im
|
223
238
|
end
|
224
239
|
|
225
240
|
end
|
@@ -232,14 +247,26 @@ describe "OracleEnhancedAdapter" do
|
|
232
247
|
|
233
248
|
it "should get columns from database at first time" do
|
234
249
|
TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
|
235
|
-
@
|
250
|
+
@logger.logged(:debug).last.should =~ /select .* from all_tab_columns/im
|
236
251
|
end
|
237
252
|
|
238
253
|
it "should get columns from cache at second time" do
|
239
254
|
TestEmployee.connection.columns('test_employees')
|
240
|
-
@
|
255
|
+
@logger.clear(:debug)
|
241
256
|
TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
|
242
|
-
@
|
257
|
+
@logger.logged(:debug).last.should be_blank
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should get primary key from database at first time" do
|
261
|
+
TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
|
262
|
+
@logger.logged(:debug).last.should =~ /select .* from all_constraints/im
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should get primary key from cache at first time" do
|
266
|
+
TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
|
267
|
+
@logger.clear(:debug)
|
268
|
+
TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
|
269
|
+
@logger.logged(:debug).last.should be_blank
|
243
270
|
end
|
244
271
|
|
245
272
|
end
|
data/spec/active_record/connection_adapters/oracle_enhanced_adapter_structure_dumper_spec.rb
CHANGED
@@ -58,7 +58,7 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
58
58
|
SQL
|
59
59
|
dump = ActiveRecord::Base.connection.structure_dump_fk_constraints
|
60
60
|
dump.split('\n').length.should == 1
|
61
|
-
dump.should =~ /ALTER TABLE TEST_POSTS ADD CONSTRAINT
|
61
|
+
dump.should =~ /ALTER TABLE \"?TEST_POSTS\"? ADD CONSTRAINT \"?FK_TEST_POST_FOO\"? FOREIGN KEY \(\"?FOO_ID\"?\) REFERENCES \"?FOOS\"?\(\"?ID\"?\)/i
|
62
62
|
end
|
63
63
|
|
64
64
|
it "should not error when no foreign keys are present" do
|
@@ -78,7 +78,7 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
78
78
|
END;
|
79
79
|
SQL
|
80
80
|
dump = ActiveRecord::Base.connection.structure_dump_db_stored_code.gsub(/\n|\s+/,' ')
|
81
|
-
dump.should =~ /
|
81
|
+
dump.should =~ /CREATE OR REPLACE TRIGGER TEST_POST_TRIGGER/
|
82
82
|
end
|
83
83
|
|
84
84
|
it "should dump types" do
|
@@ -86,7 +86,7 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
86
86
|
create or replace TYPE TEST_TYPE AS TABLE OF VARCHAR2(10);
|
87
87
|
SQL
|
88
88
|
dump = ActiveRecord::Base.connection.structure_dump_db_stored_code.gsub(/\n|\s+/,' ')
|
89
|
-
dump.should =~ /
|
89
|
+
dump.should =~ /CREATE OR REPLACE TYPE TEST_TYPE/
|
90
90
|
end
|
91
91
|
|
92
92
|
it "should dump virtual columns" do
|
@@ -99,7 +99,7 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
99
99
|
)
|
100
100
|
SQL
|
101
101
|
dump = ActiveRecord::Base.connection.structure_dump
|
102
|
-
dump.should =~ /
|
102
|
+
dump.should =~ /ID_PLUS NUMBER GENERATED ALWAYS AS \(ID\+2\) VIRTUAL/
|
103
103
|
end
|
104
104
|
|
105
105
|
it "should dump unique keys" do
|
@@ -124,9 +124,9 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
124
124
|
SQL
|
125
125
|
|
126
126
|
dump = ActiveRecord::Base.connection.structure_dump
|
127
|
-
dump.should =~ /
|
128
|
-
dump.should =~ /
|
129
|
-
dump.should_not =~ /
|
127
|
+
dump.should =~ /CREATE UNIQUE INDEX "?IX_TEST_POSTS_FOO_ID"? ON "?TEST_POSTS"? \("?FOO_ID"?\)/i
|
128
|
+
dump.should =~ /CREATE INDEX "?IX_TEST_POSTS_FOO\"? ON "?TEST_POSTS"? \("?FOO"?\)/i
|
129
|
+
dump.should_not =~ /CREATE UNIQUE INDEX "?UK_TEST_POSTS_/i
|
130
130
|
end
|
131
131
|
end
|
132
132
|
describe "temporary tables" do
|
@@ -138,7 +138,7 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
138
138
|
t.integer :post_id
|
139
139
|
end
|
140
140
|
dump = ActiveRecord::Base.connection.structure_dump
|
141
|
-
dump.should =~ /
|
141
|
+
dump.should =~ /CREATE GLOBAL TEMPORARY TABLE "?TEST_COMMENTS"?/i
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -173,8 +173,8 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
173
173
|
end
|
174
174
|
it "should dump drop sql for just temp tables" do
|
175
175
|
dump = @conn.temp_table_drop
|
176
|
-
dump.should =~ /
|
177
|
-
dump.should_not =~ /
|
176
|
+
dump.should =~ /DROP TABLE "TEMP_TBL"/
|
177
|
+
dump.should_not =~ /DROP TABLE "?NOT_TEMP_TBL"?/i
|
178
178
|
end
|
179
179
|
after(:each) do
|
180
180
|
@conn.drop_table :temp_tbl
|
@@ -194,6 +194,10 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
194
194
|
@conn.execute <<-SQL
|
195
195
|
create or replace view full_drop_test_view (foo) as select id as "foo" from full_drop_test
|
196
196
|
SQL
|
197
|
+
#materialized view
|
198
|
+
@conn.execute <<-SQL
|
199
|
+
create materialized view full_drop_test_mview (foo) as select id as "foo" from full_drop_test
|
200
|
+
SQL
|
197
201
|
#package
|
198
202
|
@conn.execute <<-SQL
|
199
203
|
create or replace package full_drop_test_package as
|
@@ -241,6 +245,7 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
241
245
|
@conn.drop_table :full_drop_test
|
242
246
|
@conn.drop_table :full_drop_test_temp
|
243
247
|
@conn.execute "DROP VIEW FULL_DROP_TEST_VIEW" rescue nil
|
248
|
+
@conn.execute "DROP MATERIALIZED VIEW FULL_DROP_TEST_MVIEW" rescue nil
|
244
249
|
@conn.execute "DROP SYNONYM FULL_DROP_TEST_SYNONYM" rescue nil
|
245
250
|
@conn.execute "DROP PACKAGE FULL_DROP_TEST_PACKAGE" rescue nil
|
246
251
|
@conn.execute "DROP FUNCTION FULL_DROP_TEST_FUNCTION" rescue nil
|
@@ -249,19 +254,21 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
249
254
|
end
|
250
255
|
it "should contain correct sql" do
|
251
256
|
drop = @conn.full_drop
|
252
|
-
drop.should =~ /
|
253
|
-
drop.should =~ /
|
254
|
-
drop.should =~ /
|
255
|
-
drop.
|
256
|
-
drop.should =~ /
|
257
|
-
drop.should =~ /
|
258
|
-
drop.should =~ /
|
259
|
-
drop.should =~ /
|
257
|
+
drop.should =~ /DROP TABLE "FULL_DROP_TEST" CASCADE CONSTRAINTS/
|
258
|
+
drop.should =~ /DROP SEQUENCE "FULL_DROP_TEST_SEQ"/
|
259
|
+
drop.should =~ /DROP VIEW "FULL_DROP_TEST_VIEW"/
|
260
|
+
drop.should_not =~ /DROP TABLE "?FULL_DROP_TEST_MVIEW"?/i
|
261
|
+
drop.should =~ /DROP MATERIALIZED VIEW "FULL_DROP_TEST_MVIEW"/
|
262
|
+
drop.should =~ /DROP PACKAGE "FULL_DROP_TEST_PACKAGE"/
|
263
|
+
drop.should =~ /DROP FUNCTION "FULL_DROP_TEST_FUNCTION"/
|
264
|
+
drop.should =~ /DROP PROCEDURE "FULL_DROP_TEST_PROCEDURE"/
|
265
|
+
drop.should =~ /DROP SYNONYM "FULL_DROP_TEST_SYNONYM"/
|
266
|
+
drop.should =~ /DROP TYPE "FULL_DROP_TEST_TYPE"/
|
260
267
|
end
|
261
268
|
it "should not drop tables when preserve_tables is true" do
|
262
269
|
drop = @conn.full_drop(true)
|
263
|
-
drop.should =~ /
|
264
|
-
drop.should_not =~ /
|
270
|
+
drop.should =~ /DROP TABLE "FULL_DROP_TEST_TEMP"/
|
271
|
+
drop.should_not =~ /DROP TABLE "?FULL_DROP_TEST"? CASCADE CONSTRAINTS/i
|
265
272
|
end
|
266
273
|
end
|
267
274
|
end
|