sequel 4.23.0 → 4.24.0
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/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
|