activerecord-oracle_enhanced-adapter 1.1.7 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|