sequel 4.23.0 → 4.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +26 -0
- data/Rakefile +1 -1
- data/doc/release_notes/4.24.0.txt +99 -0
- data/doc/sql.rdoc +10 -1
- data/lib/sequel/adapters/jdbc.rb +7 -0
- data/lib/sequel/adapters/jdbc/cubrid.rb +1 -1
- data/lib/sequel/adapters/jdbc/db2.rb +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +1 -1
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -2
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +14 -6
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/core.rb +12 -1
- data/lib/sequel/database/connecting.rb +1 -2
- data/lib/sequel/extensions/pg_inet_ops.rb +200 -0
- data/lib/sequel/plugins/association_pks.rb +63 -18
- data/lib/sequel/plugins/auto_validations.rb +43 -9
- data/lib/sequel/plugins/class_table_inheritance.rb +236 -179
- data/lib/sequel/plugins/update_refresh.rb +26 -1
- data/lib/sequel/plugins/validation_helpers.rb +7 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/adapters/postgres_spec.rb +61 -0
- data/spec/core_extensions_spec.rb +5 -1
- data/spec/extensions/association_pks_spec.rb +73 -1
- data/spec/extensions/auto_validations_spec.rb +34 -0
- data/spec/extensions/class_table_inheritance_spec.rb +58 -54
- data/spec/extensions/pg_inet_ops_spec.rb +101 -0
- data/spec/extensions/spec_helper.rb +5 -5
- data/spec/extensions/update_refresh_spec.rb +12 -0
- data/spec/extensions/validation_helpers_spec.rb +7 -0
- data/spec/integration/plugin_test.rb +48 -13
- metadata +6 -4
- data/lib/sequel/adapters/db2.rb +0 -229
- data/lib/sequel/adapters/dbi.rb +0 -102
@@ -0,0 +1,101 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
Sequel.extension :pg_inet_ops
|
4
|
+
|
5
|
+
describe "Sequel::Postgres::InetOp" do
|
6
|
+
before do
|
7
|
+
db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
8
|
+
db.extension :pg_inet
|
9
|
+
@ds = db.dataset
|
10
|
+
@h = Sequel.pg_inet_op(:h)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "#pg_inet should return self" do
|
14
|
+
@h.pg_inet.must_be_same_as(@h)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "Sequel.pg_inet_op should return argument if already an InetOp" do
|
18
|
+
Sequel.pg_inet_op(@h).must_be_same_as(@h)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "#pg_inet should return a InetOp for literal strings, and expressions" do
|
22
|
+
@ds.literal(Sequel.function(:b, :h).pg_inet.abbrev).must_equal "abbrev(b(h))"
|
23
|
+
@ds.literal(Sequel.lit('h').pg_inet.abbrev).must_equal "abbrev(h)"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should define methods for all of the PostgreSQL inet operators" do
|
27
|
+
@ds.literal(@h + @h).must_equal "(h + h)"
|
28
|
+
@ds.literal(@h - @h).must_equal "(h - h)"
|
29
|
+
@ds.literal(@h << @h).must_equal "(h << h)"
|
30
|
+
@ds.literal(@h >> @h).must_equal "(h >> h)"
|
31
|
+
@ds.literal(@h & @h).must_equal "(h & h)"
|
32
|
+
@ds.literal(@h | @h).must_equal "(h | h)"
|
33
|
+
@ds.literal(~@h).must_equal "~h"
|
34
|
+
|
35
|
+
@ds.literal(@h.contained_by(@h)).must_equal "(h << h)"
|
36
|
+
@ds.literal(@h.contained_by_or_equals(@h)).must_equal "(h <<= h)"
|
37
|
+
@ds.literal(@h.contains(@h)).must_equal "(h >> h)"
|
38
|
+
@ds.literal(@h.contains_or_equals(@h)).must_equal "(h >>= h)"
|
39
|
+
@ds.literal(@h.contains_or_contained_by(@h)).must_equal "(h && h)"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should define methods for all of the PostgreSQL inet functions" do
|
43
|
+
@ds.literal(@h.abbrev).must_equal "abbrev(h)"
|
44
|
+
@ds.literal(@h.broadcast).must_equal "broadcast(h)"
|
45
|
+
@ds.literal(@h.family).must_equal "family(h)"
|
46
|
+
@ds.literal(@h.host).must_equal "host(h)"
|
47
|
+
@ds.literal(@h.hostmask).must_equal "hostmask(h)"
|
48
|
+
@ds.literal(@h.masklen).must_equal "masklen(h)"
|
49
|
+
@ds.literal(@h.netmask).must_equal "netmask(h)"
|
50
|
+
@ds.literal(@h.network).must_equal "network(h)"
|
51
|
+
@ds.literal(@h.set_masklen(16)).must_equal "set_masklen(h, 16)"
|
52
|
+
@ds.literal(@h.text).must_equal "text(h)"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should have operators that return booleans return boolean expressions" do
|
56
|
+
@ds.literal((@h << @h) & :b).must_equal "((h << h) AND b)"
|
57
|
+
@ds.literal((@h >> @h) & :b).must_equal "((h >> h) AND b)"
|
58
|
+
|
59
|
+
@ds.literal(@h.contained_by(@h) & :b).must_equal "((h << h) AND b)"
|
60
|
+
@ds.literal(@h.contained_by_or_equals(@h) & :b).must_equal "((h <<= h) AND b)"
|
61
|
+
@ds.literal(@h.contains(@h) & :b).must_equal "((h >> h) AND b)"
|
62
|
+
@ds.literal(@h.contains_or_equals(@h) & :b).must_equal "((h >>= h) AND b)"
|
63
|
+
@ds.literal(@h.contains_or_contained_by(@h) & :b).must_equal "((h && h) AND b)"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should have operators that return inet return InetOp" do
|
67
|
+
@ds.literal((@h & @h).contains(:b)).must_equal "((h & h) >> b)"
|
68
|
+
@ds.literal((@h | @h).contains(:b)).must_equal "((h | h) >> b)"
|
69
|
+
@ds.literal((@h + @h).contains(:b)).must_equal "((h + h) >> b)"
|
70
|
+
@ds.literal((@h - 3).contains(:b)).must_equal "((h - 3) >> b)"
|
71
|
+
@ds.literal((~@h).contains(:b)).must_equal "(~h >> b)"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should have - operator with inet op return numeric expression" do
|
75
|
+
@ds.literal((@h - @h) / :b).must_equal "((h - h) / b)"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should have function methods returning int return numeric expressions" do
|
79
|
+
@ds.literal(@h.family / 2).must_equal "(family(h) / 2)"
|
80
|
+
@ds.literal(@h.masklen / 2).must_equal "(masklen(h) / 2)"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should have function methods returning text return string expressions" do
|
84
|
+
@ds.literal(@h.abbrev + :a).must_equal "(abbrev(h) || a)"
|
85
|
+
@ds.literal(@h.host + :a).must_equal "(host(h) || a)"
|
86
|
+
@ds.literal(@h.text + :a).must_equal "(text(h) || a)"
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should have function methods returning inet return InetOp" do
|
90
|
+
@ds.literal(@h.broadcast.contains(:a)).must_equal "(broadcast(h) >> a)"
|
91
|
+
@ds.literal(@h.hostmask.contains(:a)).must_equal "(hostmask(h) >> a)"
|
92
|
+
@ds.literal(@h.netmask.contains(:a)).must_equal "(netmask(h) >> a)"
|
93
|
+
@ds.literal(@h.network.contains(:a)).must_equal "(network(h) >> a)"
|
94
|
+
@ds.literal(@h.set_masklen(16).contains(:a)).must_equal "(set_masklen(h, 16) >> a)"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should string and IPAddr instances in a cast to inet" do
|
98
|
+
@ds.literal(Sequel.pg_inet_op('1.2.3.4').contains(:a)).must_equal "(CAST('1.2.3.4' AS inet) >> a)"
|
99
|
+
@ds.literal(Sequel.pg_inet_op(IPAddr.new('1.2.3.4')).contains(:a)).must_equal "(CAST('1.2.3.4/32' AS inet) >> a)"
|
100
|
+
end
|
101
|
+
end
|
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
+
gem 'minitest'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'minitest/hooks/default'
|
6
|
+
require 'minitest/shared_description'
|
7
|
+
|
3
8
|
if ENV['COVERAGE']
|
4
9
|
require File.join(File.dirname(File.expand_path(__FILE__)), "../sequel_coverage")
|
5
10
|
SimpleCov.sequel_coverage(:filter=>%r{lib/sequel/(extensions|plugins)/\w+\.rb\z})
|
@@ -29,11 +34,6 @@ def skip_warn(s)
|
|
29
34
|
warn "Skipping test of #{s}" if ENV["SKIPPED_TEST_WARN"]
|
30
35
|
end
|
31
36
|
|
32
|
-
gem 'minitest'
|
33
|
-
require 'minitest/autorun'
|
34
|
-
require 'minitest/hooks/default'
|
35
|
-
require 'minitest/shared_description'
|
36
|
-
|
37
37
|
Sequel.quote_identifiers = false
|
38
38
|
Sequel.identifier_input_method = nil
|
39
39
|
Sequel.identifier_output_method = nil
|
@@ -27,6 +27,18 @@ describe "Sequel::Plugins::UpdateRefresh" do
|
|
27
27
|
o.name.must_equal 'b'
|
28
28
|
end
|
29
29
|
|
30
|
+
it "should support specifying columns to return" do
|
31
|
+
@db.extend_datasets{def supports_returning?(x) true end; def update_sql(*); sql = super; update_returning_sql(sql); sql end}
|
32
|
+
@c.plugin :update_refresh, :columns => [ :a ]
|
33
|
+
@c.dataset = @db[:test]
|
34
|
+
@db.sqls
|
35
|
+
o = @c.load(:id=>1, :name=>'a')
|
36
|
+
o.save
|
37
|
+
@db.sqls.must_equal ["UPDATE test SET name = 'a' WHERE (id = 1) RETURNING a"]
|
38
|
+
o.name.must_equal 'b'
|
39
|
+
end
|
40
|
+
|
41
|
+
|
30
42
|
it "should refresh the instance after updating when returning specific columns" do
|
31
43
|
@db.extend_datasets{def supports_returning?(x) true end; def update_sql(*); sql = super; update_returning_sql(sql); sql end}
|
32
44
|
@c.plugin :insert_returning_select
|
@@ -56,6 +56,13 @@ describe "Sequel::Plugins::ValidationHelpers" do
|
|
56
56
|
@m.must_be :valid?
|
57
57
|
end
|
58
58
|
|
59
|
+
it "should take a :from=>:values option to lookup in values hash" do
|
60
|
+
@c.set_validations{validates_max_length(50, :value, :from=>:values)}
|
61
|
+
@c.send(:define_method, :value){super() * 2}
|
62
|
+
@m.value = ' ' * 26
|
63
|
+
@m.must_be :valid?
|
64
|
+
end
|
65
|
+
|
59
66
|
it "should allow a proc for the :message option" do
|
60
67
|
@c.set_validations{validates_format(/.+_.+/, :value, :message=>proc{|f| "doesn't match #{f.inspect}"})}
|
61
68
|
@m.value = 'abc_'
|
@@ -33,21 +33,27 @@ describe "Class Table Inheritance Plugin" do
|
|
33
33
|
end
|
34
34
|
class ::Executive < Manager
|
35
35
|
end
|
36
|
+
class ::Ceo < Executive
|
37
|
+
end
|
36
38
|
class ::Staff < Employee
|
37
39
|
many_to_one :manager
|
38
40
|
end
|
39
41
|
|
40
|
-
|
42
|
+
|
43
|
+
@i1 = @db[:employees].insert(:name=>'E', :kind=>'Employee')
|
41
44
|
@i2 = @db[:employees].insert(:name=>'S', :kind=>'Staff')
|
42
45
|
@i3 = @db[:employees].insert(:name=>'M', :kind=>'Manager')
|
43
|
-
@i4 = @db[:employees].insert(:name=>'Ex', :kind=>'Executive')
|
44
46
|
@db[:managers].insert(:id=>@i3, :num_staff=>7)
|
47
|
+
@i4 = @db[:employees].insert(:name=>'Ex', :kind=>'Executive')
|
45
48
|
@db[:managers].insert(:id=>@i4, :num_staff=>5)
|
46
49
|
@db[:executives].insert(:id=>@i4, :num_managers=>6)
|
50
|
+
@i5 = @db[:employees].insert(:name=>'C', :kind=>'Ceo')
|
51
|
+
@db[:managers].insert(:id=>@i5, :num_staff=>2)
|
52
|
+
@db[:executives].insert(:id=>@i5, :num_managers=>1)
|
47
53
|
@db[:staff].insert(:id=>@i2, :manager_id=>@i4)
|
48
54
|
end
|
49
55
|
after do
|
50
|
-
[:Executive, :Manager, :Staff, :Employee].each{|s| Object.send(:remove_const, s)}
|
56
|
+
[:Ceo, :Executive, :Manager, :Staff, :Employee].each{|s| Object.send(:remove_const, s)}
|
51
57
|
end
|
52
58
|
after(:all) do
|
53
59
|
@db.drop_table? :staff, :executives, :managers, :employees
|
@@ -58,7 +64,8 @@ describe "Class Table Inheritance Plugin" do
|
|
58
64
|
Employee.load(:id=>@i1, :name=>'E', :kind=>'Employee'),
|
59
65
|
Staff.load(:id=>@i2, :name=>'S', :kind=>'Staff'),
|
60
66
|
Manager.load(:id=>@i3, :name=>'M', :kind=>'Manager'),
|
61
|
-
Executive.load(:id=>@i4, :name=>'Ex', :kind=>'Executive')
|
67
|
+
Executive.load(:id=>@i4, :name=>'Ex', :kind=>'Executive'),
|
68
|
+
Ceo.load(:id=>@i5, :name=>'C', :kind=>'Ceo')
|
62
69
|
]
|
63
70
|
end
|
64
71
|
|
@@ -71,6 +78,8 @@ describe "Class Table Inheritance Plugin" do
|
|
71
78
|
Employee[@i4].num_staff.must_equal 5
|
72
79
|
Employee[@i4][:num_managers].must_equal nil
|
73
80
|
Employee[@i4].num_managers.must_equal 6
|
81
|
+
Employee[@i5][:num_managers].must_equal nil
|
82
|
+
Employee[@i5].num_managers.must_equal 1
|
74
83
|
end
|
75
84
|
|
76
85
|
it "should eagerly load columns in subclass tables when retrieving multiple objects" do
|
@@ -83,6 +92,8 @@ describe "Class Table Inheritance Plugin" do
|
|
83
92
|
a[3].num_staff.must_equal 5
|
84
93
|
a[3][:num_managers].must_equal nil
|
85
94
|
a[3].num_managers.must_equal 6
|
95
|
+
a[4][:num_managers].must_equal 1
|
96
|
+
a[4].num_managers.must_equal 1
|
86
97
|
end
|
87
98
|
|
88
99
|
it "should include schema for columns for tables for ancestor classes" do
|
@@ -90,6 +101,7 @@ describe "Class Table Inheritance Plugin" do
|
|
90
101
|
Staff.db_schema.keys.sort_by{|x| x.to_s}.must_equal [:id, :kind, :manager_id, :name]
|
91
102
|
Manager.db_schema.keys.sort_by{|x| x.to_s}.must_equal [:id, :kind, :name, :num_staff]
|
92
103
|
Executive.db_schema.keys.sort_by{|x| x.to_s}.must_equal [:id, :kind, :name, :num_managers, :num_staff]
|
104
|
+
Ceo.db_schema.keys.sort_by{|x| x.to_s}.must_equal [:id, :kind, :name, :num_managers, :num_staff]
|
93
105
|
end
|
94
106
|
|
95
107
|
it "should include columns for tables for ancestor classes" do
|
@@ -97,10 +109,11 @@ describe "Class Table Inheritance Plugin" do
|
|
97
109
|
Staff.columns.must_equal [:id, :name, :kind, :manager_id]
|
98
110
|
Manager.columns.must_equal [:id, :name, :kind, :num_staff]
|
99
111
|
Executive.columns.must_equal [:id, :name, :kind, :num_staff, :num_managers]
|
112
|
+
Ceo.columns.must_equal [:id, :name, :kind, :num_staff, :num_managers]
|
100
113
|
end
|
101
114
|
|
102
115
|
it "should delete rows from all tables" do
|
103
|
-
e =
|
116
|
+
e = Ceo.first
|
104
117
|
i = e.id
|
105
118
|
e.staff_members_dataset.destroy
|
106
119
|
e.destroy
|
@@ -114,9 +127,9 @@ describe "Class Table Inheritance Plugin" do
|
|
114
127
|
end
|
115
128
|
|
116
129
|
it "should insert rows into all tables" do
|
117
|
-
e =
|
130
|
+
e = Ceo.create(:name=>'Ex2', :num_managers=>8, :num_staff=>9)
|
118
131
|
i = e.id
|
119
|
-
@db[:employees][:id=>i].must_equal(:id=>i, :name=>'Ex2', :kind=>'
|
132
|
+
@db[:employees][:id=>i].must_equal(:id=>i, :name=>'Ex2', :kind=>'Ceo')
|
120
133
|
@db[:managers][:id=>i].must_equal(:id=>i, :num_staff=>9)
|
121
134
|
@db[:executives][:id=>i].must_equal(:id=>i, :num_managers=>8)
|
122
135
|
end
|
@@ -1280,20 +1293,42 @@ describe "AssociationPks plugin" do
|
|
1280
1293
|
Vocalist.order(:first, :last).all.map{|a| a.hit_pks.sort}.must_equal [[@h1, @h2, @h3], [@h2], []]
|
1281
1294
|
end
|
1282
1295
|
|
1296
|
+
it "should handle :delay association option for new instances" do
|
1297
|
+
album_class = Class.new(Album)
|
1298
|
+
album_class.many_to_many :tags, :clone=>:tags, :delay_pks=>true, :join_table=>:albums_tags, :left_key=>:album_id
|
1299
|
+
album = album_class.new(:name=>'test album')
|
1300
|
+
album.tag_pks.must_equal []
|
1301
|
+
album.tag_pks = [@t1, @t2]
|
1302
|
+
album.tag_pks.must_equal [@t1, @t2]
|
1303
|
+
album.save
|
1304
|
+
album_class.with_pk!(album.pk).tag_pks.sort.must_equal [@t1, @t2]
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
it "should handle :delay=>:all association option for existing instances" do
|
1308
|
+
album_class = Class.new(Album)
|
1309
|
+
album_class.many_to_many :tags, :clone=>:tags, :delay_pks=>:always, :join_table=>:albums_tags, :left_key=>:album_id
|
1310
|
+
album = album_class.with_pk!(@al1)
|
1311
|
+
album.tag_pks.sort.must_equal [@t1, @t2, @t3]
|
1312
|
+
album.tag_pks = [@t1, @t2]
|
1313
|
+
album.tag_pks.must_equal [@t1, @t2]
|
1314
|
+
album.save_changes
|
1315
|
+
album_class.with_pk!(album.pk).tag_pks.sort.must_equal [@t1, @t2]
|
1316
|
+
end
|
1317
|
+
|
1283
1318
|
it "should set associated pks correctly for a one_to_many association" do
|
1284
1319
|
Artist.use_transactions = true
|
1285
1320
|
Album.order(:id).select_map(:artist_id).must_equal [@ar1, @ar1, @ar1]
|
1286
1321
|
|
1287
|
-
Artist[@ar2].album_pks = [@
|
1288
|
-
Artist[@ar1].album_pks.must_equal [@
|
1322
|
+
Artist[@ar2].album_pks = [@al1, @al3]
|
1323
|
+
Artist[@ar1].album_pks.must_equal [@al2]
|
1289
1324
|
Album.order(:id).select_map(:artist_id).must_equal [@ar2, @ar1, @ar2]
|
1290
1325
|
|
1291
|
-
Artist[@ar1].album_pks = [@
|
1292
|
-
Artist[@ar2].album_pks.must_equal [@
|
1326
|
+
Artist[@ar1].album_pks = [@al1]
|
1327
|
+
Artist[@ar2].album_pks.must_equal [@al3]
|
1293
1328
|
Album.order(:id).select_map(:artist_id).must_equal [@ar1, nil, @ar2]
|
1294
1329
|
|
1295
|
-
Artist[@ar1].album_pks = [@
|
1296
|
-
Artist[@ar2].album_pks.must_equal [@
|
1330
|
+
Artist[@ar1].album_pks = [@al1, @al2]
|
1331
|
+
Artist[@ar2].album_pks.must_equal [@al3]
|
1297
1332
|
Album.order(:id).select_map(:artist_id).must_equal [@ar1, @ar1, @ar2]
|
1298
1333
|
end
|
1299
1334
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.24.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -224,6 +224,7 @@ extra_rdoc_files:
|
|
224
224
|
- doc/release_notes/4.21.0.txt
|
225
225
|
- doc/release_notes/4.22.0.txt
|
226
226
|
- doc/release_notes/4.23.0.txt
|
227
|
+
- doc/release_notes/4.24.0.txt
|
227
228
|
files:
|
228
229
|
- CHANGELOG
|
229
230
|
- MIT-LICENSE
|
@@ -335,6 +336,7 @@ files:
|
|
335
336
|
- doc/release_notes/4.21.0.txt
|
336
337
|
- doc/release_notes/4.22.0.txt
|
337
338
|
- doc/release_notes/4.23.0.txt
|
339
|
+
- doc/release_notes/4.24.0.txt
|
338
340
|
- doc/release_notes/4.3.0.txt
|
339
341
|
- doc/release_notes/4.4.0.txt
|
340
342
|
- doc/release_notes/4.5.0.txt
|
@@ -357,8 +359,6 @@ files:
|
|
357
359
|
- lib/sequel/adapters/ado/mssql.rb
|
358
360
|
- lib/sequel/adapters/amalgalite.rb
|
359
361
|
- lib/sequel/adapters/cubrid.rb
|
360
|
-
- lib/sequel/adapters/db2.rb
|
361
|
-
- lib/sequel/adapters/dbi.rb
|
362
362
|
- lib/sequel/adapters/do.rb
|
363
363
|
- lib/sequel/adapters/do/mysql.rb
|
364
364
|
- lib/sequel/adapters/do/postgres.rb
|
@@ -483,6 +483,7 @@ files:
|
|
483
483
|
- lib/sequel/extensions/pg_hstore.rb
|
484
484
|
- lib/sequel/extensions/pg_hstore_ops.rb
|
485
485
|
- lib/sequel/extensions/pg_inet.rb
|
486
|
+
- lib/sequel/extensions/pg_inet_ops.rb
|
486
487
|
- lib/sequel/extensions/pg_interval.rb
|
487
488
|
- lib/sequel/extensions/pg_json.rb
|
488
489
|
- lib/sequel/extensions/pg_json_ops.rb
|
@@ -681,6 +682,7 @@ files:
|
|
681
682
|
- spec/extensions/pg_enum_spec.rb
|
682
683
|
- spec/extensions/pg_hstore_ops_spec.rb
|
683
684
|
- spec/extensions/pg_hstore_spec.rb
|
685
|
+
- spec/extensions/pg_inet_ops_spec.rb
|
684
686
|
- spec/extensions/pg_inet_spec.rb
|
685
687
|
- spec/extensions/pg_interval_spec.rb
|
686
688
|
- spec/extensions/pg_json_ops_spec.rb
|
data/lib/sequel/adapters/db2.rb
DELETED
@@ -1,229 +0,0 @@
|
|
1
|
-
require 'db2/db2cli'
|
2
|
-
Sequel.require %w'shared/db2', 'adapters'
|
3
|
-
Sequel::Deprecation.deprecate 'The db2 adapter is deprecated and will be removed in a future version of Sequel. Please switch to the ibmdb adapter.'
|
4
|
-
|
5
|
-
module Sequel
|
6
|
-
module DB2
|
7
|
-
|
8
|
-
@convert_smallint_to_bool = true
|
9
|
-
|
10
|
-
# Underlying error raised by Sequel, since ruby-db2 doesn't
|
11
|
-
# use exceptions.
|
12
|
-
class DB2Error < StandardError
|
13
|
-
end
|
14
|
-
|
15
|
-
class << self
|
16
|
-
# Whether to convert smallint values to bool, true by default.
|
17
|
-
# Can also be overridden per dataset.
|
18
|
-
attr_accessor :convert_smallint_to_bool
|
19
|
-
end
|
20
|
-
|
21
|
-
tt = Class.new do
|
22
|
-
def boolean(s) !s.to_i.zero? end
|
23
|
-
def date(s) Date.new(s.year, s.month, s.day) end
|
24
|
-
def time(s) Sequel::SQLTime.create(s.hour, s.minute, s.second) end
|
25
|
-
end.new
|
26
|
-
|
27
|
-
# Hash holding type translation methods, used by Dataset#fetch_rows.
|
28
|
-
DB2_TYPES = {
|
29
|
-
:boolean => tt.method(:boolean),
|
30
|
-
DB2CLI::SQL_BLOB => ::Sequel::SQL::Blob.method(:new),
|
31
|
-
DB2CLI::SQL_TYPE_DATE => tt.method(:date),
|
32
|
-
DB2CLI::SQL_TYPE_TIME => tt.method(:time),
|
33
|
-
DB2CLI::SQL_DECIMAL => ::BigDecimal.method(:new)
|
34
|
-
}
|
35
|
-
|
36
|
-
class Database < Sequel::Database
|
37
|
-
include DatabaseMethods
|
38
|
-
|
39
|
-
set_adapter_scheme :db2
|
40
|
-
|
41
|
-
TEMPORARY = 'GLOBAL TEMPORARY '.freeze
|
42
|
-
_, NullHandle = DB2CLI.SQLAllocHandle(DB2CLI::SQL_HANDLE_ENV, DB2CLI::SQL_NULL_HANDLE)
|
43
|
-
|
44
|
-
# Hash of connection procs for converting
|
45
|
-
attr_reader :conversion_procs
|
46
|
-
|
47
|
-
def connect(server)
|
48
|
-
opts = server_opts(server)
|
49
|
-
dbc = checked_error("Could not allocate database connection"){DB2CLI.SQLAllocHandle(DB2CLI::SQL_HANDLE_DBC, NullHandle)}
|
50
|
-
checked_error("Could not connect to database"){DB2CLI.SQLConnect(dbc, opts[:database], opts[:user], opts[:password])}
|
51
|
-
dbc
|
52
|
-
end
|
53
|
-
|
54
|
-
def disconnect_connection(conn)
|
55
|
-
DB2CLI.SQLDisconnect(conn)
|
56
|
-
DB2CLI.SQLFreeHandle(DB2CLI::SQL_HANDLE_DBC, conn)
|
57
|
-
end
|
58
|
-
|
59
|
-
def execute(sql, opts=OPTS, &block)
|
60
|
-
synchronize(opts[:server]){|conn| log_connection_execute(conn, sql, &block)}
|
61
|
-
end
|
62
|
-
|
63
|
-
def execute_insert(sql, opts=OPTS)
|
64
|
-
synchronize(opts[:server]) do |conn|
|
65
|
-
log_connection_execute(conn, sql)
|
66
|
-
sql = "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1"
|
67
|
-
log_connection_execute(conn, sql) do |sth|
|
68
|
-
_, _, datatype, size, _, _ = checked_error("Could not describe column"){DB2CLI.SQLDescribeCol(sth, 1, 256)}
|
69
|
-
if DB2CLI.SQLFetch(sth) != DB2CLI::SQL_NO_DATA_FOUND
|
70
|
-
v, _ = checked_error("Could not get data"){DB2CLI.SQLGetData(sth, 1, datatype, size)}
|
71
|
-
if v.is_a?(String)
|
72
|
-
return v.to_i
|
73
|
-
else
|
74
|
-
return nil
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
ERROR_MAP = {}
|
82
|
-
%w'SQL_INVALID_HANDLE SQL_STILL_EXECUTING SQL_ERROR'.each do |s|
|
83
|
-
ERROR_MAP[DB2CLI.const_get(s)] = s
|
84
|
-
end
|
85
|
-
def check_error(rc, msg)
|
86
|
-
case rc
|
87
|
-
when DB2CLI::SQL_SUCCESS, DB2CLI::SQL_SUCCESS_WITH_INFO, DB2CLI::SQL_NO_DATA_FOUND
|
88
|
-
nil
|
89
|
-
when DB2CLI::SQL_INVALID_HANDLE, DB2CLI::SQL_STILL_EXECUTING
|
90
|
-
e = DB2Error.new("#{ERROR_MAP[rc]}: #{msg}")
|
91
|
-
e.set_backtrace(caller)
|
92
|
-
raise_error(e, :disconnect=>true)
|
93
|
-
else
|
94
|
-
e = DB2Error.new("#{ERROR_MAP[rc] || "Error code #{rc}"}: #{msg}")
|
95
|
-
e.set_backtrace(caller)
|
96
|
-
raise_error(e, :disconnect=>true)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def checked_error(msg)
|
101
|
-
rc, *ary= yield
|
102
|
-
check_error(rc, msg)
|
103
|
-
ary.length <= 1 ? ary.first : ary
|
104
|
-
end
|
105
|
-
|
106
|
-
def to_application_timestamp_db2(v)
|
107
|
-
to_application_timestamp(v.to_s)
|
108
|
-
end
|
109
|
-
|
110
|
-
private
|
111
|
-
|
112
|
-
def adapter_initialize
|
113
|
-
@conversion_procs = DB2_TYPES.dup
|
114
|
-
@conversion_procs[DB2CLI::SQL_TYPE_TIMESTAMP] = method(:to_application_timestamp_db2)
|
115
|
-
end
|
116
|
-
|
117
|
-
def database_error_classes
|
118
|
-
[DB2Error]
|
119
|
-
end
|
120
|
-
|
121
|
-
def begin_transaction(conn, opts=OPTS)
|
122
|
-
log_yield(TRANSACTION_BEGIN){DB2CLI.SQLSetConnectAttr(conn, DB2CLI::SQL_ATTR_AUTOCOMMIT, DB2CLI::SQL_AUTOCOMMIT_OFF)}
|
123
|
-
set_transaction_isolation(conn, opts)
|
124
|
-
end
|
125
|
-
|
126
|
-
def remove_transaction(conn, committed)
|
127
|
-
DB2CLI.SQLSetConnectAttr(conn, DB2CLI::SQL_ATTR_AUTOCOMMIT, DB2CLI::SQL_AUTOCOMMIT_ON)
|
128
|
-
ensure
|
129
|
-
super
|
130
|
-
end
|
131
|
-
|
132
|
-
def rollback_transaction(conn, opts=OPTS)
|
133
|
-
log_yield(TRANSACTION_ROLLBACK){DB2CLI.SQLEndTran(DB2CLI::SQL_HANDLE_DBC, conn, DB2CLI::SQL_ROLLBACK)}
|
134
|
-
end
|
135
|
-
|
136
|
-
def commit_transaction(conn, opts=OPTS)
|
137
|
-
log_yield(TRANSACTION_COMMIT){DB2CLI.SQLEndTran(DB2CLI::SQL_HANDLE_DBC, conn, DB2CLI::SQL_COMMIT)}
|
138
|
-
end
|
139
|
-
|
140
|
-
def log_connection_execute(conn, sql)
|
141
|
-
sth = checked_error("Could not allocate statement"){DB2CLI.SQLAllocHandle(DB2CLI::SQL_HANDLE_STMT, conn)}
|
142
|
-
|
143
|
-
begin
|
144
|
-
checked_error("Could not execute statement: #{sql}"){log_yield(sql){DB2CLI.SQLExecDirect(sth, sql)}}
|
145
|
-
|
146
|
-
if block_given?
|
147
|
-
yield(sth)
|
148
|
-
else
|
149
|
-
checked_error("Could not get RPC"){DB2CLI.SQLRowCount(sth)}
|
150
|
-
end
|
151
|
-
ensure
|
152
|
-
checked_error("Could not free statement"){DB2CLI.SQLFreeHandle(DB2CLI::SQL_HANDLE_STMT, sth)}
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
# Convert smallint type to boolean if convert_smallint_to_bool is true
|
157
|
-
def schema_column_type(db_type)
|
158
|
-
if DB2.convert_smallint_to_bool && db_type =~ /smallint/i
|
159
|
-
:boolean
|
160
|
-
else
|
161
|
-
super
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
class Dataset < Sequel::Dataset
|
167
|
-
include DatasetMethods
|
168
|
-
|
169
|
-
Database::DatasetClass = self
|
170
|
-
MAX_COL_SIZE = 256
|
171
|
-
|
172
|
-
# Whether to convert smallint to boolean arguments for this dataset.
|
173
|
-
# Defaults to the DB2 module setting.
|
174
|
-
def convert_smallint_to_bool
|
175
|
-
defined?(@convert_smallint_to_bool) ? @convert_smallint_to_bool : (@convert_smallint_to_bool = DB2.convert_smallint_to_bool)
|
176
|
-
end
|
177
|
-
|
178
|
-
# Override the default DB2.convert_smallint_to_bool setting for this dataset.
|
179
|
-
attr_writer :convert_smallint_to_bool
|
180
|
-
|
181
|
-
def fetch_rows(sql)
|
182
|
-
execute(sql) do |sth|
|
183
|
-
db = @db
|
184
|
-
column_info = get_column_info(sth)
|
185
|
-
cols = column_info.map{|c| c.at(1)}
|
186
|
-
@columns = cols
|
187
|
-
errors = [DB2CLI::SQL_NO_DATA_FOUND, DB2CLI::SQL_ERROR]
|
188
|
-
until errors.include?(rc = DB2CLI.SQLFetch(sth))
|
189
|
-
db.check_error(rc, "Could not fetch row")
|
190
|
-
row = {}
|
191
|
-
column_info.each do |i, c, t, s, pr|
|
192
|
-
v, _ = db.checked_error("Could not get data"){DB2CLI.SQLGetData(sth, i, t, s)}
|
193
|
-
row[c] = if v == DB2CLI::Null
|
194
|
-
nil
|
195
|
-
elsif pr
|
196
|
-
pr.call(v)
|
197
|
-
else
|
198
|
-
v
|
199
|
-
end
|
200
|
-
end
|
201
|
-
yield row
|
202
|
-
end
|
203
|
-
end
|
204
|
-
self
|
205
|
-
end
|
206
|
-
|
207
|
-
private
|
208
|
-
|
209
|
-
def get_column_info(sth)
|
210
|
-
db = @db
|
211
|
-
column_count = db.checked_error("Could not get number of result columns"){DB2CLI.SQLNumResultCols(sth)}
|
212
|
-
convert = convert_smallint_to_bool
|
213
|
-
cps = db.conversion_procs
|
214
|
-
|
215
|
-
(1..column_count).map do |i|
|
216
|
-
name, _, datatype, size, digits, _ = db.checked_error("Could not describe column"){DB2CLI.SQLDescribeCol(sth, i, MAX_COL_SIZE)}
|
217
|
-
pr = if datatype == DB2CLI::SQL_SMALLINT && convert && size <= 5 && digits <= 1
|
218
|
-
cps[:boolean]
|
219
|
-
elsif datatype == DB2CLI::SQL_CLOB && Sequel::DB2.use_clob_as_blob
|
220
|
-
cps[DB2CLI::SQL_BLOB]
|
221
|
-
else
|
222
|
-
cps[datatype]
|
223
|
-
end
|
224
|
-
[i, output_identifier(name), datatype, size, pr]
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|