activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.0.beta1
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.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/Gemfile +20 -11
- data/History.md +123 -4
- data/RUNNING_TESTS.md +79 -55
- data/Rakefile +13 -19
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +16 -17
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +7 -59
- data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +6 -50
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +11 -11
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +117 -117
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +30 -23
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +48 -70
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +51 -69
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +4 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +76 -76
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +13 -42
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +60 -64
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +33 -47
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +146 -159
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +94 -132
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +65 -100
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +250 -487
- data/lib/active_record/oracle_enhanced/type/boolean.rb +7 -10
- data/lib/active_record/oracle_enhanced/type/integer.rb +3 -4
- data/lib/active_record/oracle_enhanced/type/national_character_string.rb +1 -1
- data/lib/active_record/oracle_enhanced/type/raw.rb +2 -3
- data/lib/active_record/oracle_enhanced/type/string.rb +2 -2
- data/lib/active_record/oracle_enhanced/type/text.rb +2 -2
- data/lib/activerecord-oracle_enhanced-adapter.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +57 -131
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +32 -34
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -42
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +83 -85
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +205 -286
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +14 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +3 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +42 -49
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +68 -71
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +51 -92
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +221 -327
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +16 -18
- data/spec/spec_helper.rb +59 -57
- metadata +10 -10
@@ -4,7 +4,6 @@ module ActiveRecord
|
|
4
4
|
attr_reader :table_name, :nchar, :virtual_column_data_default, :returning_id #:nodoc:
|
5
5
|
|
6
6
|
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, virtual = false, returning_id = nil, comment = nil) #:nodoc:
|
7
|
-
|
8
7
|
@virtual = virtual
|
9
8
|
@virtual_column_data_default = default.inspect if virtual
|
10
9
|
@returning_id = returning_id
|
@@ -17,7 +16,7 @@ module ActiveRecord
|
|
17
16
|
# Is column NCHAR or NVARCHAR2 (will need to use N'...' value quoting for these data types)?
|
18
17
|
# Define only when needed as adapter "quote" method will check at first if instance variable is defined.
|
19
18
|
if sql_type_metadata
|
20
|
-
@object_type = sql_type_metadata.sql_type.include?
|
19
|
+
@object_type = sql_type_metadata.sql_type.include? "."
|
21
20
|
end
|
22
21
|
# TODO: Need to investigate when `sql_type` becomes nil
|
23
22
|
end
|
@@ -62,72 +61,21 @@ module ActiveRecord
|
|
62
61
|
super
|
63
62
|
end
|
64
63
|
|
65
|
-
# Get column comment from schema definition.
|
66
|
-
# Will work only if using default ActiveRecord connection.
|
67
|
-
# def comment
|
68
|
-
# #TODO: may be deprecated due to conflict with variable
|
69
|
-
# ActiveRecord::Base.connection.column_comment(@table_name, name)
|
70
|
-
# end
|
71
|
-
|
72
64
|
private
|
73
65
|
|
74
|
-
|
75
|
-
|
66
|
+
def self.extract_value_from_default(default)
|
67
|
+
case default
|
76
68
|
when String
|
77
69
|
default.gsub(/''/, "'")
|
78
|
-
|
70
|
+
else
|
79
71
|
default
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def guess_date_or_time(value)
|
84
|
-
value.respond_to?(:hour) && (value.hour == 0 and value.min == 0 and value.sec == 0) ?
|
85
|
-
Date.new(value.year, value.month, value.day) : value
|
86
|
-
end
|
87
|
-
|
88
|
-
class << self
|
89
|
-
protected
|
90
|
-
|
91
|
-
def fallback_string_to_date(string) #:nodoc:
|
92
|
-
if OracleEnhancedAdapter.string_to_date_format || OracleEnhancedAdapter.string_to_time_format
|
93
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
94
|
-
`fallback_string_to_date` has been deprecated.
|
95
|
-
It will be removed from next version of Oracle enhanced adapter.
|
96
|
-
Users are unlikely to see this message since this method has gone
|
97
|
-
from ActiveRecord::ConnectionAdapters::Column in Rails 4.2.
|
98
|
-
MSG
|
99
|
-
return (string_to_date_or_time_using_format(string).to_date rescue super)
|
100
|
-
end
|
101
|
-
super
|
102
|
-
end
|
103
|
-
|
104
|
-
def fallback_string_to_time(string) #:nodoc:
|
105
|
-
if OracleEnhancedAdapter.string_to_time_format || OracleEnhancedAdapter.string_to_date_format
|
106
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
107
|
-
`fallback_string_to_time` has been deprecated.
|
108
|
-
It will be removed from next version of Oracle enhanced adapter.
|
109
|
-
Users are unlikely to see this message since this method has gone
|
110
|
-
from ActiveRecord::ConnectionAdapters::Column in Rails 4.2.
|
111
|
-
MSG
|
112
|
-
return (string_to_date_or_time_using_format(string).to_time rescue super)
|
113
72
|
end
|
114
|
-
super
|
115
73
|
end
|
116
74
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
It will be removed from next version of Oracle enhanced adapter.
|
121
|
-
Users are unlikely to see this message since `fallback_string_to_date`
|
122
|
-
and `fallback_string_to_time` have gone
|
123
|
-
from ActiveRecord::ConnectionAdapters::Column in Rails 4.2.
|
124
|
-
MSG
|
125
|
-
if OracleEnhancedAdapter.string_to_time_format && dt=Date._strptime(string, OracleEnhancedAdapter.string_to_time_format)
|
126
|
-
return Time.parse("#{dt[:year]}-#{dt[:mon]}-#{dt[:mday]} #{dt[:hour]}:#{dt[:min]}:#{dt[:sec]}#{dt[:zone]}")
|
127
|
-
end
|
128
|
-
DateTime.strptime(string, OracleEnhancedAdapter.string_to_date_format).to_date
|
75
|
+
def guess_date_or_time(value)
|
76
|
+
value.respond_to?(:hour) && ((value.hour == 0) && (value.min == 0) && (value.sec == 0)) ?
|
77
|
+
Date.new(value.year, value.month, value.day) : value
|
129
78
|
end
|
130
|
-
end
|
131
79
|
end
|
132
80
|
end
|
133
81
|
end
|
@@ -2,66 +2,22 @@ module ActiveRecord #:nodoc:
|
|
2
2
|
module ConnectionAdapters #:nodoc:
|
3
3
|
module OracleEnhanced #:nodoc:
|
4
4
|
module ColumnDumper #:nodoc:
|
5
|
-
def column_spec(column)
|
6
|
-
spec = Hash[prepare_column_options(column).map { |k, v| [k, "#{k}: #{v}"] }]
|
7
|
-
spec[:name] = column.name.inspect
|
8
|
-
if column.virtual?
|
9
|
-
spec[:type] = "virtual"
|
10
|
-
else
|
11
|
-
spec[:type] = schema_type(column).to_s
|
12
|
-
end
|
13
|
-
spec
|
14
|
-
end
|
15
|
-
|
16
5
|
def prepare_column_options(column)
|
17
|
-
spec =
|
18
|
-
|
19
|
-
if limit = schema_limit(column)
|
20
|
-
spec[:limit] = limit
|
21
|
-
end
|
22
|
-
|
23
|
-
if precision = schema_precision(column)
|
24
|
-
spec[:precision] = precision
|
25
|
-
end
|
26
|
-
|
27
|
-
if scale = schema_scale(column)
|
28
|
-
spec[:scale] = scale
|
29
|
-
end
|
6
|
+
spec = super
|
30
7
|
|
31
|
-
if
|
32
|
-
spec[:as] =
|
8
|
+
if supports_virtual_columns? && column.virtual?
|
9
|
+
spec[:as] = column.virtual_column_data_default
|
10
|
+
spec = { type: schema_type(column).inspect }.merge!(spec) unless column.type == :decimal
|
33
11
|
end
|
34
12
|
|
35
|
-
if virtual_type = schema_virtual_type(column)
|
36
|
-
spec[:virtual_type] = virtual_type
|
37
|
-
end
|
38
|
-
|
39
|
-
default = schema_default(column) if column.has_default?
|
40
|
-
spec[:default] = default unless default.nil?
|
41
|
-
|
42
|
-
spec[:null] = 'false' unless column.null
|
43
|
-
|
44
|
-
spec[:comment] = column.comment.inspect if column.comment.present?
|
45
|
-
|
46
13
|
spec
|
47
14
|
end
|
48
15
|
|
49
|
-
def migration_keys
|
50
|
-
# TODO `& column_specs.map(&:keys).flatten` should be exetuted here
|
51
|
-
[:name, :limit, :precision, :scale, :default, :null, :as, :virtual_type, :comment]
|
52
|
-
end
|
53
|
-
|
54
16
|
private
|
55
17
|
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
def schema_virtual_type(column)
|
61
|
-
unless column.type == :decimal
|
62
|
-
column.type.inspect if column.virtual?
|
18
|
+
def default_primary_key?(column)
|
19
|
+
schema_type(column) == :integer
|
63
20
|
end
|
64
|
-
end
|
65
21
|
end
|
66
22
|
end
|
67
23
|
end
|
@@ -29,8 +29,8 @@ module ActiveRecord
|
|
29
29
|
# Used always by JDBC connection as well by OCI connection when describing tables over database link
|
30
30
|
def describe(name)
|
31
31
|
name = name.to_s
|
32
|
-
if name.include?(
|
33
|
-
name, db_link = name.split(
|
32
|
+
if name.include?("@")
|
33
|
+
name, db_link = name.split("@")
|
34
34
|
default_owner = select_value("SELECT username FROM all_db_links WHERE db_link = '#{db_link.upcase}'")
|
35
35
|
db_link = "@#{db_link}"
|
36
36
|
else
|
@@ -38,8 +38,8 @@ module ActiveRecord
|
|
38
38
|
default_owner = @owner
|
39
39
|
end
|
40
40
|
real_name = ActiveRecord::ConnectionAdapters::OracleEnhanced::Quoting.valid_table_name?(name) ? name.upcase : name
|
41
|
-
if real_name.include?(
|
42
|
-
table_owner, table_name = real_name.split(
|
41
|
+
if real_name.include?(".")
|
42
|
+
table_owner, table_name = real_name.split(".")
|
43
43
|
else
|
44
44
|
table_owner, table_name = default_owner, real_name
|
45
45
|
end
|
@@ -65,11 +65,11 @@ module ActiveRecord
|
|
65
65
|
AND synonym_name = '#{real_name}'
|
66
66
|
SQL
|
67
67
|
if result = select_one(sql)
|
68
|
-
case result[
|
69
|
-
when
|
68
|
+
case result["name_type"]
|
69
|
+
when "SYNONYM"
|
70
70
|
describe("#{result['owner'] && "#{result['owner']}."}#{result['table_name']}#{db_link}")
|
71
71
|
else
|
72
|
-
db_link ? [result[
|
72
|
+
db_link ? [result["owner"], result["table_name"], db_link] : [result["owner"], result["table_name"]]
|
73
73
|
end
|
74
74
|
else
|
75
75
|
raise OracleEnhancedConnectionException, %Q{"DESC #{name}" failed; does it exist?}
|
@@ -109,13 +109,13 @@ module ActiveRecord
|
|
109
109
|
end
|
110
110
|
|
111
111
|
# if MRI or YARV
|
112
|
-
if !defined?(RUBY_ENGINE) || RUBY_ENGINE ==
|
112
|
+
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
|
113
113
|
ORACLE_ENHANCED_CONNECTION = :oci
|
114
|
-
require
|
114
|
+
require "active_record/connection_adapters/oracle_enhanced/oci_connection"
|
115
115
|
# if JRuby
|
116
|
-
elsif RUBY_ENGINE ==
|
116
|
+
elsif RUBY_ENGINE == "jruby"
|
117
117
|
ORACLE_ENHANCED_CONNECTION = :jdbc
|
118
|
-
require
|
118
|
+
require "active_record/connection_adapters/oracle_enhanced/jdbc_connection"
|
119
119
|
else
|
120
120
|
raise "Unsupported Ruby engine #{RUBY_ENGINE}"
|
121
121
|
end
|
@@ -74,9 +74,9 @@ module ActiveRecord
|
|
74
74
|
def add_context_index(table_name, column_name, options = {})
|
75
75
|
self.all_schema_indexes = nil
|
76
76
|
column_names = Array(column_name)
|
77
|
-
index_name = options[:name] || index_name(table_name, :
|
77
|
+
index_name = options[:name] || index_name(table_name, column: options[:index_column] || column_names,
|
78
78
|
# CONEXT index name max length is 25
|
79
|
-
:
|
79
|
+
identifier_max_length: 25)
|
80
80
|
|
81
81
|
quoted_column_name = quote_column_name(options[:index_column] || column_names.first)
|
82
82
|
if options[:index_column_trigger_on]
|
@@ -129,10 +129,10 @@ module ActiveRecord
|
|
129
129
|
def remove_context_index(table_name, options = {})
|
130
130
|
self.all_schema_indexes = nil
|
131
131
|
unless Hash === options # if column names passed as argument
|
132
|
-
options = {:
|
132
|
+
options = { column: Array(options) }
|
133
133
|
end
|
134
134
|
index_name = options[:name] || index_name(table_name,
|
135
|
-
:
|
135
|
+
column: options[:index_column] || options[:column], identifier_max_length: 25)
|
136
136
|
execute "DROP INDEX #{index_name}"
|
137
137
|
drop_ctx_preference(default_datastore_name(index_name))
|
138
138
|
drop_ctx_preference(default_storage_name(index_name))
|
@@ -143,17 +143,17 @@ module ActiveRecord
|
|
143
143
|
|
144
144
|
private
|
145
145
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
146
|
+
def create_datastore_procedure(table_name, procedure_name, column_names, options)
|
147
|
+
quoted_table_name = quote_table_name(table_name)
|
148
|
+
select_queries, column_names = column_names.partition { |c| c.to_s =~ /^\s*SELECT\s+/i }
|
149
|
+
select_queries = select_queries.map { |s| s.strip.gsub(/\s+/, " ") }
|
150
|
+
keys, selected_columns = parse_select_queries(select_queries)
|
151
|
+
quoted_column_names = (column_names + keys).map { |col| quote_column_name(col) }
|
152
|
+
execute compress_lines(<<-SQL)
|
153
153
|
CREATE OR REPLACE PROCEDURE #{quote_table_name(procedure_name)}
|
154
154
|
(p_rowid IN ROWID,
|
155
155
|
p_clob IN OUT NOCOPY CLOB) IS
|
156
|
-
-- add_context_index_parameters #{(column_names+select_queries).inspect}#{!options.empty? ? ', ' << options.inspect[1..-2] : ''}
|
156
|
+
-- add_context_index_parameters #{(column_names + select_queries).inspect}#{!options.empty? ? ', ' << options.inspect[1..-2] : ''}
|
157
157
|
#{
|
158
158
|
selected_columns.map do |cols|
|
159
159
|
cols.map do |col|
|
@@ -170,171 +170,171 @@ module ActiveRecord
|
|
170
170
|
#{
|
171
171
|
(column_names.map do |col|
|
172
172
|
col = col.to_s
|
173
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+2}, '<#{col}>');\n" <<
|
173
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length + 2}, '<#{col}>');\n" <<
|
174
174
|
"IF LENGTH(r1.#{col}) > 0 THEN\n" <<
|
175
175
|
"DBMS_LOB.WRITEAPPEND(p_clob, LENGTH(r1.#{col}), r1.#{col});\n" <<
|
176
176
|
"END IF;\n" <<
|
177
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+3}, '</#{col}>');\n"
|
177
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length + 3}, '</#{col}>');\n"
|
178
178
|
end.join) <<
|
179
179
|
(selected_columns.zip(select_queries).map do |cols, query|
|
180
180
|
(cols.map do |col|
|
181
181
|
"l_#{col} := '';\n"
|
182
182
|
end.join) <<
|
183
183
|
"FOR r2 IN (\n" <<
|
184
|
-
query.gsub(/:(\w+)/,"r1.\\1") << "\n) LOOP\n" <<
|
184
|
+
query.gsub(/:(\w+)/, "r1.\\1") << "\n) LOOP\n" <<
|
185
185
|
(cols.map do |col|
|
186
186
|
"l_#{col} := l_#{col} || r2.#{col} || CHR(10);\n"
|
187
187
|
end.join) <<
|
188
188
|
"END LOOP;\n" <<
|
189
189
|
(cols.map do |col|
|
190
190
|
col = col.to_s
|
191
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+2}, '<#{col}>');\n" <<
|
191
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length + 2}, '<#{col}>');\n" <<
|
192
192
|
"IF LENGTH(l_#{col}) > 0 THEN\n" <<
|
193
193
|
"DBMS_LOB.WRITEAPPEND(p_clob, LENGTH(l_#{col}), l_#{col});\n" <<
|
194
194
|
"END IF;\n" <<
|
195
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+3}, '</#{col}>');\n"
|
195
|
+
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length + 3}, '</#{col}>');\n"
|
196
196
|
end.join)
|
197
197
|
end.join)
|
198
198
|
}
|
199
199
|
END LOOP;
|
200
200
|
END;
|
201
201
|
SQL
|
202
|
-
|
202
|
+
end
|
203
203
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
204
|
+
def parse_select_queries(select_queries)
|
205
|
+
keys = []
|
206
|
+
selected_columns = []
|
207
|
+
select_queries.each do |query|
|
208
|
+
# get primary or foreign keys like :id or :something_id
|
209
|
+
keys << (query.scan(/:\w+/).map { |k| k[1..-1].downcase.to_sym })
|
210
|
+
select_part = query.scan(/^select\s.*\sfrom/i).first
|
211
|
+
selected_columns << select_part.scan(/\sas\s+(\w+)/i).map { |c| c.first }
|
212
|
+
end
|
213
|
+
[keys.flatten.uniq, selected_columns]
|
212
214
|
end
|
213
|
-
[keys.flatten.uniq, selected_columns]
|
214
|
-
end
|
215
215
|
|
216
|
-
|
217
|
-
|
218
|
-
|
216
|
+
def create_datastore_preference(datastore_name, procedure_name)
|
217
|
+
drop_ctx_preference(datastore_name)
|
218
|
+
execute <<-SQL
|
219
219
|
BEGIN
|
220
220
|
CTX_DDL.CREATE_PREFERENCE('#{datastore_name}', 'USER_DATASTORE');
|
221
221
|
CTX_DDL.SET_ATTRIBUTE('#{datastore_name}', 'PROCEDURE', '#{procedure_name}');
|
222
222
|
END;
|
223
223
|
SQL
|
224
|
-
|
224
|
+
end
|
225
225
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
226
|
+
def create_storage_preference(storage_name, tablespace)
|
227
|
+
drop_ctx_preference(storage_name)
|
228
|
+
sql = "BEGIN\nCTX_DDL.CREATE_PREFERENCE('#{storage_name}', 'BASIC_STORAGE');\n"
|
229
|
+
["I_TABLE_CLAUSE", "K_TABLE_CLAUSE", "R_TABLE_CLAUSE",
|
230
|
+
"N_TABLE_CLAUSE", "I_INDEX_CLAUSE", "P_TABLE_CLAUSE"].each do |clause|
|
231
|
+
default_clause = case clause
|
232
|
+
when "R_TABLE_CLAUSE"; "LOB(DATA) STORE AS (CACHE) "
|
233
|
+
when "I_INDEX_CLAUSE"; "COMPRESS 2 "
|
234
|
+
else ""
|
235
|
+
end
|
236
|
+
sql << "CTX_DDL.SET_ATTRIBUTE('#{storage_name}', '#{clause}', '#{default_clause}TABLESPACE #{tablespace}');\n"
|
235
237
|
end
|
236
|
-
sql << "
|
238
|
+
sql << "END;\n"
|
239
|
+
execute sql
|
237
240
|
end
|
238
|
-
sql << "END;\n"
|
239
|
-
execute sql
|
240
|
-
end
|
241
241
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
242
|
+
def create_lexer_preference(lexer_name, lexer_type, options)
|
243
|
+
drop_ctx_preference(lexer_name)
|
244
|
+
sql = "BEGIN\nCTX_DDL.CREATE_PREFERENCE('#{lexer_name}', '#{lexer_type}');\n"
|
245
|
+
options.each do |key, value|
|
246
|
+
plsql_value = case value
|
247
|
+
when String; "'#{value}'"
|
248
|
+
when true; "'YES'"
|
249
|
+
when false; "'NO'"
|
250
|
+
when nil; "NULL"
|
251
|
+
else value
|
252
|
+
end
|
253
|
+
sql << "CTX_DDL.SET_ATTRIBUTE('#{lexer_name}', '#{key}', #{plsql_value});\n"
|
252
254
|
end
|
253
|
-
sql << "
|
255
|
+
sql << "END;\n"
|
256
|
+
execute sql
|
254
257
|
end
|
255
|
-
sql << "END;\n"
|
256
|
-
execute sql
|
257
|
-
end
|
258
258
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
259
|
+
def create_wordlist_preference(wordlist_name, wordlist_type, options)
|
260
|
+
drop_ctx_preference(wordlist_name)
|
261
|
+
sql = "BEGIN\nCTX_DDL.CREATE_PREFERENCE('#{wordlist_name}', '#{wordlist_type}');\n"
|
262
|
+
options.each do |key, value|
|
263
|
+
plsql_value = case value
|
264
|
+
when String; "'#{value}'"
|
265
|
+
when true; "'YES'"
|
266
|
+
when false; "'NO'"
|
267
|
+
when nil; "NULL"
|
268
|
+
else value
|
269
|
+
end
|
270
|
+
sql << "CTX_DDL.SET_ATTRIBUTE('#{wordlist_name}', '#{key}', #{plsql_value});\n"
|
269
271
|
end
|
270
|
-
sql << "
|
272
|
+
sql << "END;\n"
|
273
|
+
execute sql
|
271
274
|
end
|
272
|
-
sql << "END;\n"
|
273
|
-
execute sql
|
274
|
-
end
|
275
275
|
|
276
|
-
|
277
|
-
|
278
|
-
|
276
|
+
def drop_ctx_preference(preference_name)
|
277
|
+
execute "BEGIN CTX_DDL.DROP_PREFERENCE('#{preference_name}'); END;" rescue nil
|
278
|
+
end
|
279
279
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
280
|
+
def create_index_column_trigger(table_name, index_name, index_column, index_column_source)
|
281
|
+
trigger_name = default_index_column_trigger_name(index_name)
|
282
|
+
columns = Array(index_column_source)
|
283
|
+
quoted_column_names = columns.map { |col| quote_column_name(col) }.join(", ")
|
284
|
+
execute compress_lines(<<-SQL)
|
285
285
|
CREATE OR REPLACE TRIGGER #{quote_table_name(trigger_name)}
|
286
286
|
BEFORE UPDATE OF #{quoted_column_names} ON #{quote_table_name(table_name)} FOR EACH ROW
|
287
287
|
BEGIN
|
288
288
|
:new.#{quote_column_name(index_column)} := '1';
|
289
289
|
END;
|
290
290
|
SQL
|
291
|
-
|
291
|
+
end
|
292
292
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
293
|
+
def drop_index_column_trigger(index_name)
|
294
|
+
trigger_name = default_index_column_trigger_name(index_name)
|
295
|
+
execute "DROP TRIGGER #{quote_table_name(trigger_name)}" rescue nil
|
296
|
+
end
|
297
297
|
|
298
|
-
|
299
|
-
|
300
|
-
|
298
|
+
def default_datastore_procedure(index_name)
|
299
|
+
"#{index_name}_prc"
|
300
|
+
end
|
301
301
|
|
302
|
-
|
303
|
-
|
304
|
-
|
302
|
+
def default_datastore_name(index_name)
|
303
|
+
"#{index_name}_dst"
|
304
|
+
end
|
305
305
|
|
306
|
-
|
307
|
-
|
308
|
-
|
306
|
+
def default_storage_name(index_name)
|
307
|
+
"#{index_name}_sto"
|
308
|
+
end
|
309
309
|
|
310
|
-
|
311
|
-
|
312
|
-
|
310
|
+
def default_index_column_trigger_name(index_name)
|
311
|
+
"#{index_name}_trg"
|
312
|
+
end
|
313
313
|
|
314
|
-
|
315
|
-
|
316
|
-
|
314
|
+
def default_lexer_name(index_name)
|
315
|
+
"#{index_name}_lex"
|
316
|
+
end
|
317
317
|
|
318
|
-
|
319
|
-
|
320
|
-
|
318
|
+
def default_wordlist_name(index_name)
|
319
|
+
"#{index_name}_wl"
|
320
|
+
end
|
321
321
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
322
|
+
module BaseClassMethods
|
323
|
+
# Declare that model table has context index defined.
|
324
|
+
# As a result <tt>contains</tt> class scope method is defined.
|
325
|
+
def has_context_index
|
326
|
+
extend ContextIndexClassMethods
|
327
|
+
end
|
327
328
|
end
|
328
|
-
end
|
329
329
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
330
|
+
module ContextIndexClassMethods
|
331
|
+
# Add context index condition.
|
332
|
+
def contains(column, query, options = {})
|
333
|
+
score_label = options[:label].to_i || 1
|
334
|
+
where("CONTAINS(#{connection.quote_table_name(column)}, ?, #{score_label}) > 0", query).
|
335
|
+
order("SCORE(#{score_label}) DESC")
|
336
|
+
end
|
336
337
|
end
|
337
|
-
end
|
338
338
|
end
|
339
339
|
end
|
340
340
|
end
|