activerecord-oracle_enhanced-adapter 1.1.7 → 1.1.8
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/History.txt +14 -0
- data/lib/active_record/connection_adapters/oracle_enhanced.rake +4 -4
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +65 -7
- data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +2 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +121 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +25 -1
- data/spec/spec_helper.rb +3 -3
- metadata +13 -4
data/History.txt
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
== 1.1.8 2008-10-10
|
2
|
+
|
3
|
+
* Bug fixes:
|
4
|
+
* Fixed storing of serialized LOB columns
|
5
|
+
* Prevent from SQL injection in :limit and :offset
|
6
|
+
* Order by LOB columns (by replacing column with function which returns first 100 characters of LOB)
|
7
|
+
* Sequence creation for tables with non-default primary key in create_table block
|
8
|
+
* Do count distinct workaround only when composite_primary_keys gem is used
|
9
|
+
(otherwise count distinct did not work with ActiveRecord 2.1.1)
|
10
|
+
* Fixed rake db:test:clone_structure task
|
11
|
+
(see http://rsim.lighthouseapp.com/projects/11468/tickets/11-rake-dbtestclone_structure-fails-in-117)
|
12
|
+
* Fixed bug when ActiveRecord::Base.allow_concurrency = true
|
13
|
+
(see http://dev.rubyonrails.org/ticket/11134)
|
14
|
+
|
1
15
|
== 1.1.7 2008-08-20
|
2
16
|
|
3
17
|
* Bug fixes:
|
@@ -27,16 +27,16 @@ namespace :db do
|
|
27
27
|
redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
|
28
28
|
abcs = ActiveRecord::Base.configurations
|
29
29
|
ActiveRecord::Base.establish_connection(:test)
|
30
|
-
IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split("
|
31
|
-
ActiveRecord::Base.connection.execute(ddl)
|
30
|
+
IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split("\n\n").each do |ddl|
|
31
|
+
ActiveRecord::Base.connection.execute(ddl.chop)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
redefine_task :purge => :environment do
|
36
36
|
abcs = ActiveRecord::Base.configurations
|
37
37
|
ActiveRecord::Base.establish_connection(:test)
|
38
|
-
ActiveRecord::Base.connection.structure_drop.split("
|
39
|
-
ActiveRecord::Base.connection.execute(ddl)
|
38
|
+
ActiveRecord::Base.connection.structure_drop.split("\n\n").each do |ddl|
|
39
|
+
ActiveRecord::Base.connection.execute(ddl.chop)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -81,8 +81,32 @@ begin
|
|
81
81
|
connection.write_lobs(self.class.table_name, self.class, attributes)
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
85
84
|
private :enhanced_write_lobs
|
85
|
+
|
86
|
+
class << self
|
87
|
+
# RSI: patch ORDER BY to work with LOBs
|
88
|
+
def add_order_with_lobs!(sql, order, scope = :auto)
|
89
|
+
if connection.is_a?(ConnectionAdapters::OracleEnhancedAdapter)
|
90
|
+
order = connection.lob_order_by_expression(self, order) if order
|
91
|
+
|
92
|
+
orig_scope = scope
|
93
|
+
scope = scope(:find) if :auto == scope
|
94
|
+
if scope
|
95
|
+
new_scope_order = connection.lob_order_by_expression(self, scope[:order])
|
96
|
+
if new_scope_order != scope[:order]
|
97
|
+
scope = scope.merge(:order => new_scope_order)
|
98
|
+
else
|
99
|
+
scope = orig_scope
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
add_order_without_lobs!(sql, order, scope = :auto)
|
104
|
+
end
|
105
|
+
private :add_order_with_lobs!
|
106
|
+
alias_method :add_order_without_lobs!, :add_order!
|
107
|
+
alias_method :add_order!, :add_order_with_lobs!
|
108
|
+
end
|
109
|
+
|
86
110
|
end
|
87
111
|
|
88
112
|
|
@@ -425,9 +449,11 @@ begin
|
|
425
449
|
end
|
426
450
|
|
427
451
|
def add_limit_offset!(sql, options) #:nodoc:
|
428
|
-
|
452
|
+
# RSI: added to_i for limit and offset to protect from SQL injection
|
453
|
+
offset = (options[:offset] || 0).to_i
|
429
454
|
|
430
455
|
if limit = options[:limit]
|
456
|
+
limit = limit.to_i
|
431
457
|
sql.replace "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_ where rownum <= #{offset+limit}) where raw_rnum_ > #{offset}"
|
432
458
|
elsif offset > 0
|
433
459
|
sql.replace "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_) where raw_rnum_ > #{offset}"
|
@@ -460,8 +486,9 @@ begin
|
|
460
486
|
id = quote(attributes[klass.primary_key])
|
461
487
|
klass.columns.select { |col| col.sql_type =~ /LOB$/i }.each do |col|
|
462
488
|
value = attributes[col.name]
|
463
|
-
|
489
|
+
# RSI: changed sequence of next two lines - should check if value is nil before converting to yaml
|
464
490
|
next if value.nil? || (value == '')
|
491
|
+
value = value.to_yaml if col.text? && klass.serialized_attributes[col.name]
|
465
492
|
uncached do
|
466
493
|
lob = select_one("SELECT #{col.name} FROM #{table_name} WHERE #{klass.primary_key} = #{id} FOR UPDATE",
|
467
494
|
'Writable Large Object')[col.name]
|
@@ -470,6 +497,22 @@ begin
|
|
470
497
|
end
|
471
498
|
end
|
472
499
|
|
500
|
+
# RSI: change LOB column for ORDER BY clause
|
501
|
+
# just first 100 characters are taken for ordering
|
502
|
+
def lob_order_by_expression(klass, order)
|
503
|
+
return order if order.nil?
|
504
|
+
changed = false
|
505
|
+
new_order = order.to_s.strip.split(/, */).map do |order_by_col|
|
506
|
+
column_name, asc_desc = order_by_col.split(/ +/)
|
507
|
+
if column = klass.columns.detect { |col| col.name == column_name && col.sql_type =~ /LOB$/i}
|
508
|
+
changed = true
|
509
|
+
"DBMS_LOB.SUBSTR(#{column_name},100,1) #{asc_desc}"
|
510
|
+
else
|
511
|
+
order_by_col
|
512
|
+
end
|
513
|
+
end.join(', ')
|
514
|
+
changed ? new_order : order
|
515
|
+
end
|
473
516
|
|
474
517
|
# SCHEMA STATEMENTS ========================================
|
475
518
|
#
|
@@ -590,10 +633,25 @@ begin
|
|
590
633
|
end
|
591
634
|
end
|
592
635
|
|
593
|
-
def create_table(name, options = {}) #:nodoc:
|
594
|
-
|
636
|
+
def create_table(name, options = {}, &block) #:nodoc:
|
637
|
+
create_sequence = options[:id] != false
|
638
|
+
if create_sequence
|
639
|
+
super(name, options, &block)
|
640
|
+
else
|
641
|
+
super(name, options) do |t|
|
642
|
+
class <<t
|
643
|
+
attr_accessor :create_sequence
|
644
|
+
def primary_key(*args)
|
645
|
+
self.create_sequence = true
|
646
|
+
super(*args)
|
647
|
+
end
|
648
|
+
end
|
649
|
+
result = block.call(t)
|
650
|
+
create_sequence = t.create_sequence
|
651
|
+
end
|
652
|
+
end
|
595
653
|
seq_name = options[:sequence_name] || "#{name}_seq"
|
596
|
-
execute "CREATE SEQUENCE #{seq_name} START WITH 10000"
|
654
|
+
execute "CREATE SEQUENCE #{seq_name} START WITH 10000" if create_sequence
|
597
655
|
end
|
598
656
|
|
599
657
|
def rename_table(name, new_name) #:nodoc:
|
@@ -836,7 +894,7 @@ begin
|
|
836
894
|
def describe(name)
|
837
895
|
@desc ||= @@env.alloc(OCIDescribe)
|
838
896
|
@desc.attrSet(OCI_ATTR_DESC_PUBLIC, -1) if VERSION >= '0.1.14'
|
839
|
-
@desc.describeAny(@svc, name.to_s, OCI_PTYPE_UNK) rescue raise %Q{"DESC #{name}" failed; does it exist?}
|
897
|
+
do_ocicall(@ctx) { @desc.describeAny(@svc, name.to_s, OCI_PTYPE_UNK) } rescue raise %Q{"DESC #{name}" failed; does it exist?}
|
840
898
|
info = @desc.attrGet(OCI_ATTR_PARAM)
|
841
899
|
|
842
900
|
case info.attrGet(OCI_ATTR_PTYPE)
|
@@ -3,8 +3,9 @@ module ActiveRecord #:nodoc:
|
|
3
3
|
module OracleEnhancedCpk #:nodoc:
|
4
4
|
|
5
5
|
# This mightn't be in Core, but count(distinct x,y) doesn't work for me
|
6
|
+
# RSI: return that not supported if composite_primary_keys gem is required
|
6
7
|
def supports_count_distinct? #:nodoc:
|
7
|
-
|
8
|
+
@supports_count_distinct ||= ! defined?(CompositePrimaryKeys)
|
8
9
|
end
|
9
10
|
|
10
11
|
def concat(*columns)
|
@@ -976,3 +976,124 @@ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
|
|
976
976
|
end
|
977
977
|
|
978
978
|
end
|
979
|
+
|
980
|
+
describe "OracleEnhancedAdapter handling of CLOB columns" do
|
981
|
+
before(:all) do
|
982
|
+
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
983
|
+
:database => "xe",
|
984
|
+
:username => "hr",
|
985
|
+
:password => "hr")
|
986
|
+
@conn = ActiveRecord::Base.connection
|
987
|
+
@conn.execute <<-SQL
|
988
|
+
CREATE TABLE test_employees (
|
989
|
+
employee_id NUMBER(6,0),
|
990
|
+
first_name VARCHAR2(20),
|
991
|
+
last_name VARCHAR2(25),
|
992
|
+
comments CLOB
|
993
|
+
)
|
994
|
+
SQL
|
995
|
+
@conn.execute <<-SQL
|
996
|
+
CREATE SEQUENCE test_employees_seq MINVALUE 1
|
997
|
+
INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
|
998
|
+
SQL
|
999
|
+
class TestEmployee < ActiveRecord::Base
|
1000
|
+
set_primary_key :employee_id
|
1001
|
+
end
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
after(:all) do
|
1005
|
+
Object.send(:remove_const, "TestEmployee")
|
1006
|
+
@conn.execute "DROP TABLE test_employees"
|
1007
|
+
@conn.execute "DROP SEQUENCE test_employees_seq"
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
before(:each) do
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
it "should create record without CLOB data when attribute is serialized" do
|
1014
|
+
TestEmployee.serialize :comments
|
1015
|
+
@employee = TestEmployee.create!(
|
1016
|
+
:first_name => "First",
|
1017
|
+
:last_name => "Last"
|
1018
|
+
)
|
1019
|
+
@employee.should be_valid
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
it "should order by CLOB column" do
|
1023
|
+
@employee = TestEmployee.create!(
|
1024
|
+
:first_name => "First",
|
1025
|
+
:last_name => "Last",
|
1026
|
+
:comments => "comments"
|
1027
|
+
)
|
1028
|
+
TestEmployee.find(:all, :order => "comments ASC").should_not be_empty
|
1029
|
+
TestEmployee.find(:all, :order => " comments ASC ").should_not be_empty
|
1030
|
+
TestEmployee.find(:all, :order => "comments").should_not be_empty
|
1031
|
+
TestEmployee.find(:all, :order => " comments ").should_not be_empty
|
1032
|
+
TestEmployee.find(:all, :order => :comments).should_not be_empty
|
1033
|
+
TestEmployee.find(:all, :order => " first_name DESC, last_name ASC ").should_not be_empty
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
describe "OracleEnhancedAdapter table and sequence creation with non-default primary key" do
|
1039
|
+
before(:all) do
|
1040
|
+
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
1041
|
+
:database => "xe",
|
1042
|
+
:username => "hr",
|
1043
|
+
:password => "hr")
|
1044
|
+
ActiveRecord::Schema.define do
|
1045
|
+
create_table :keyboards, :force => true, :id => false do |t|
|
1046
|
+
t.primary_key :key_number
|
1047
|
+
t.string :name
|
1048
|
+
end
|
1049
|
+
create_table :id_keyboards, :force => true do |t|
|
1050
|
+
t.string :name
|
1051
|
+
end
|
1052
|
+
end
|
1053
|
+
class Keyboard < ActiveRecord::Base
|
1054
|
+
set_primary_key :key_number
|
1055
|
+
end
|
1056
|
+
class IdKeyboard < ActiveRecord::Base
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
after(:all) do
|
1061
|
+
ActiveRecord::Schema.define do
|
1062
|
+
drop_table :keyboards
|
1063
|
+
drop_table :id_keyboards
|
1064
|
+
end
|
1065
|
+
Object.send(:remove_const, "Keyboard")
|
1066
|
+
Object.send(:remove_const, "IdKeyboard")
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
it "should create sequence for non-default primary key" do
|
1070
|
+
ActiveRecord::Base.connection.next_sequence_value(Keyboard.sequence_name).should_not be_nil
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
it "should create sequence for default primary key" do
|
1074
|
+
ActiveRecord::Base.connection.next_sequence_value(IdKeyboard.sequence_name).should_not be_nil
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
describe "OracleEnhancedAdapter without composite_primary_keys" do
|
1079
|
+
|
1080
|
+
before(:all) do
|
1081
|
+
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
1082
|
+
:database => "xe",
|
1083
|
+
:username => "hr",
|
1084
|
+
:password => "hr")
|
1085
|
+
Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
|
1086
|
+
class Employee < ActiveRecord::Base
|
1087
|
+
set_primary_key :employee_id
|
1088
|
+
end
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
it "should tell ActiveRecord that count distinct is supported" do
|
1092
|
+
ActiveRecord::Base.connection.supports_count_distinct?.should be_true
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
it "should execute correct SQL COUNT DISTINCT statement" do
|
1096
|
+
lambda { Employee.count(:employee_id, :distinct => true) }.should_not raise_error
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
end
|
@@ -3,6 +3,30 @@ require "composite_primary_keys"
|
|
3
3
|
|
4
4
|
describe "OracleEnhancedAdapter composite_primary_keys support" do
|
5
5
|
|
6
|
-
|
6
|
+
before(:all) do
|
7
|
+
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
8
|
+
:database => "xe",
|
9
|
+
:username => "hr",
|
10
|
+
:password => "hr")
|
11
|
+
class JobHistory < ActiveRecord::Base
|
12
|
+
set_table_name "job_history"
|
13
|
+
set_primary_keys :employee_id, :start_date
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
after(:all) do
|
18
|
+
Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
|
19
|
+
Object.send(:remove_const, 'JobHistory') if defined?(JobHistory)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should tell ActiveRecord that count distinct is not supported" do
|
23
|
+
ActiveRecord::Base.connection.supports_count_distinct?.should be_false
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should execute correct SQL COUNT DISTINCT statement on table with composite primary keys" do
|
27
|
+
lambda { JobHistory.count(:distinct => true) }.should_not raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
# Other testing was done based on composite_primary_keys tests
|
7
31
|
|
8
32
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,9 +6,9 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
|
|
6
6
|
# gem 'activerecord', '=2.0.2'
|
7
7
|
# gem 'actionpack', '=2.0.2'
|
8
8
|
# gem 'activesupport', '=2.0.2'
|
9
|
-
gem 'activerecord', '=2.1.
|
10
|
-
gem 'actionpack', '=2.1.
|
11
|
-
gem 'activesupport', '=2.1.
|
9
|
+
gem 'activerecord', '=2.1.1'
|
10
|
+
gem 'actionpack', '=2.1.1'
|
11
|
+
gem 'activesupport', '=2.1.1'
|
12
12
|
require 'activerecord'
|
13
13
|
require 'actionpack'
|
14
14
|
require 'action_controller/session/active_record_store'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-oracle_enhanced-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raimonds Simanovskis
|
@@ -9,10 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-10-10 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.7.0
|
24
|
+
version:
|
16
25
|
description: Oracle enhaced adapter for Active Record
|
17
26
|
email:
|
18
27
|
- raymonds72@gmail.com
|