sequel 3.20.0 → 3.21.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +32 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/Rakefile +13 -3
- data/bin/sequel +18 -5
- data/doc/active_record.rdoc +4 -4
- data/doc/opening_databases.rdoc +38 -1
- data/doc/release_notes/3.21.0.txt +87 -0
- data/doc/validations.rdoc +2 -2
- data/lib/sequel/adapters/informix.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +2 -5
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -4
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -4
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -6
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -8
- data/lib/sequel/adapters/shared/mssql.rb +8 -0
- data/lib/sequel/adapters/shared/mysql.rb +23 -3
- data/lib/sequel/adapters/shared/oracle.rb +2 -2
- data/lib/sequel/adapters/tinytds.rb +125 -0
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +37 -5
- data/lib/sequel/dataset/sql.rb +6 -6
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/model/base.rb +50 -0
- data/lib/sequel/model/plugins.rb +0 -55
- data/lib/sequel/plugins/association_autoreloading.rb +48 -0
- data/lib/sequel/plugins/validation_class_methods.rb +6 -5
- data/lib/sequel/plugins/validation_helpers.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +6 -6
- data/spec/adapters/informix_spec.rb +2 -2
- data/spec/adapters/mssql_spec.rb +18 -13
- data/spec/adapters/mysql_spec.rb +47 -20
- data/spec/adapters/oracle_spec.rb +40 -4
- data/spec/adapters/postgres_spec.rb +14 -14
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +8 -8
- data/spec/core/connection_pool_spec.rb +18 -17
- data/spec/core/core_sql_spec.rb +18 -18
- data/spec/core/database_spec.rb +62 -62
- data/spec/core/dataset_spec.rb +105 -92
- data/spec/core/expression_filters_spec.rb +2 -2
- data/spec/core/schema_spec.rb +6 -6
- data/spec/core/version_spec.rb +1 -1
- data/spec/extensions/association_autoreloading_spec.rb +94 -0
- data/spec/extensions/blank_spec.rb +6 -6
- data/spec/extensions/looser_typecasting_spec.rb +1 -1
- data/spec/extensions/migration_spec.rb +6 -6
- data/spec/extensions/pagination_spec.rb +2 -2
- data/spec/extensions/pretty_table_spec.rb +2 -2
- data/spec/extensions/query_spec.rb +2 -2
- data/spec/extensions/schema_dumper_spec.rb +2 -1
- data/spec/extensions/single_table_inheritance_spec.rb +1 -1
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/string_date_time_spec.rb +4 -4
- data/spec/extensions/validation_class_methods_spec.rb +2 -2
- data/spec/integration/dataset_test.rb +8 -3
- data/spec/integration/plugin_test.rb +5 -5
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +7 -0
- data/spec/integration/spec_helper.rb +14 -1
- data/spec/integration/timezone_test.rb +4 -4
- data/spec/integration/type_test.rb +1 -1
- data/spec/model/model_spec.rb +3 -3
- metadata +9 -4
@@ -72,7 +72,7 @@ module Sequel
|
|
72
72
|
|
73
73
|
# Check attribute value(s) is included in the given set.
|
74
74
|
def validates_includes(set, atts, opts={})
|
75
|
-
validatable_attributes_for_type(:includes, atts, opts){|a,v,m| validation_error_message(m, set) unless set.
|
75
|
+
validatable_attributes_for_type(:includes, atts, opts){|a,v,m| validation_error_message(m, set) unless set.send(set.respond_to?(:cover?) ? :cover? : :include?, v)}
|
76
76
|
end
|
77
77
|
|
78
78
|
# Check attribute value(s) string representation is a valid integer.
|
@@ -89,7 +89,7 @@ module Sequel
|
|
89
89
|
|
90
90
|
# Check that the attribute values length is in the specified range.
|
91
91
|
def validates_length_range(range, atts, opts={})
|
92
|
-
validatable_attributes_for_type(:length_range, atts, opts){|a,v,m| validation_error_message(m, range) unless v && range.
|
92
|
+
validatable_attributes_for_type(:length_range, atts, opts){|a,v,m| validation_error_message(m, range) unless v && range.send(range.respond_to?(:cover?) ? :cover? : :include?, v.length)}
|
93
93
|
end
|
94
94
|
|
95
95
|
# Check that the attribute values are not longer than the given max length.
|
data/lib/sequel/version.rb
CHANGED
@@ -3,7 +3,7 @@ module Sequel
|
|
3
3
|
MAJOR = 3
|
4
4
|
# The minor version of Sequel. Bumped for every non-patch level
|
5
5
|
# release, generally around once a month.
|
6
|
-
MINOR =
|
6
|
+
MINOR = 21
|
7
7
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
8
8
|
# releases that fix regressions from previous versions.
|
9
9
|
TINY = 0
|
@@ -43,7 +43,7 @@ FIREBIRD_DB.create_table! :test6 do
|
|
43
43
|
String :val4, :text=>true
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
describe "A Firebird database" do
|
47
47
|
before do
|
48
48
|
@db = FIREBIRD_DB
|
49
49
|
end
|
@@ -60,7 +60,7 @@ context "A Firebird database" do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
describe "A Firebird dataset" do
|
64
64
|
before do
|
65
65
|
@d = FIREBIRD_DB[:test]
|
66
66
|
@d.delete # remove all records
|
@@ -230,7 +230,7 @@ context "A Firebird dataset" do
|
|
230
230
|
end
|
231
231
|
end
|
232
232
|
|
233
|
-
|
233
|
+
describe "A Firebird dataset with a timestamp field" do
|
234
234
|
before do
|
235
235
|
@d = FIREBIRD_DB[:test3]
|
236
236
|
@d.delete
|
@@ -244,7 +244,7 @@ context "A Firebird dataset with a timestamp field" do
|
|
244
244
|
end
|
245
245
|
end
|
246
246
|
|
247
|
-
|
247
|
+
describe "A Firebird database" do
|
248
248
|
before do
|
249
249
|
@db = FIREBIRD_DB
|
250
250
|
@db.drop_table(:posts) rescue nil
|
@@ -353,7 +353,7 @@ context "A Firebird database" do
|
|
353
353
|
end
|
354
354
|
end
|
355
355
|
|
356
|
-
|
356
|
+
describe "Postgres::Dataset#insert" do
|
357
357
|
before do
|
358
358
|
@ds = FIREBIRD_DB[:test5]
|
359
359
|
@ds.delete
|
@@ -387,7 +387,7 @@ context "Postgres::Dataset#insert" do
|
|
387
387
|
end
|
388
388
|
end
|
389
389
|
|
390
|
-
|
390
|
+
describe "Postgres::Dataset#insert" do
|
391
391
|
before do
|
392
392
|
@ds = FIREBIRD_DB[:test6]
|
393
393
|
@ds.delete
|
@@ -15,7 +15,7 @@ INFORMIX_DB.create_table :test do
|
|
15
15
|
index :value
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
describe "A Informix database" do
|
19
19
|
specify "should provide disconnect functionality" do
|
20
20
|
INFORMIX_DB.execute("select user from dual")
|
21
21
|
INFORMIX_DB.pool.size.should == 1
|
@@ -24,7 +24,7 @@ context "A Informix database" do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
|
27
|
+
describe "A Informix dataset" do
|
28
28
|
before do
|
29
29
|
@d = INFORMIX_DB[:test]
|
30
30
|
@d.delete # remove all records
|
data/spec/adapters/mssql_spec.rb
CHANGED
@@ -34,7 +34,7 @@ MSSQL_DB.create_table! :test4 do
|
|
34
34
|
varbinary :value
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
describe "A MSSQL database" do
|
38
38
|
before do
|
39
39
|
@db = MSSQL_DB
|
40
40
|
end
|
@@ -59,7 +59,7 @@ context "A MSSQL database" do
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
|
62
|
+
describe "MSSQL Dataset#join_table" do
|
63
63
|
specify "should emulate the USING clause with ON" do
|
64
64
|
MSSQL_DB[:items].join(:categories, [:id]).sql.should ==
|
65
65
|
'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON (CATEGORIES.ID = ITEMS.ID)'
|
@@ -71,7 +71,7 @@ context "MSSQL Dataset#join_table" do
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
describe "MSSQL Dataset#output" do
|
75
75
|
before do
|
76
76
|
@db = MSSQL_DB
|
77
77
|
@db.create_table!(:items){String :name; Integer :value}
|
@@ -150,13 +150,13 @@ context "MSSQL Dataset#output" do
|
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
|
-
|
153
|
+
describe "MSSQL dataset" do
|
154
154
|
before do
|
155
155
|
@db = MSSQL_DB
|
156
156
|
@ds = MSSQL_DB[:t]
|
157
157
|
end
|
158
158
|
|
159
|
-
|
159
|
+
describe "using #with and #with_recursive" do
|
160
160
|
before do
|
161
161
|
@ds1 = @ds.with(:t, @db[:x])
|
162
162
|
@ds2 = @ds.with_recursive(:t, @db[:x], @db[:t])
|
@@ -177,7 +177,12 @@ context "MSSQL dataset" do
|
|
177
177
|
@ds2.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) INSERT INTO T SELECT * FROM T'
|
178
178
|
end
|
179
179
|
|
180
|
-
|
180
|
+
specify "should move WITH clause on joined dataset to top level" do
|
181
|
+
@db[:s].inner_join(@ds1).sql.should == "WITH T AS (SELECT * FROM X) SELECT * FROM S INNER JOIN (SELECT * FROM T) AS T1"
|
182
|
+
@ds1.inner_join(@db[:s].with(:s, @db[:y])).sql.should == "WITH T AS (SELECT * FROM X), S AS (SELECT * FROM Y) SELECT * FROM T INNER JOIN (SELECT * FROM S) AS T1"
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "on #import" do
|
181
186
|
before do
|
182
187
|
@db = @db.clone
|
183
188
|
class << @db
|
@@ -213,7 +218,7 @@ context "MSSQL dataset" do
|
|
213
218
|
end
|
214
219
|
end
|
215
220
|
|
216
|
-
|
221
|
+
describe "MSSQL joined datasets" do
|
217
222
|
before do
|
218
223
|
@db = MSSQL_DB
|
219
224
|
end
|
@@ -325,7 +330,7 @@ describe "Common Table Expressions" do
|
|
325
330
|
end
|
326
331
|
end
|
327
332
|
|
328
|
-
|
333
|
+
describe "MSSSQL::Dataset#insert" do
|
329
334
|
before do
|
330
335
|
@db = MSSQL_DB
|
331
336
|
@db.create_table!(:test5){primary_key :xid; Integer :value}
|
@@ -352,13 +357,13 @@ context "MSSSQL::Dataset#insert" do
|
|
352
357
|
end
|
353
358
|
end
|
354
359
|
|
355
|
-
|
360
|
+
describe "MSSSQL::Dataset#disable_insert_output" do
|
356
361
|
specify "should play nicely with simple_select_all?" do
|
357
362
|
MSSQL_DB[:test].disable_insert_output.send(:simple_select_all?).should == true
|
358
363
|
end
|
359
364
|
end
|
360
365
|
|
361
|
-
|
366
|
+
describe "MSSSQL::Dataset#into" do
|
362
367
|
before do
|
363
368
|
@db = MSSQL_DB
|
364
369
|
end
|
@@ -377,7 +382,7 @@ context "MSSSQL::Dataset#into" do
|
|
377
382
|
end
|
378
383
|
end
|
379
384
|
|
380
|
-
|
385
|
+
describe "A MSSQL database" do
|
381
386
|
before do
|
382
387
|
@db = MSSQL_DB
|
383
388
|
end
|
@@ -403,7 +408,7 @@ context "A MSSQL database" do
|
|
403
408
|
end
|
404
409
|
end
|
405
410
|
|
406
|
-
|
411
|
+
describe "MSSQL::Database#rename_table" do
|
407
412
|
specify "should work on non-schema bound tables which need escaping" do
|
408
413
|
MSSQL_DB.quote_identifiers = true
|
409
414
|
MSSQL_DB.create_table! :'foo bar' do
|
@@ -426,7 +431,7 @@ context "MSSQL::Database#rename_table" do
|
|
426
431
|
end
|
427
432
|
end
|
428
433
|
|
429
|
-
|
434
|
+
describe "MSSQL::Dataset#count" do
|
430
435
|
specify "should work with a distinct query with an order clause" do
|
431
436
|
MSSQL_DB.create_table!(:items){String :name; Integer :value}
|
432
437
|
MSSQL_DB[:items].insert(:name => "name", :value => 1)
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -34,7 +34,7 @@ SQL_BEGIN = 'BEGIN'
|
|
34
34
|
SQL_ROLLBACK = 'ROLLBACK'
|
35
35
|
SQL_COMMIT = 'COMMIT'
|
36
36
|
|
37
|
-
|
37
|
+
describe "MySQL", '#create_table' do
|
38
38
|
before do
|
39
39
|
@db = MYSQL_DB
|
40
40
|
MYSQL_DB.sqls.clear
|
@@ -84,7 +84,7 @@ context "MySQL", '#create_table' do
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
-
|
87
|
+
describe "A MySQL database" do
|
88
88
|
specify "should provide the server version" do
|
89
89
|
MYSQL_DB.server_version.should >= 40000
|
90
90
|
end
|
@@ -99,7 +99,7 @@ context "A MySQL database" do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
if MYSQL_DB.adapter_scheme == :mysql
|
102
|
-
|
102
|
+
describe "Sequel::MySQL.convert_tinyint_to_bool" do
|
103
103
|
before do
|
104
104
|
@db = MYSQL_DB
|
105
105
|
@db.create_table(:booltest){column :b, 'tinyint(1)'; column :i, 'tinyint(4)'}
|
@@ -148,7 +148,7 @@ if MYSQL_DB.adapter_scheme == :mysql
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
151
|
-
|
151
|
+
describe "A MySQL dataset" do
|
152
152
|
before do
|
153
153
|
MYSQL_DB.create_table(:items){String :name; Integer :value}
|
154
154
|
@d = MYSQL_DB[:items]
|
@@ -243,7 +243,7 @@ context "A MySQL dataset" do
|
|
243
243
|
end
|
244
244
|
end
|
245
245
|
|
246
|
-
|
246
|
+
describe "MySQL datasets" do
|
247
247
|
before do
|
248
248
|
@d = MYSQL_DB[:orders]
|
249
249
|
end
|
@@ -282,7 +282,7 @@ describe "Dataset#distinct" do
|
|
282
282
|
end
|
283
283
|
end
|
284
284
|
|
285
|
-
|
285
|
+
describe "MySQL join expressions" do
|
286
286
|
before do
|
287
287
|
@ds = MYSQL_DB[:nodes]
|
288
288
|
@ds.db.meta_def(:server_version) {50014}
|
@@ -333,7 +333,7 @@ context "MySQL join expressions" do
|
|
333
333
|
end
|
334
334
|
end
|
335
335
|
|
336
|
-
|
336
|
+
describe "Joined MySQL dataset" do
|
337
337
|
before do
|
338
338
|
@ds = MYSQL_DB[:nodes]
|
339
339
|
end
|
@@ -357,7 +357,7 @@ context "Joined MySQL dataset" do
|
|
357
357
|
end
|
358
358
|
end
|
359
359
|
|
360
|
-
|
360
|
+
describe "A MySQL database" do
|
361
361
|
before do
|
362
362
|
@db = MYSQL_DB
|
363
363
|
end
|
@@ -424,7 +424,7 @@ context "A MySQL database" do
|
|
424
424
|
end
|
425
425
|
end
|
426
426
|
|
427
|
-
|
427
|
+
describe "A MySQL database with table options" do
|
428
428
|
before do
|
429
429
|
@options = {:engine=>'MyISAM', :charset=>'latin1', :collate => 'latin1_swedish_ci'}
|
430
430
|
|
@@ -461,7 +461,7 @@ context "A MySQL database with table options" do
|
|
461
461
|
end
|
462
462
|
end
|
463
463
|
|
464
|
-
|
464
|
+
describe "A MySQL database" do
|
465
465
|
before do
|
466
466
|
@db = MYSQL_DB
|
467
467
|
@db.drop_table(:items) rescue nil
|
@@ -547,7 +547,7 @@ end
|
|
547
547
|
|
548
548
|
# Socket tests should only be run if the MySQL server is on localhost
|
549
549
|
if %w'localhost 127.0.0.1 ::1'.include?(MYSQL_URI.host) and MYSQL_DB.adapter_scheme == :mysql
|
550
|
-
|
550
|
+
describe "A MySQL database" do
|
551
551
|
specify "should accept a socket option" do
|
552
552
|
db = Sequel.mysql(MYSQL_DB.opts[:database], :host => 'localhost', :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket => MYSQL_SOCKET_FILE)
|
553
553
|
proc {db.test_connection}.should_not raise_error
|
@@ -565,7 +565,7 @@ if %w'localhost 127.0.0.1 ::1'.include?(MYSQL_URI.host) and MYSQL_DB.adapter_sch
|
|
565
565
|
end
|
566
566
|
end
|
567
567
|
|
568
|
-
|
568
|
+
describe "A MySQL database" do
|
569
569
|
specify "should accept a read_timeout option when connecting" do
|
570
570
|
db = Sequel.connect(MYSQL_DB.opts.merge(:read_timeout=>22342))
|
571
571
|
proc {db.test_connection}.should_not raise_error
|
@@ -577,7 +577,7 @@ context "A MySQL database" do
|
|
577
577
|
end
|
578
578
|
end
|
579
579
|
|
580
|
-
|
580
|
+
describe "A grouped MySQL dataset" do
|
581
581
|
before do
|
582
582
|
MYSQL_DB[:test2].delete
|
583
583
|
MYSQL_DB[:test2] << {:name => '11', :value => 10}
|
@@ -599,7 +599,7 @@ context "A grouped MySQL dataset" do
|
|
599
599
|
end
|
600
600
|
end
|
601
601
|
|
602
|
-
|
602
|
+
describe "A MySQL database" do
|
603
603
|
before do
|
604
604
|
@db = MYSQL_DB
|
605
605
|
@db.drop_table(:posts) rescue nil
|
@@ -668,7 +668,7 @@ context "A MySQL database" do
|
|
668
668
|
end
|
669
669
|
end
|
670
670
|
|
671
|
-
|
671
|
+
describe "MySQL::Dataset#insert and related methods" do
|
672
672
|
before do
|
673
673
|
MYSQL_DB.create_table(:items){String :name; Integer :value}
|
674
674
|
@d = MYSQL_DB[:items]
|
@@ -853,7 +853,7 @@ context "MySQL::Dataset#insert and related methods" do
|
|
853
853
|
|
854
854
|
end
|
855
855
|
|
856
|
-
|
856
|
+
describe "MySQL::Dataset#replace" do
|
857
857
|
before do
|
858
858
|
MYSQL_DB.create_table(:items){Integer :id, :unique=>true; Integer :value}
|
859
859
|
@d = MYSQL_DB[:items]
|
@@ -895,7 +895,7 @@ context "MySQL::Dataset#replace" do
|
|
895
895
|
end
|
896
896
|
end
|
897
897
|
|
898
|
-
|
898
|
+
describe "MySQL::Dataset#complex_expression_sql" do
|
899
899
|
before do
|
900
900
|
@d = MYSQL_DB.dataset
|
901
901
|
end
|
@@ -923,8 +923,35 @@ context "MySQL::Dataset#complex_expression_sql" do
|
|
923
923
|
end
|
924
924
|
end
|
925
925
|
|
926
|
+
describe "MySQL::Dataset#calc_found_rows" do
|
927
|
+
before do
|
928
|
+
MYSQL_DB.create_table!(:items){Integer :a}
|
929
|
+
end
|
930
|
+
after do
|
931
|
+
MYSQL_DB.drop_table(:items)
|
932
|
+
end
|
933
|
+
|
934
|
+
specify "should add the SQL_CALC_FOUND_ROWS keyword when selecting" do
|
935
|
+
MYSQL_DB[:items].select(:a).calc_found_rows.limit(1).sql.should == \
|
936
|
+
'SELECT SQL_CALC_FOUND_ROWS a FROM items LIMIT 1'
|
937
|
+
end
|
938
|
+
|
939
|
+
specify "should count matching rows disregarding LIMIT clause" do
|
940
|
+
MYSQL_DB[:items].multi_insert([{:a => 1}, {:a => 1}, {:a => 2}])
|
941
|
+
MYSQL_DB.sqls.clear
|
942
|
+
|
943
|
+
MYSQL_DB[:items].calc_found_rows.filter(:a => 1).limit(1).all.should == [{:a => 1}]
|
944
|
+
MYSQL_DB.dataset.select(:FOUND_ROWS.sql_function.as(:rows)).all.should == [{:rows => 2 }]
|
945
|
+
|
946
|
+
MYSQL_DB.sqls.should == [
|
947
|
+
'SELECT SQL_CALC_FOUND_ROWS * FROM items WHERE (a = 1) LIMIT 1',
|
948
|
+
'SELECT FOUND_ROWS() AS rows',
|
949
|
+
]
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
926
953
|
if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc
|
927
|
-
|
954
|
+
describe "MySQL Stored Procedures" do
|
928
955
|
before do
|
929
956
|
MYSQL_DB.create_table(:items){Integer :id; Integer :value}
|
930
957
|
@d = MYSQL_DB[:items]
|
@@ -969,7 +996,7 @@ if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc
|
|
969
996
|
end
|
970
997
|
|
971
998
|
if MYSQL_DB.adapter_scheme == :mysql
|
972
|
-
|
999
|
+
describe "MySQL bad date/time conversions" do
|
973
1000
|
after do
|
974
1001
|
Sequel::MySQL.convert_invalid_date_time = false
|
975
1002
|
end
|
@@ -1000,7 +1027,7 @@ if MYSQL_DB.adapter_scheme == :mysql
|
|
1000
1027
|
end
|
1001
1028
|
end
|
1002
1029
|
|
1003
|
-
|
1030
|
+
describe "MySQL multiple result sets" do
|
1004
1031
|
before do
|
1005
1032
|
MYSQL_DB.create_table!(:a){Integer :a}
|
1006
1033
|
MYSQL_DB.create_table!(:b){Integer :b}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
|
2
|
+
require "timeout"
|
2
3
|
|
3
4
|
unless defined?(ORACLE_DB)
|
4
5
|
ORACLE_DB = Sequel.connect('oracle://hr:hr@localhost/XE')
|
@@ -32,7 +33,7 @@ ORACLE_DB.create_table :categories do
|
|
32
33
|
varchar2 :cat_name, :size => 50
|
33
34
|
end
|
34
35
|
|
35
|
-
|
36
|
+
describe "An Oracle database" do
|
36
37
|
specify "should provide disconnect functionality" do
|
37
38
|
ORACLE_DB.execute("select user from dual")
|
38
39
|
ORACLE_DB.pool.size.should == 1
|
@@ -74,7 +75,7 @@ context "An Oracle database" do
|
|
74
75
|
end
|
75
76
|
end
|
76
77
|
|
77
|
-
|
78
|
+
describe "An Oracle dataset" do
|
78
79
|
before do
|
79
80
|
@d = ORACLE_DB[:items]
|
80
81
|
@d.delete # remove all records
|
@@ -222,7 +223,7 @@ context "An Oracle dataset" do
|
|
222
223
|
end
|
223
224
|
end
|
224
225
|
|
225
|
-
|
226
|
+
describe "Joined Oracle dataset" do
|
226
227
|
before do
|
227
228
|
@d1 = ORACLE_DB[:books]
|
228
229
|
@d1.delete # remove all records
|
@@ -263,7 +264,7 @@ context "Joined Oracle dataset" do
|
|
263
264
|
end
|
264
265
|
end
|
265
266
|
|
266
|
-
|
267
|
+
describe "Oracle aliasing" do
|
267
268
|
before do
|
268
269
|
@d1 = ORACLE_DB[:books]
|
269
270
|
@d1.delete # remove all records
|
@@ -284,3 +285,38 @@ context "Oracle aliasing" do
|
|
284
285
|
@d1.select(:title).group_by(:title).count.should == 2
|
285
286
|
end
|
286
287
|
end
|
288
|
+
|
289
|
+
describe "Row locks in Oracle" do
|
290
|
+
before do
|
291
|
+
@d1 = ORACLE_DB[:books]
|
292
|
+
@d1.delete # remove all records
|
293
|
+
@d1 << {:id => 1, :title => 'aaa'}
|
294
|
+
end
|
295
|
+
|
296
|
+
specify "#for_update should use FOR UPDATE" do
|
297
|
+
@d1.for_update.sql.should == "SELECT * FROM BOOKS FOR UPDATE"
|
298
|
+
end
|
299
|
+
|
300
|
+
specify "#lock_style should accept symbols" do
|
301
|
+
@d1.lock_style(:update).sql.should == "SELECT * FROM BOOKS FOR UPDATE"
|
302
|
+
end
|
303
|
+
|
304
|
+
specify "should not update during row lock" do
|
305
|
+
ORACLE_DB.transaction do
|
306
|
+
@d1.filter(:id => 1).for_update.to_a
|
307
|
+
proc do
|
308
|
+
t1 = Thread.start do
|
309
|
+
# wait for unlock
|
310
|
+
Timeout::timeout(0.02) do
|
311
|
+
ORACLE_DB[:books].filter(:id => 1).update(:title => "bbb")
|
312
|
+
end
|
313
|
+
end
|
314
|
+
t1.join
|
315
|
+
end.should raise_error
|
316
|
+
@d1.filter(:id => 1).first[:title].should == "aaa"
|
317
|
+
end
|
318
|
+
t2 = Thread.start { ORACLE_DB[:books].filter(:id => 1).update(:title => "bbb") }
|
319
|
+
t2.join
|
320
|
+
@d1.filter(:id => 1).first[:title].should == "bbb"
|
321
|
+
end
|
322
|
+
end
|