activerecord-oracle_enhanced-adapter 1.4.1 → 1.4.2.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/History.md +16 -1
- data/README.md +60 -35
- data/Rakefile +14 -1
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +2 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +27 -9
- data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +13 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +7 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +31 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +6 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +17 -5
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +2 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +29 -11
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +9 -4
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +31 -7
- data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +5 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +34 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +22 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +1 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +52 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +20 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +6 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +79 -21
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +203 -35
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +17 -1
- data/spec/spec_helper.rb +3 -1
- metadata +74 -51
data/Gemfile
CHANGED
data/History.md
CHANGED
@@ -1,4 +1,19 @@
|
|
1
|
-
### 1.4.
|
1
|
+
### 1.4.2.rc1 / 2012-11-13
|
2
|
+
|
3
|
+
* Enhancements:
|
4
|
+
* Wordlist option for context index [#154]
|
5
|
+
* Fall back to directly connecting via OracleDriver on JRuby [#163]
|
6
|
+
* Allow slash-prefixed database name in database.yml for using a service [#201]
|
7
|
+
* Bug fixes:
|
8
|
+
* Fixed explain plans to work with JDBC and OCI8 [#146]
|
9
|
+
* Fixed various issues with virtual columns [#159]
|
10
|
+
* Fixed SQL structure dump with function indexes [#161]
|
11
|
+
* Fixed broken column remove inside a change_table block [#216]
|
12
|
+
* Dump indexes on virtual columns using the column's name instead of the column expression [#211]
|
13
|
+
* Don't update lobs that haven't changed or are attr_readonly [#212]
|
14
|
+
* Support dirty tracking with rails 3.2.9
|
15
|
+
|
16
|
+
### 1.4.1 / 2012-01-27
|
2
17
|
|
3
18
|
* Enhancements:
|
4
19
|
* Support for Rails 3.2
|
data/README.md
CHANGED
@@ -25,7 +25,7 @@ If you would like to use latest adapter version from github then specify
|
|
25
25
|
|
26
26
|
If you are using MRI 1.8 or 1.9 Ruby implementation then you need to install ruby-oci8 gem as well as Oracle client, e.g. [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html). Include in Gemfile also ruby-oci8:
|
27
27
|
|
28
|
-
gem 'ruby-oci8', '~> 2.0
|
28
|
+
gem 'ruby-oci8', '~> 2.1.0'
|
29
29
|
|
30
30
|
If you are using JRuby then you need to download latest [Oracle JDBC driver](http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html) - either ojdbc6.jar for Java 6 or ojdbc5.jar for Java 5. And copy this file to one of these locations:
|
31
31
|
|
@@ -72,6 +72,15 @@ In Rails application `config/database.yml` use oracle_enhanced as adapter name,
|
|
72
72
|
username: user
|
73
73
|
password: secret
|
74
74
|
|
75
|
+
If you're connecting to a service name, indicate the service with a
|
76
|
+
leading slash on the database parameter:
|
77
|
+
|
78
|
+
development:
|
79
|
+
adapter: oracle_enhanced
|
80
|
+
database: /xe
|
81
|
+
username: user
|
82
|
+
password: secret
|
83
|
+
|
75
84
|
If `TNS_ADMIN` environment variable is pointing to directory where `tnsnames.ora` file is located then you can use TNS connection name in `database` parameter. Otherwise you can directly specify database host, port (defaults to 1521) and database name in the following way:
|
76
85
|
|
77
86
|
development:
|
@@ -248,6 +257,54 @@ And you can even create index on multiple tables by providing SELECT statements
|
|
248
257
|
Post.contains(:all_text, "aaa within title")
|
249
258
|
Post.contains(:all_text, "bbb within comment_author")
|
250
259
|
|
260
|
+
### Oracle virtual collumns support
|
261
|
+
|
262
|
+
Since version R11G1 Oracle database allows adding computed [Virtual Columns](http://www.oracle-base.com/articles/11g/virtual-columns-11gr1.php) to the table.
|
263
|
+
They can be used as normal fields in the queries, in the foreign key contstraints and to partitioning data.
|
264
|
+
|
265
|
+
To define virtual column you can use `virtual` method in the `create_table` block, providing column expression in the `:as` option:
|
266
|
+
|
267
|
+
create_table :mytable do |t|
|
268
|
+
t.decimal :price, :precision => 15, :scale => 2
|
269
|
+
t.decimal :quantity, :precision => 15, :scale => 2
|
270
|
+
t.virtual :amount, :as => 'price * quantity'
|
271
|
+
end
|
272
|
+
|
273
|
+
Oracle tries to predict type of the virtual column, based on its expression but sometimes it is necessary to state type explicitly.
|
274
|
+
This can be done by providing `:type` option to the `virtual` method:
|
275
|
+
|
276
|
+
...
|
277
|
+
t.virtual :amount_2, :as => 'ROUND(price * quantity,2)', :type => :decimal, :precision => 15, :scale => 2
|
278
|
+
t.virtual :amount_str, :as => "TO_CHAR(quantity) || ' x ' || TO_CHAR(price) || ' USD = ' || TO_CHAR(quantity*price) || ' USD'",
|
279
|
+
:type => :string, :limit => 100
|
280
|
+
...
|
281
|
+
|
282
|
+
It is possible to add virtual column to existing table:
|
283
|
+
|
284
|
+
add_column :mytable, :amount_4, :virtual, :as => 'ROUND(price * quantity,4)', :precision => 38, :scale => 4
|
285
|
+
|
286
|
+
You can use the same options here as in the `create_table` `virtual` method.
|
287
|
+
|
288
|
+
Changing virtual columns is also possible:
|
289
|
+
|
290
|
+
change_column :mytable, :amount, :virtual, :as => 'ROUND(price * quantity,0)', :type => :integer
|
291
|
+
|
292
|
+
Virtual columns allowed in the foreign key constraints.
|
293
|
+
For example it can be used to force foreign key constraint on polymorphic association:
|
294
|
+
|
295
|
+
create_table :comments do |t|
|
296
|
+
t.string :subject_type
|
297
|
+
t.integer :subject_id
|
298
|
+
t.virtual :subject_photo_id, :as => "CASE subject_type WHEN 'Photo' THEN subject_id END"
|
299
|
+
t.virtual :subject_event_id, :as => "CASE subject_type WHEN 'Event' THEN subject_id END"
|
300
|
+
end
|
301
|
+
|
302
|
+
add_foreign_key :comments, :photos, :column => :subject_photo_id
|
303
|
+
add_foreign_key :comments, :events, :column => :subject_event_id
|
304
|
+
|
305
|
+
For backward compatibility reasons it is possible to use `:default` option in the `create_table` instead of `:as` option.
|
306
|
+
But this is deprecated and may be removed in the future version.
|
307
|
+
|
251
308
|
### Oracle specific schema statements and data types
|
252
309
|
|
253
310
|
There are several additional schema statements and data types available that you can use in database migrations:
|
@@ -257,7 +314,6 @@ There are several additional schema statements and data types available that you
|
|
257
314
|
* You can create table with primary key trigger using `:primary_key_trigger => true` option for `create_table`
|
258
315
|
* You can define columns with `raw` type which maps to Oracle's `RAW` type
|
259
316
|
* You can add table and column comments with `:comment` option
|
260
|
-
* On Oracle 11g you can define `virtual` columns with calculation formula in `:default` option
|
261
317
|
* Default tablespaces can be specified for tables, indexes, clobs and blobs, for example:
|
262
318
|
|
263
319
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
|
@@ -285,7 +341,7 @@ Please verify that
|
|
285
341
|
require 'rubygems'
|
286
342
|
gem 'activerecord'
|
287
343
|
gem 'activerecord-oracle_enhanced-adapter'
|
288
|
-
require '
|
344
|
+
require 'active_record'
|
289
345
|
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced", :database => "database",:username => "user",:password => "password")
|
290
346
|
|
291
347
|
and see if it is successful (use your correct database, username and password)
|
@@ -320,37 +376,6 @@ LINKS
|
|
320
376
|
* Discuss at Oracle enhanced adapter group: http://groups.google.com/group/oracle-enhanced
|
321
377
|
* Blog posts about Oracle enhanced adapter can be found at http://blog.rayapps.com/category/oracle_enhanced
|
322
378
|
|
323
|
-
CONTRIBUTORS
|
324
|
-
------------
|
325
|
-
|
326
|
-
* Raimonds Simanovskis
|
327
|
-
* Jorge Dias
|
328
|
-
* James Wylder
|
329
|
-
* Rob Christie
|
330
|
-
* Nate Wieger
|
331
|
-
* Edgars Beigarts
|
332
|
-
* Lachlan Laycock
|
333
|
-
* toddwf
|
334
|
-
* Anton Jenkins
|
335
|
-
* Dave Smylie
|
336
|
-
* Alex Rothenberg
|
337
|
-
* Billy Reisinger
|
338
|
-
* David Blain
|
339
|
-
* Joe Khoobyar
|
340
|
-
* Edvard Majakari
|
341
|
-
* Beau Fabry
|
342
|
-
* Simon Chiang
|
343
|
-
* Peter Nyberg
|
344
|
-
* Dwayne Litzenberger
|
345
|
-
* Aaron Patterson
|
346
|
-
* Darcy Schultz
|
347
|
-
* Alexi Rahman
|
348
|
-
* Joeri Samson
|
349
|
-
* Luca Bernardo Ciddio
|
350
|
-
* Sam Baskinger
|
351
|
-
* Benjamin Ortega
|
352
|
-
* Yasuo Honda
|
353
|
-
|
354
379
|
LICENSE
|
355
380
|
-------
|
356
381
|
|
@@ -375,4 +400,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
375
400
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
376
401
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
377
402
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
378
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
403
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -33,9 +33,22 @@ RSpec::Core::RakeTask.new(:rcov) do |t|
|
|
33
33
|
t.rcov_opts = ['--exclude', '/Library,spec/']
|
34
34
|
end
|
35
35
|
|
36
|
+
desc "Clear test database"
|
37
|
+
task :clear do
|
38
|
+
require "./spec/spec_helper"
|
39
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
40
|
+
require "active_support/core_ext"
|
41
|
+
ActiveRecord::Base.connection.execute_structure_dump(ActiveRecord::Base.connection.full_drop)
|
42
|
+
ActiveRecord::Base.connection.execute("PURGE RECYCLEBIN") rescue nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Clear test database before running spec and rcov
|
46
|
+
task :spec => :clear
|
47
|
+
task :rcov => :clear
|
48
|
+
|
36
49
|
task :default => :spec
|
37
50
|
|
38
|
-
require '
|
51
|
+
require 'rdoc/task'
|
39
52
|
Rake::RDocTask.new do |rdoc|
|
40
53
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
54
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.4.
|
1
|
+
1.4.2.rc1
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{activerecord-oracle_enhanced-adapter}
|
8
|
-
s.version = "1.4.
|
8
|
+
s.version = "1.4.2.rc1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Raimonds Simanovskis}]
|
12
|
-
s.date = %q{2012-
|
12
|
+
s.date = %q{2012-11-13}
|
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
|
}
|
@@ -656,7 +656,11 @@ module ActiveRecord
|
|
656
656
|
def explain(arel, binds = [])
|
657
657
|
sql = "EXPLAIN PLAN FOR #{to_sql(arel)}"
|
658
658
|
return if sql =~ /FROM all_/
|
659
|
-
|
659
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
660
|
+
exec_query(sql, 'EXPLAIN', binds)
|
661
|
+
else
|
662
|
+
exec_query(sql, 'EXPLAIN')
|
663
|
+
end
|
660
664
|
select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)", 'EXPLAIN').join("\n")
|
661
665
|
end
|
662
666
|
|
@@ -855,12 +859,12 @@ module ActiveRecord
|
|
855
859
|
|
856
860
|
klass = klass.constantize rescue nil
|
857
861
|
if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base)
|
858
|
-
write_lobs(table_name, klass, fixture)
|
862
|
+
write_lobs(table_name, klass, fixture, klass.lob_columns)
|
859
863
|
end
|
860
864
|
end
|
861
865
|
|
862
|
-
# Writes LOB values from attributes
|
863
|
-
def write_lobs(table_name, klass, attributes) #:nodoc:
|
866
|
+
# Writes LOB values from attributes for specified columns
|
867
|
+
def write_lobs(table_name, klass, attributes, columns) #:nodoc:
|
864
868
|
# is class with composite primary key>
|
865
869
|
is_with_cpk = klass.respond_to?(:composite?) && klass.composite?
|
866
870
|
if is_with_cpk
|
@@ -868,7 +872,7 @@ module ActiveRecord
|
|
868
872
|
else
|
869
873
|
id = quote(attributes[klass.primary_key])
|
870
874
|
end
|
871
|
-
|
875
|
+
columns.each do |col|
|
872
876
|
value = attributes[col.name]
|
873
877
|
# changed sequence of next two lines - should check if value is nil before converting to yaml
|
874
878
|
next if value.nil? || (value == '')
|
@@ -930,11 +934,14 @@ module ActiveRecord
|
|
930
934
|
SELECT LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
|
931
935
|
i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
|
932
936
|
LOWER(i.tablespace_name) AS tablespace_name,
|
933
|
-
LOWER(c.column_name) AS column_name, e.column_expression
|
937
|
+
LOWER(c.column_name) AS column_name, e.column_expression,
|
938
|
+
atc.virtual_column
|
934
939
|
FROM all_indexes#{db_link} i
|
935
940
|
JOIN all_ind_columns#{db_link} c ON c.index_name = i.index_name AND c.index_owner = i.owner
|
936
941
|
LEFT OUTER JOIN all_ind_expressions#{db_link} e ON e.index_name = i.index_name AND
|
937
942
|
e.index_owner = i.owner AND e.column_position = c.column_position
|
943
|
+
LEFT OUTER JOIN all_tab_cols#{db_link} atc ON i.table_name = atc.table_name AND
|
944
|
+
c.column_name = atc.column_name AND i.owner = atc.owner AND atc.hidden_column = 'NO'
|
938
945
|
WHERE i.owner = '#{owner}'
|
939
946
|
AND i.table_owner = '#{owner}'
|
940
947
|
AND NOT EXISTS (SELECT uc.index_name FROM all_constraints uc
|
@@ -969,7 +976,16 @@ module ActiveRecord
|
|
969
976
|
row['tablespace_name'] == default_tablespace_name ? nil : row['tablespace_name'], [])
|
970
977
|
current_index = row['index_name']
|
971
978
|
end
|
972
|
-
|
979
|
+
|
980
|
+
# Functional index columns and virtual columns both get stored as column expressions,
|
981
|
+
# but re-creating a virtual column index as an expression (instead of using the virtual column's name)
|
982
|
+
# results in a ORA-54018 error. Thus, we only want the column expression value returned
|
983
|
+
# when the column is not virtual.
|
984
|
+
if row['column_expression'] && row['virtual_column'] != 'YES'
|
985
|
+
all_schema_indexes.last.columns << row['column_expression']
|
986
|
+
else
|
987
|
+
all_schema_indexes.last.columns << row['column_name'].downcase
|
988
|
+
end
|
973
989
|
end
|
974
990
|
end
|
975
991
|
|
@@ -1089,8 +1105,10 @@ module ActiveRecord
|
|
1089
1105
|
row['sql_type'] += "(#{(limit || 38).to_i}" + ((scale = scale.to_i) > 0 ? ",#{scale})" : ")")
|
1090
1106
|
end
|
1091
1107
|
|
1108
|
+
is_virtual = row['virtual_column']=='YES'
|
1109
|
+
|
1092
1110
|
# clean up odd default spacing from Oracle
|
1093
|
-
if row['data_default']
|
1111
|
+
if row['data_default'] && !is_virtual
|
1094
1112
|
row['data_default'].sub!(/^(.*?)\s*$/, '\1')
|
1095
1113
|
|
1096
1114
|
# If a default contains a newline these cleanup regexes need to
|
@@ -1106,7 +1124,7 @@ module ActiveRecord
|
|
1106
1124
|
# pass table name for table specific column definitions
|
1107
1125
|
table_name,
|
1108
1126
|
# pass column type if specified in class definition
|
1109
|
-
get_type_for_column(table_name, oracle_downcase(row['name'])),
|
1127
|
+
get_type_for_column(table_name, oracle_downcase(row['name'])), is_virtual)
|
1110
1128
|
end
|
1111
1129
|
end
|
1112
1130
|
|
@@ -62,23 +62,35 @@ module ActiveRecord
|
|
62
62
|
# After setting large objects to empty, select the OCI8::LOB
|
63
63
|
# and write back the data.
|
64
64
|
if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR >= 1
|
65
|
+
before_update :record_changed_lobs
|
65
66
|
after_update :enhanced_write_lobs
|
66
67
|
else
|
68
|
+
before_update :record_changed_lobs
|
67
69
|
after_save :enhanced_write_lobs
|
68
70
|
end
|
69
71
|
def enhanced_write_lobs #:nodoc:
|
70
72
|
if connection.is_a?(ConnectionAdapters::OracleEnhancedAdapter) &&
|
71
73
|
!(self.class.custom_create_method || self.class.custom_update_method)
|
72
|
-
connection.write_lobs(self.class.table_name, self.class, attributes)
|
74
|
+
connection.write_lobs(self.class.table_name, self.class, attributes, @changed_lob_columns || self.class.lob_columns)
|
73
75
|
end
|
74
76
|
end
|
77
|
+
def record_changed_lobs
|
78
|
+
@changed_lob_columns = self.class.lob_columns.select{|col| self.send(:"#{col.name}_changed?") && !self.class.readonly_attributes.to_a.include?(col.name)}
|
79
|
+
end
|
75
80
|
private :enhanced_write_lobs
|
81
|
+
private :record_changed_lobs
|
76
82
|
|
77
83
|
# Get table comment from schema definition.
|
78
84
|
def self.table_comment
|
79
85
|
connection.table_comment(self.table_name)
|
80
86
|
end
|
81
87
|
|
88
|
+
def self.lob_columns
|
89
|
+
columns.select do |column|
|
90
|
+
column.respond_to?(:lob?) && column.lob?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
82
94
|
def self.virtual_columns
|
83
95
|
columns.select do |column|
|
84
96
|
column.respond_to?(:virtual?) && column.virtual?
|
@@ -3,13 +3,14 @@ module ActiveRecord
|
|
3
3
|
class OracleEnhancedColumn < Column
|
4
4
|
|
5
5
|
attr_reader :table_name, :forced_column_type, :nchar, :virtual_column_data_default #:nodoc:
|
6
|
-
|
6
|
+
|
7
7
|
def initialize(name, default, sql_type = nil, null = true, table_name = nil, forced_column_type = nil, virtual=false) #:nodoc:
|
8
8
|
@table_name = table_name
|
9
9
|
@forced_column_type = forced_column_type
|
10
10
|
@virtual = virtual
|
11
|
-
super(name, default, sql_type, null)
|
12
11
|
@virtual_column_data_default = default.inspect if virtual
|
12
|
+
default = nil if virtual
|
13
|
+
super(name, default, sql_type, null)
|
13
14
|
# Is column NCHAR or NVARCHAR2 (will need to use N'...' value quoting for these data types)?
|
14
15
|
# Define only when needed as adapter "quote" method will check at first if instance variable is defined.
|
15
16
|
@nchar = true if @type == :string && sql_type[0,1] == 'N'
|
@@ -25,6 +26,10 @@ module ActiveRecord
|
|
25
26
|
@virtual
|
26
27
|
end
|
27
28
|
|
29
|
+
def lob?
|
30
|
+
self.sql_type =~ /LOB$/i
|
31
|
+
end
|
32
|
+
|
28
33
|
# convert something to a boolean
|
29
34
|
# added y as boolean value
|
30
35
|
def self.value_to_boolean(value) #:nodoc:
|
@@ -21,6 +21,7 @@ module ActiveRecord
|
|
21
21
|
# * <tt>:tablespace</tt>
|
22
22
|
# * <tt>:sync</tt> - 'MANUAL', 'EVERY "interval-string"' or 'ON COMMIT' (defaults to 'MANUAL').
|
23
23
|
# * <tt>:lexer</tt> - Lexer options (e.g. <tt>:type => 'BASIC_LEXER', :base_letter => true</tt>).
|
24
|
+
# * <tt>:wordlist</tt> - Wordlist options (e.g. <tt>:type => 'BASIC_WORDLIST', :prefix_index => true</tt>).
|
24
25
|
# * <tt>:transactional</tt> - When +true+, the CONTAINS operator will process inserted and updated rows.
|
25
26
|
#
|
26
27
|
# ===== Examples
|
@@ -64,6 +65,9 @@ module ActiveRecord
|
|
64
65
|
# ====== Creating index using lexer
|
65
66
|
# add_context_index :posts, :title, :lexer => { :type => 'BASIC_LEXER', :base_letter => true, ... }
|
66
67
|
#
|
68
|
+
# ====== Creating index using wordlist
|
69
|
+
# add_context_index :posts, :title, :wordlist => { :type => 'BASIC_WORDLIST', :prefix_index => true, ... }
|
70
|
+
#
|
67
71
|
# ====== Creating transactional index (will reindex changed rows when querying)
|
68
72
|
# add_context_index :posts, :title, :transactional => true
|
69
73
|
#
|
@@ -106,6 +110,12 @@ module ActiveRecord
|
|
106
110
|
create_lexer_preference(lexer_name, lexer_type, lexer_options)
|
107
111
|
parameters << "LEXER #{lexer_name}"
|
108
112
|
end
|
113
|
+
if options[:wordlist] && (wordlist_type = options[:wordlist][:type])
|
114
|
+
wordlist_name = default_wordlist_name(index_name)
|
115
|
+
(wordlist_options = options[:wordlist].dup).delete(:type)
|
116
|
+
create_wordlist_preference(wordlist_name, wordlist_type, wordlist_options)
|
117
|
+
parameters << "WORDLIST #{wordlist_name}"
|
118
|
+
end
|
109
119
|
if options[:transactional]
|
110
120
|
parameters << "TRANSACTIONAL"
|
111
121
|
end
|
@@ -246,6 +256,23 @@ module ActiveRecord
|
|
246
256
|
execute sql
|
247
257
|
end
|
248
258
|
|
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"
|
271
|
+
end
|
272
|
+
sql << "END;\n"
|
273
|
+
execute sql
|
274
|
+
end
|
275
|
+
|
249
276
|
def drop_ctx_preference(preference_name)
|
250
277
|
execute "BEGIN CTX_DDL.DROP_PREFERENCE('#{preference_name}'); END;" rescue nil
|
251
278
|
end
|
@@ -288,6 +315,10 @@ module ActiveRecord
|
|
288
315
|
"#{index_name}_lex"
|
289
316
|
end
|
290
317
|
|
318
|
+
def default_wordlist_name(index_name)
|
319
|
+
"#{index_name}_wl"
|
320
|
+
end
|
321
|
+
|
291
322
|
module BaseClassMethods
|
292
323
|
# Declare that model table has context index defined.
|
293
324
|
# As a result <tt>contains</tt> class scope method is defined.
|
@@ -5,7 +5,7 @@ module ActiveRecord #:nodoc:
|
|
5
5
|
module InstanceMethods #:nodoc:
|
6
6
|
private
|
7
7
|
|
8
|
-
def
|
8
|
+
def _field_changed?(attr, old, value)
|
9
9
|
if column = column_for_attribute(attr)
|
10
10
|
# Added also :decimal type
|
11
11
|
if (column.type == :integer || column.type == :decimal) && column.null && (old.nil? || old == 0) && value.blank?
|
@@ -35,5 +35,10 @@ end
|
|
35
35
|
if ActiveRecord::Base.method_defined?(:changed?)
|
36
36
|
ActiveRecord::Base.class_eval do
|
37
37
|
include ActiveRecord::ConnectionAdapters::OracleEnhancedDirty::InstanceMethods
|
38
|
+
# Starting with rails 3.2.9 the method #field_changed?
|
39
|
+
# was renamed to #_field_changed?
|
40
|
+
if private_method_defined?(:field_changed?)
|
41
|
+
alias_method :field_changed?, :_field_changed?
|
42
|
+
end
|
38
43
|
end
|
39
44
|
end
|