activerecord-oracle_enhanced-adapter 1.5.6 → 1.6.9
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/.travis/oracle/download.sh +14 -0
- data/.travis/oracle/install.sh +31 -0
- data/.travis/setup_accounts.sh +9 -0
- data/.travis.yml +39 -0
- data/Gemfile +8 -8
- data/History.md +189 -0
- data/README.md +388 -178
- data/RUNNING_TESTS.md +11 -6
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +29 -26
- data/lib/active_record/connection_adapters/{oracle_enhanced_column.rb → oracle_enhanced/column.rb} +14 -63
- data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +66 -0
- data/lib/active_record/connection_adapters/{oracle_enhanced_connection.rb → oracle_enhanced/connection.rb} +2 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +347 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +260 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/dirty.rb +40 -0
- data/lib/active_record/connection_adapters/{oracle_enhanced_jdbc_connection.rb → oracle_enhanced/jdbc_connection.rb} +13 -4
- data/lib/active_record/connection_adapters/{oracle_enhanced_oci_connection.rb → oracle_enhanced/oci_connection.rb} +11 -5
- data/lib/active_record/connection_adapters/{oracle_enhanced_procedures.rb → oracle_enhanced/procedures.rb} +1 -1
- data/lib/active_record/connection_adapters/{oracle_enhanced_schema_creation.rb → oracle_enhanced/schema_creation.rb} +34 -35
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +95 -0
- data/lib/active_record/connection_adapters/{oracle_enhanced_schema_dumper.rb → oracle_enhanced/schema_dumper.rb} +14 -37
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +562 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +65 -0
- data/lib/active_record/connection_adapters/{oracle_enhanced_structure_dump.rb → oracle_enhanced/structure_dump.rb} +63 -14
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +171 -73
- data/lib/active_record/oracle_enhanced/type/integer.rb +13 -0
- data/lib/active_record/oracle_enhanced/type/raw.rb +13 -0
- data/lib/active_record/oracle_enhanced/type/timestamp.rb +11 -0
- data/lib/activerecord-oracle_enhanced-adapter.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +127 -49
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +46 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +11 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +3 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +151 -78
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +4 -4
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +10 -16
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +5 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +65 -181
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +114 -11
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +17 -1
- data/spec/spec_config.yaml.template +11 -0
- data/spec/spec_helper.rb +31 -12
- data/spec/support/alter_system_user_password.sql +2 -0
- data/spec/support/create_oracle_enhanced_users.sql +31 -0
- metadata +37 -27
- data/lib/active_record/connection_adapters/oracle_enhanced_column_dumper.rb +0 -77
- data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +0 -350
- data/lib/active_record/connection_adapters/oracle_enhanced_database_statements.rb +0 -262
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +0 -45
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +0 -197
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +0 -450
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +0 -258
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +0 -1
- /data/lib/active_record/connection_adapters/{oracle_enhanced_cpk.rb → oracle_enhanced/cpk.rb} +0 -0
- /data/lib/active_record/connection_adapters/{oracle_enhanced_database_tasks.rb → oracle_enhanced/database_tasks.rb} +0 -0
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,17 @@
|
|
1
|
-
require
|
1
|
+
require "rubygems"
|
2
2
|
require "bundler"
|
3
|
+
require "yaml"
|
3
4
|
Bundler.setup(:default, :development)
|
4
5
|
|
5
6
|
$:.unshift(File.expand_path('../../lib', __FILE__))
|
7
|
+
config_path = File.expand_path('../spec_config.yaml', __FILE__)
|
8
|
+
if File.exist?(config_path)
|
9
|
+
puts "==> Loading config from #{config_path}"
|
10
|
+
config = YAML.load_file(config_path)
|
11
|
+
else
|
12
|
+
puts "==> Loading config from ENV or use default"
|
13
|
+
config = {"rails" => {}, "database" => {}}
|
14
|
+
end
|
6
15
|
|
7
16
|
require 'rspec'
|
8
17
|
|
@@ -13,11 +22,8 @@ elsif RUBY_ENGINE == 'jruby'
|
|
13
22
|
puts "==> Running specs with JRuby version #{JRUBY_VERSION}"
|
14
23
|
end
|
15
24
|
|
16
|
-
ENV['RAILS_GEM_VERSION'] ||= '4.0-master'
|
17
25
|
NO_COMPOSITE_PRIMARY_KEYS = true
|
18
26
|
|
19
|
-
puts "==> Running specs with Rails version #{ENV['RAILS_GEM_VERSION']}"
|
20
|
-
|
21
27
|
require 'active_record'
|
22
28
|
|
23
29
|
require 'action_dispatch'
|
@@ -32,6 +38,8 @@ require 'logger'
|
|
32
38
|
require 'active_record/connection_adapters/oracle_enhanced_adapter'
|
33
39
|
require 'ruby-plsql'
|
34
40
|
|
41
|
+
puts "==> Effective ActiveRecord version #{ActiveRecord::VERSION::STRING}"
|
42
|
+
|
35
43
|
module LoggerSpecHelper
|
36
44
|
def set_logger
|
37
45
|
@logger = MockLogger.new
|
@@ -109,12 +117,13 @@ module SchemaSpecHelper
|
|
109
117
|
end
|
110
118
|
end
|
111
119
|
|
112
|
-
DATABASE_NAME
|
113
|
-
DATABASE_HOST
|
114
|
-
DATABASE_PORT
|
115
|
-
DATABASE_USER
|
116
|
-
DATABASE_PASSWORD
|
117
|
-
|
120
|
+
DATABASE_NAME = config["database"]["name"] || ENV['DATABASE_NAME'] || 'orcl'
|
121
|
+
DATABASE_HOST = config["database"]["host"] || ENV['DATABASE_HOST'] || "127.0.0.1"
|
122
|
+
DATABASE_PORT = config["database"]["port"] || ENV['DATABASE_PORT'] || 1521
|
123
|
+
DATABASE_USER = config["database"]["user"] || ENV['DATABASE_USER'] || 'oracle_enhanced'
|
124
|
+
DATABASE_PASSWORD = config["database"]["password"] || ENV['DATABASE_PASSWORD'] || 'oracle_enhanced'
|
125
|
+
DATABASE_SCHEMA = config["database"]["schema"] || ENV['DATABASE_SCHEMA'] || 'oracle_enhanced_schema'
|
126
|
+
DATABASE_SYS_PASSWORD = config["database"]["sys_password"] || ENV['DATABASE_SYS_PASSWORD'] || 'admin'
|
118
127
|
|
119
128
|
CONNECTION_PARAMS = {
|
120
129
|
:adapter => "oracle_enhanced",
|
@@ -125,6 +134,16 @@ CONNECTION_PARAMS = {
|
|
125
134
|
:password => DATABASE_PASSWORD
|
126
135
|
}
|
127
136
|
|
137
|
+
CONNECTION_WITH_SCHEMA_PARAMS = {
|
138
|
+
:adapter => "oracle_enhanced",
|
139
|
+
:database => DATABASE_NAME,
|
140
|
+
:host => DATABASE_HOST,
|
141
|
+
:port => DATABASE_PORT,
|
142
|
+
:username => DATABASE_USER,
|
143
|
+
:password => DATABASE_PASSWORD,
|
144
|
+
:schema => DATABASE_SCHEMA
|
145
|
+
}
|
146
|
+
|
128
147
|
SYS_CONNECTION_PARAMS = {
|
129
148
|
:adapter => "oracle_enhanced",
|
130
149
|
:database => DATABASE_NAME,
|
@@ -144,11 +163,11 @@ SYSTEM_CONNECTION_PARAMS = {
|
|
144
163
|
:password => DATABASE_SYS_PASSWORD
|
145
164
|
}
|
146
165
|
|
147
|
-
DATABASE_NON_DEFAULT_TABLESPACE = ENV['DATABASE_NON_DEFAULT_TABLESPACE'] || "SYSTEM"
|
166
|
+
DATABASE_NON_DEFAULT_TABLESPACE = config["database"]["non_default_tablespace"] || ENV['DATABASE_NON_DEFAULT_TABLESPACE'] || "SYSTEM"
|
148
167
|
|
149
168
|
# set default time zone in TZ environment variable
|
150
169
|
# which will be used to set session time zone
|
151
|
-
ENV['TZ'] ||= 'Europe/Riga'
|
170
|
+
ENV['TZ'] ||= config["timezone"] || 'Europe/Riga'
|
152
171
|
|
153
172
|
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
154
173
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
alter database default tablespace USERS;
|
2
|
+
|
3
|
+
CREATE USER oracle_enhanced IDENTIFIED BY oracle_enhanced;
|
4
|
+
|
5
|
+
GRANT unlimited tablespace, create session, create table, create sequence,
|
6
|
+
create procedure, create trigger, create view, create materialized view,
|
7
|
+
create database link, create synonym, create type, ctxapp TO oracle_enhanced;
|
8
|
+
|
9
|
+
CREATE USER oracle_enhanced_schema IDENTIFIED BY oracle_enhanced_schema;
|
10
|
+
|
11
|
+
GRANT unlimited tablespace, create session, create table, create sequence,
|
12
|
+
create procedure, create trigger, create view, create materialized view,
|
13
|
+
create database link, create synonym, create type, ctxapp TO oracle_enhanced_schema;
|
14
|
+
|
15
|
+
CREATE USER arunit IDENTIFIED BY arunit;
|
16
|
+
|
17
|
+
GRANT unlimited tablespace, create session, create table, create sequence,
|
18
|
+
create procedure, create trigger, create view, create materialized view,
|
19
|
+
create database link, create synonym, create type, ctxapp TO arunit;
|
20
|
+
|
21
|
+
CREATE USER arunit2 IDENTIFIED BY arunit2;
|
22
|
+
|
23
|
+
GRANT unlimited tablespace, create session, create table, create sequence,
|
24
|
+
create procedure, create trigger, create view, create materialized view,
|
25
|
+
create database link, create synonym, create type, ctxapp TO arunit2;
|
26
|
+
|
27
|
+
CREATE USER ruby IDENTIFIED BY oci8;
|
28
|
+
GRANT connect, resource, create view,create synonym TO ruby;
|
29
|
+
GRANT EXECUTE ON dbms_lock TO ruby;
|
30
|
+
GRANT CREATE VIEW TO ruby;
|
31
|
+
GRANT unlimited tablespace to ruby;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-oracle_enhanced-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raimonds Simanovskis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jeweler
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rdoc
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -202,6 +202,10 @@ extra_rdoc_files:
|
|
202
202
|
- README.md
|
203
203
|
files:
|
204
204
|
- ".rspec"
|
205
|
+
- ".travis.yml"
|
206
|
+
- ".travis/oracle/download.sh"
|
207
|
+
- ".travis/oracle/install.sh"
|
208
|
+
- ".travis/setup_accounts.sh"
|
205
209
|
- Gemfile
|
206
210
|
- History.md
|
207
211
|
- License.txt
|
@@ -211,25 +215,28 @@ files:
|
|
211
215
|
- VERSION
|
212
216
|
- activerecord-oracle_enhanced-adapter.gemspec
|
213
217
|
- lib/active_record/connection_adapters/emulation/oracle_adapter.rb
|
218
|
+
- lib/active_record/connection_adapters/oracle_enhanced/column.rb
|
219
|
+
- lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb
|
220
|
+
- lib/active_record/connection_adapters/oracle_enhanced/connection.rb
|
221
|
+
- lib/active_record/connection_adapters/oracle_enhanced/context_index.rb
|
222
|
+
- lib/active_record/connection_adapters/oracle_enhanced/cpk.rb
|
223
|
+
- lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb
|
224
|
+
- lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb
|
225
|
+
- lib/active_record/connection_adapters/oracle_enhanced/dirty.rb
|
226
|
+
- lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb
|
227
|
+
- lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb
|
228
|
+
- lib/active_record/connection_adapters/oracle_enhanced/procedures.rb
|
229
|
+
- lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb
|
230
|
+
- lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb
|
231
|
+
- lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb
|
232
|
+
- lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb
|
233
|
+
- lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb
|
234
|
+
- lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb
|
235
|
+
- lib/active_record/connection_adapters/oracle_enhanced/version.rb
|
214
236
|
- lib/active_record/connection_adapters/oracle_enhanced_adapter.rb
|
215
|
-
- lib/active_record/
|
216
|
-
- lib/active_record/
|
217
|
-
- lib/active_record/
|
218
|
-
- lib/active_record/connection_adapters/oracle_enhanced_context_index.rb
|
219
|
-
- lib/active_record/connection_adapters/oracle_enhanced_cpk.rb
|
220
|
-
- lib/active_record/connection_adapters/oracle_enhanced_database_statements.rb
|
221
|
-
- lib/active_record/connection_adapters/oracle_enhanced_database_tasks.rb
|
222
|
-
- lib/active_record/connection_adapters/oracle_enhanced_dirty.rb
|
223
|
-
- lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb
|
224
|
-
- lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb
|
225
|
-
- lib/active_record/connection_adapters/oracle_enhanced_procedures.rb
|
226
|
-
- lib/active_record/connection_adapters/oracle_enhanced_schema_creation.rb
|
227
|
-
- lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb
|
228
|
-
- lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb
|
229
|
-
- lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb
|
230
|
-
- lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb
|
231
|
-
- lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb
|
232
|
-
- lib/active_record/connection_adapters/oracle_enhanced_version.rb
|
237
|
+
- lib/active_record/oracle_enhanced/type/integer.rb
|
238
|
+
- lib/active_record/oracle_enhanced/type/raw.rb
|
239
|
+
- lib/active_record/oracle_enhanced/type/timestamp.rb
|
233
240
|
- lib/activerecord-oracle_enhanced-adapter.rb
|
234
241
|
- spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb
|
235
242
|
- spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb
|
@@ -244,7 +251,10 @@ files:
|
|
244
251
|
- spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb
|
245
252
|
- spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb
|
246
253
|
- spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb
|
254
|
+
- spec/spec_config.yaml.template
|
247
255
|
- spec/spec_helper.rb
|
256
|
+
- spec/support/alter_system_user_password.sql
|
257
|
+
- spec/support/create_oracle_enhanced_users.sql
|
248
258
|
homepage: http://github.com/rsim/oracle-enhanced
|
249
259
|
licenses:
|
250
260
|
- MIT
|
@@ -265,7 +275,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
265
275
|
version: '0'
|
266
276
|
requirements: []
|
267
277
|
rubyforge_project:
|
268
|
-
rubygems_version: 2.
|
278
|
+
rubygems_version: 2.6.11
|
269
279
|
signing_key:
|
270
280
|
specification_version: 4
|
271
281
|
summary: Oracle enhanced adapter for ActiveRecord
|
@@ -1,77 +0,0 @@
|
|
1
|
-
module ActiveRecord #:nodoc:
|
2
|
-
module ConnectionAdapters #:nodoc:
|
3
|
-
module OracleEnhancedColumnDumper #:nodoc:
|
4
|
-
|
5
|
-
def self.included(base) #:nodoc:
|
6
|
-
base.class_eval do
|
7
|
-
private
|
8
|
-
alias_method_chain :column_spec, :oracle_enhanced
|
9
|
-
alias_method_chain :prepare_column_options, :oracle_enhanced
|
10
|
-
alias_method_chain :migration_keys, :oracle_enhanced
|
11
|
-
|
12
|
-
def oracle_enhanced_adapter?
|
13
|
-
# return original method if not using 'OracleEnhanced'
|
14
|
-
if (rails_env = defined?(Rails.env) ? Rails.env : (defined?(RAILS_ENV) ? RAILS_ENV : nil)) &&
|
15
|
-
ActiveRecord::Base.configurations[rails_env] &&
|
16
|
-
ActiveRecord::Base.configurations[rails_env]['adapter'] != 'oracle_enhanced'
|
17
|
-
return false
|
18
|
-
else
|
19
|
-
return true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def column_spec_with_oracle_enhanced(column, types)
|
26
|
-
# return original method if not using 'OracleEnhanced'
|
27
|
-
return column_spec_without_oracle_enhanced(column, types) unless oracle_enhanced_adapter?
|
28
|
-
|
29
|
-
spec = prepare_column_options(column, types)
|
30
|
-
(spec.keys - [:name, :type]).each do |k|
|
31
|
-
key_s = (k == :virtual_type ? "type: " : "#{k.to_s}: ")
|
32
|
-
spec[k] = key_s + spec[k]
|
33
|
-
end
|
34
|
-
spec
|
35
|
-
end
|
36
|
-
|
37
|
-
def prepare_column_options_with_oracle_enhanced(column, types)
|
38
|
-
# return original method if not using 'OracleEnhanced'
|
39
|
-
return prepare_column_options_without_oracle_enhanced(column, types) unless oracle_enhanced_adapter?
|
40
|
-
|
41
|
-
spec = {}
|
42
|
-
|
43
|
-
spec[:name] = column.name.inspect
|
44
|
-
spec[:type] = column.virtual? ? 'virtual' : column.type.to_s
|
45
|
-
spec[:limit] = column.limit.inspect if column.limit != types[column.type][:limit] && column.type != :decimal
|
46
|
-
spec[:precision] = column.precision.inspect if !column.precision.nil?
|
47
|
-
spec[:scale] = column.scale.inspect if !column.scale.nil?
|
48
|
-
spec[:null] = 'false' if !column.null
|
49
|
-
spec[:as] = column.virtual_column_data_default if column.virtual?
|
50
|
-
spec[:default] = default_string(column.default) if column.has_default? && !column.virtual?
|
51
|
-
|
52
|
-
if column.virtual?
|
53
|
-
# Supports backwards compatibility with older OracleEnhancedAdapter versions where 'NUMBER' virtual column type is not included in dump
|
54
|
-
if column.sql_type != "NUMBER" || ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.number_datatype_coercion != :decimal
|
55
|
-
spec[:virtual_type] = column.type.inspect
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
spec
|
60
|
-
end
|
61
|
-
|
62
|
-
def migration_keys_with_oracle_enhanced
|
63
|
-
# TODO `& column_specs.map(&:keys).flatten` should be exetuted here
|
64
|
-
# return original method if not using 'OracleEnhanced'
|
65
|
-
return migration_keys_without_oracle_enhanced unless oracle_enhanced_adapter?
|
66
|
-
|
67
|
-
[:name, :limit, :precision, :scale, :default, :null, :as, :virtual_type]
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
ActiveRecord::ConnectionAdapters::ColumnDumper.class_eval do
|
76
|
-
include ActiveRecord::ConnectionAdapters::OracleEnhancedColumnDumper
|
77
|
-
end
|
@@ -1,350 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module ConnectionAdapters
|
3
|
-
module OracleEnhancedContextIndex
|
4
|
-
|
5
|
-
# Define full text index with Oracle specific CONTEXT index type
|
6
|
-
#
|
7
|
-
# Oracle CONTEXT index by default supports full text indexing of one column.
|
8
|
-
# This method allows full text index creation also on several columns
|
9
|
-
# as well as indexing related table columns by generating stored procedure
|
10
|
-
# that concatenates all columns for indexing as well as generating trigger
|
11
|
-
# that will update main index column to trigger reindexing of record.
|
12
|
-
#
|
13
|
-
# Use +contains+ ActiveRecord model instance method to add CONTAINS where condition
|
14
|
-
# and order by score of matched results.
|
15
|
-
#
|
16
|
-
# Options:
|
17
|
-
#
|
18
|
-
# * <tt>:name</tt>
|
19
|
-
# * <tt>:index_column</tt>
|
20
|
-
# * <tt>:index_column_trigger_on</tt>
|
21
|
-
# * <tt>:tablespace</tt>
|
22
|
-
# * <tt>:sync</tt> - 'MANUAL', 'EVERY "interval-string"' or 'ON COMMIT' (defaults to 'MANUAL').
|
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>).
|
25
|
-
# * <tt>:transactional</tt> - When +true+, the CONTAINS operator will process inserted and updated rows.
|
26
|
-
#
|
27
|
-
# ===== Examples
|
28
|
-
#
|
29
|
-
# ====== Creating single column index
|
30
|
-
# add_context_index :posts, :title
|
31
|
-
# search with
|
32
|
-
# Post.contains(:title, 'word')
|
33
|
-
#
|
34
|
-
# ====== Creating index on several columns
|
35
|
-
# add_context_index :posts, [:title, :body]
|
36
|
-
# search with (use first column as argument for contains method but it will search in all index columns)
|
37
|
-
# Post.contains(:title, 'word')
|
38
|
-
#
|
39
|
-
# ====== Creating index on several columns with dummy index column and commit option
|
40
|
-
# add_context_index :posts, [:title, :body], :index_column => :all_text, :sync => 'ON COMMIT'
|
41
|
-
# search with
|
42
|
-
# Post.contains(:all_text, 'word')
|
43
|
-
#
|
44
|
-
# ====== Creating index with trigger option (will reindex when specified columns are updated)
|
45
|
-
# add_context_index :posts, [:title, :body], :index_column => :all_text, :sync => 'ON COMMIT',
|
46
|
-
# :index_column_trigger_on => [:created_at, :updated_at]
|
47
|
-
# search with
|
48
|
-
# Post.contains(:all_text, 'word')
|
49
|
-
#
|
50
|
-
# ====== Creating index on multiple tables
|
51
|
-
# add_context_index :posts,
|
52
|
-
# [:title, :body,
|
53
|
-
# # specify aliases always with AS keyword
|
54
|
-
# "SELECT comments.author AS comment_author, comments.body AS comment_body FROM comments WHERE comments.post_id = :id"
|
55
|
-
# ],
|
56
|
-
# :name => 'post_and_comments_index',
|
57
|
-
# :index_column => :all_text, :index_column_trigger_on => [:updated_at, :comments_count],
|
58
|
-
# :sync => 'ON COMMIT'
|
59
|
-
# search in any table columns
|
60
|
-
# Post.contains(:all_text, 'word')
|
61
|
-
# search in specified column
|
62
|
-
# Post.contains(:all_text, "aaa within title")
|
63
|
-
# Post.contains(:all_text, "bbb within comment_author")
|
64
|
-
#
|
65
|
-
# ====== Creating index using lexer
|
66
|
-
# add_context_index :posts, :title, :lexer => { :type => 'BASIC_LEXER', :base_letter => true, ... }
|
67
|
-
#
|
68
|
-
# ====== Creating index using wordlist
|
69
|
-
# add_context_index :posts, :title, :wordlist => { :type => 'BASIC_WORDLIST', :prefix_index => true, ... }
|
70
|
-
#
|
71
|
-
# ====== Creating transactional index (will reindex changed rows when querying)
|
72
|
-
# add_context_index :posts, :title, :transactional => true
|
73
|
-
#
|
74
|
-
def add_context_index(table_name, column_name, options = {})
|
75
|
-
self.all_schema_indexes = nil
|
76
|
-
column_names = Array(column_name)
|
77
|
-
index_name = options[:name] || index_name(table_name, :column => options[:index_column] || column_names,
|
78
|
-
# CONEXT index name max length is 25
|
79
|
-
:identifier_max_length => 25)
|
80
|
-
|
81
|
-
quoted_column_name = quote_column_name(options[:index_column] || column_names.first)
|
82
|
-
if options[:index_column_trigger_on]
|
83
|
-
raise ArgumentError, "Option :index_column should be specified together with :index_column_trigger_on option" \
|
84
|
-
unless options[:index_column]
|
85
|
-
create_index_column_trigger(table_name, index_name, options[:index_column], options[:index_column_trigger_on])
|
86
|
-
end
|
87
|
-
|
88
|
-
sql = "CREATE INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
89
|
-
sql << " (#{quoted_column_name})"
|
90
|
-
sql << " INDEXTYPE IS CTXSYS.CONTEXT"
|
91
|
-
parameters = []
|
92
|
-
if column_names.size > 1
|
93
|
-
procedure_name = default_datastore_procedure(index_name)
|
94
|
-
datastore_name = default_datastore_name(index_name)
|
95
|
-
create_datastore_procedure(table_name, procedure_name, column_names, options)
|
96
|
-
create_datastore_preference(datastore_name, procedure_name)
|
97
|
-
parameters << "DATASTORE #{datastore_name} SECTION GROUP CTXSYS.AUTO_SECTION_GROUP"
|
98
|
-
end
|
99
|
-
if options[:tablespace]
|
100
|
-
storage_name = default_storage_name(index_name)
|
101
|
-
create_storage_preference(storage_name, options[:tablespace])
|
102
|
-
parameters << "STORAGE #{storage_name}"
|
103
|
-
end
|
104
|
-
if options[:sync]
|
105
|
-
parameters << "SYNC(#{options[:sync]})"
|
106
|
-
end
|
107
|
-
if options[:lexer] && (lexer_type = options[:lexer][:type])
|
108
|
-
lexer_name = default_lexer_name(index_name)
|
109
|
-
(lexer_options = options[:lexer].dup).delete(:type)
|
110
|
-
create_lexer_preference(lexer_name, lexer_type, lexer_options)
|
111
|
-
parameters << "LEXER #{lexer_name}"
|
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
|
119
|
-
if options[:transactional]
|
120
|
-
parameters << "TRANSACTIONAL"
|
121
|
-
end
|
122
|
-
unless parameters.empty?
|
123
|
-
sql << " PARAMETERS ('#{parameters.join(' ')}')"
|
124
|
-
end
|
125
|
-
execute sql
|
126
|
-
end
|
127
|
-
|
128
|
-
# Drop full text index with Oracle specific CONTEXT index type
|
129
|
-
def remove_context_index(table_name, options = {})
|
130
|
-
self.all_schema_indexes = nil
|
131
|
-
unless Hash === options # if column names passed as argument
|
132
|
-
options = {:column => Array(options)}
|
133
|
-
end
|
134
|
-
index_name = options[:name] || index_name(table_name,
|
135
|
-
:column => options[:index_column] || options[:column], :identifier_max_length => 25)
|
136
|
-
execute "DROP INDEX #{index_name}"
|
137
|
-
drop_ctx_preference(default_datastore_name(index_name))
|
138
|
-
drop_ctx_preference(default_storage_name(index_name))
|
139
|
-
procedure_name = default_datastore_procedure(index_name)
|
140
|
-
execute "DROP PROCEDURE #{quote_table_name(procedure_name)}" rescue nil
|
141
|
-
drop_index_column_trigger(index_name)
|
142
|
-
end
|
143
|
-
|
144
|
-
private
|
145
|
-
|
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
|
-
CREATE OR REPLACE PROCEDURE #{quote_table_name(procedure_name)}
|
154
|
-
(p_rowid IN ROWID,
|
155
|
-
p_clob IN OUT NOCOPY CLOB) IS
|
156
|
-
-- add_context_index_parameters #{(column_names+select_queries).inspect}#{!options.empty? ? ', ' << options.inspect[1..-2] : ''}
|
157
|
-
#{
|
158
|
-
selected_columns.map do |cols|
|
159
|
-
cols.map do |col|
|
160
|
-
raise ArgumentError, "Alias #{col} too large, should be 28 or less characters long" unless col.length <= 28
|
161
|
-
"l_#{col} VARCHAR2(32767);\n"
|
162
|
-
end.join
|
163
|
-
end.join
|
164
|
-
} BEGIN
|
165
|
-
FOR r1 IN (
|
166
|
-
SELECT #{quoted_column_names.join(', ')}
|
167
|
-
FROM #{quoted_table_name}
|
168
|
-
WHERE #{quoted_table_name}.ROWID = p_rowid
|
169
|
-
) LOOP
|
170
|
-
#{
|
171
|
-
(column_names.map do |col|
|
172
|
-
col = col.to_s
|
173
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+2}, '<#{col}>');\n" <<
|
174
|
-
"IF LENGTH(r1.#{col}) > 0 THEN\n" <<
|
175
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, LENGTH(r1.#{col}), r1.#{col});\n" <<
|
176
|
-
"END IF;\n" <<
|
177
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+3}, '</#{col}>');\n"
|
178
|
-
end.join) <<
|
179
|
-
(selected_columns.zip(select_queries).map do |cols, query|
|
180
|
-
(cols.map do |col|
|
181
|
-
"l_#{col} := '';\n"
|
182
|
-
end.join) <<
|
183
|
-
"FOR r2 IN (\n" <<
|
184
|
-
query.gsub(/:(\w+)/,"r1.\\1") << "\n) LOOP\n" <<
|
185
|
-
(cols.map do |col|
|
186
|
-
"l_#{col} := l_#{col} || r2.#{col} || CHR(10);\n"
|
187
|
-
end.join) <<
|
188
|
-
"END LOOP;\n" <<
|
189
|
-
(cols.map do |col|
|
190
|
-
col = col.to_s
|
191
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+2}, '<#{col}>');\n" <<
|
192
|
-
"IF LENGTH(l_#{col}) > 0 THEN\n" <<
|
193
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, LENGTH(l_#{col}), l_#{col});\n" <<
|
194
|
-
"END IF;\n" <<
|
195
|
-
"DBMS_LOB.WRITEAPPEND(p_clob, #{col.length+3}, '</#{col}>');\n"
|
196
|
-
end.join)
|
197
|
-
end.join)
|
198
|
-
}
|
199
|
-
END LOOP;
|
200
|
-
END;
|
201
|
-
SQL
|
202
|
-
end
|
203
|
-
|
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]
|
214
|
-
end
|
215
|
-
|
216
|
-
def create_datastore_preference(datastore_name, procedure_name)
|
217
|
-
drop_ctx_preference(datastore_name)
|
218
|
-
execute <<-SQL
|
219
|
-
BEGIN
|
220
|
-
CTX_DDL.CREATE_PREFERENCE('#{datastore_name}', 'USER_DATASTORE');
|
221
|
-
CTX_DDL.SET_ATTRIBUTE('#{datastore_name}', 'PROCEDURE', '#{procedure_name}');
|
222
|
-
END;
|
223
|
-
SQL
|
224
|
-
end
|
225
|
-
|
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"
|
237
|
-
end
|
238
|
-
sql << "END;\n"
|
239
|
-
execute sql
|
240
|
-
end
|
241
|
-
|
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"
|
254
|
-
end
|
255
|
-
sql << "END;\n"
|
256
|
-
execute sql
|
257
|
-
end
|
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
|
-
|
276
|
-
def drop_ctx_preference(preference_name)
|
277
|
-
execute "BEGIN CTX_DDL.DROP_PREFERENCE('#{preference_name}'); END;" rescue nil
|
278
|
-
end
|
279
|
-
|
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
|
-
CREATE OR REPLACE TRIGGER #{quote_table_name(trigger_name)}
|
286
|
-
BEFORE UPDATE OF #{quoted_column_names} ON #{quote_table_name(table_name)} FOR EACH ROW
|
287
|
-
BEGIN
|
288
|
-
:new.#{quote_column_name(index_column)} := '1';
|
289
|
-
END;
|
290
|
-
SQL
|
291
|
-
end
|
292
|
-
|
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
|
-
|
298
|
-
def default_datastore_procedure(index_name)
|
299
|
-
"#{index_name}_prc"
|
300
|
-
end
|
301
|
-
|
302
|
-
def default_datastore_name(index_name)
|
303
|
-
"#{index_name}_dst"
|
304
|
-
end
|
305
|
-
|
306
|
-
def default_storage_name(index_name)
|
307
|
-
"#{index_name}_sto"
|
308
|
-
end
|
309
|
-
|
310
|
-
def default_index_column_trigger_name(index_name)
|
311
|
-
"#{index_name}_trg"
|
312
|
-
end
|
313
|
-
|
314
|
-
def default_lexer_name(index_name)
|
315
|
-
"#{index_name}_lex"
|
316
|
-
end
|
317
|
-
|
318
|
-
def default_wordlist_name(index_name)
|
319
|
-
"#{index_name}_wl"
|
320
|
-
end
|
321
|
-
|
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
|
328
|
-
end
|
329
|
-
|
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_column_name(column)}, ?, #{score_label}) > 0", query).
|
335
|
-
order("SCORE(#{score_label}) DESC")
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
end
|
340
|
-
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
|
345
|
-
include ActiveRecord::ConnectionAdapters::OracleEnhancedContextIndex
|
346
|
-
end
|
347
|
-
|
348
|
-
ActiveRecord::Base.class_eval do
|
349
|
-
extend ActiveRecord::ConnectionAdapters::OracleEnhancedContextIndex::BaseClassMethods
|
350
|
-
end
|