sequel 3.21.0 → 3.29.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.
- data/CHANGELOG +413 -3
- data/README.rdoc +20 -6
- data/Rakefile +23 -16
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +210 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +86 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +115 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +15 -7
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +5 -31
- data/lib/sequel/adapters/jdbc/db2.rb +44 -0
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +26 -17
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
- data/lib/sequel/adapters/jdbc/mysql.rb +9 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +67 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +6 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +41 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +107 -38
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +78 -182
- data/lib/sequel/adapters/mysql2.rb +24 -23
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +349 -51
- data/lib/sequel/adapters/postgres.rb +169 -21
- data/lib/sequel/adapters/shared/access.rb +21 -6
- data/lib/sequel/adapters/shared/db2.rb +288 -0
- data/lib/sequel/adapters/shared/firebird.rb +214 -0
- data/lib/sequel/adapters/shared/informix.rb +45 -0
- data/lib/sequel/adapters/shared/mssql.rb +108 -65
- data/lib/sequel/adapters/shared/mysql.rb +56 -13
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -34
- data/lib/sequel/adapters/shared/postgres.rb +107 -58
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +168 -41
- data/lib/sequel/adapters/sqlite.rb +27 -18
- data/lib/sequel/adapters/swift/mysql.rb +9 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +152 -17
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +63 -0
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +100 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +8 -5
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +194 -57
- data/lib/sequel/dataset/features.rb +81 -8
- data/lib/sequel/dataset/graph.rb +8 -7
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +32 -15
- data/lib/sequel/dataset/query.rb +223 -42
- data/lib/sequel/dataset/sql.rb +58 -61
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +997 -331
- data/lib/sequel/model/base.rb +386 -129
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +12 -25
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +107 -51
- data/lib/sequel/timezones.rb +44 -35
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +65 -29
- data/spec/adapters/mysql_spec.rb +122 -123
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +213 -61
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +20 -31
- data/spec/core/database_spec.rb +729 -508
- data/spec/core/dataset_spec.rb +980 -1044
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/identity_map_spec.rb +162 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/many_through_many_spec.rb +195 -20
- data/spec/extensions/migration_spec.rb +17 -17
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +4 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
- data/spec/extensions/prepared_statements_spec.rb +72 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/single_table_inheritance_spec.rb +11 -0
- data/spec/extensions/spec_helper.rb +7 -1
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/to_dot_spec.rb +3 -5
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +522 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +375 -62
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +200 -120
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +174 -7
- data/spec/model/associations_spec.rb +849 -661
- data/spec/model/base_spec.rb +255 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +640 -676
- data/spec/model/hooks_spec.rb +309 -67
- data/spec/model/model_spec.rb +207 -167
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +321 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +95 -38
|
@@ -66,6 +66,17 @@ describe "An SQLite database" do
|
|
|
66
66
|
@db[:fk].all.should == [{:id=>1, :parent_id=>2}]
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
specify "should support a use_timestamp_timezones setting" do
|
|
70
|
+
@db.create_table!(:time){Time :time}
|
|
71
|
+
@db[:time].insert(Time.now)
|
|
72
|
+
@db[:time].get(:time.cast_string).should =~ /[-+]\d\d\d\d\z/
|
|
73
|
+
@db.use_timestamp_timezones = false
|
|
74
|
+
@db[:time].delete
|
|
75
|
+
@db[:time].insert(Time.now)
|
|
76
|
+
@db[:time].get(:time.cast_string).should_not =~ /[-+]\d\d\d\d\z/
|
|
77
|
+
@db.use_timestamp_timezones = true
|
|
78
|
+
end
|
|
79
|
+
|
|
69
80
|
specify "should provide a list of existing tables" do
|
|
70
81
|
@db.drop_table(:testing) rescue nil
|
|
71
82
|
@db.tables.should be_a_kind_of(Array)
|
|
@@ -133,13 +144,6 @@ describe "An SQLite dataset" do
|
|
|
133
144
|
@d = SQLITE_DB[:items]
|
|
134
145
|
end
|
|
135
146
|
|
|
136
|
-
specify "should handle string pattern matches correctly" do
|
|
137
|
-
@d.literal(:x.like('a')).should == "(x LIKE 'a')"
|
|
138
|
-
@d.literal(~:x.like('a')).should == "NOT (x LIKE 'a')"
|
|
139
|
-
@d.literal(:x.ilike('a')).should == "(x LIKE 'a')"
|
|
140
|
-
@d.literal(~:x.ilike('a')).should == "NOT (x LIKE 'a')"
|
|
141
|
-
end
|
|
142
|
-
|
|
143
147
|
specify "should raise errors if given a regexp pattern match" do
|
|
144
148
|
proc{@d.literal(:x.like(/a/))}.should raise_error(Sequel::Error)
|
|
145
149
|
proc{@d.literal(~:x.like(/a/))}.should raise_error(Sequel::Error)
|
|
@@ -164,27 +168,27 @@ end
|
|
|
164
168
|
|
|
165
169
|
describe "An SQLite dataset AS clause" do
|
|
166
170
|
specify "should use a string literal for :col___alias" do
|
|
167
|
-
SQLITE_DB.literal(:c___a).should == "c AS 'a'"
|
|
171
|
+
SQLITE_DB.literal(:c___a).should == "`c` AS 'a'"
|
|
168
172
|
end
|
|
169
173
|
|
|
170
174
|
specify "should use a string literal for :table__col___alias" do
|
|
171
|
-
SQLITE_DB.literal(:t__c___a).should == "t
|
|
175
|
+
SQLITE_DB.literal(:t__c___a).should == "`t`.`c` AS 'a'"
|
|
172
176
|
end
|
|
173
177
|
|
|
174
178
|
specify "should use a string literal for :column.as(:alias)" do
|
|
175
|
-
SQLITE_DB.literal(:c.as(:a)).should == "c AS 'a'"
|
|
179
|
+
SQLITE_DB.literal(:c.as(:a)).should == "`c` AS 'a'"
|
|
176
180
|
end
|
|
177
181
|
|
|
178
182
|
specify "should use a string literal in the SELECT clause" do
|
|
179
|
-
SQLITE_DB[:t].select(:c___a).sql.should == "SELECT c AS 'a' FROM t"
|
|
183
|
+
SQLITE_DB[:t].select(:c___a).sql.should == "SELECT `c` AS 'a' FROM `t`"
|
|
180
184
|
end
|
|
181
185
|
|
|
182
186
|
specify "should use a string literal in the FROM clause" do
|
|
183
|
-
SQLITE_DB[:t___a].sql.should == "SELECT * FROM t AS 'a'"
|
|
187
|
+
SQLITE_DB[:t___a].sql.should == "SELECT * FROM `t` AS 'a'"
|
|
184
188
|
end
|
|
185
189
|
|
|
186
190
|
specify "should use a string literal in the JOIN clause" do
|
|
187
|
-
SQLITE_DB[:t].join_table(:natural, :j, nil, :a).sql.should == "SELECT * FROM t NATURAL JOIN j AS 'a'"
|
|
191
|
+
SQLITE_DB[:t].join_table(:natural, :j, nil, :a).sql.should == "SELECT * FROM `t` NATURAL JOIN `j` AS 'a'"
|
|
188
192
|
end
|
|
189
193
|
end
|
|
190
194
|
|
|
@@ -313,6 +317,15 @@ describe "A SQLite database" do
|
|
|
313
317
|
@db[:test2].first.should == {:name => 'mmm'}
|
|
314
318
|
end
|
|
315
319
|
|
|
320
|
+
specify "should keep a composite primary key when dropping columns" do
|
|
321
|
+
@db.create_table!(:test2){Integer :a; Integer :b; Integer :c; primary_key [:a, :b]}
|
|
322
|
+
@db.drop_column :test2, :c
|
|
323
|
+
@db[:test2].columns.should == [:a, :b]
|
|
324
|
+
@db[:test2] << {:a=>1, :b=>2}
|
|
325
|
+
@db[:test2] << {:a=>2, :b=>3}
|
|
326
|
+
proc{@db[:test2] << {:a=>2, :b=>3}}.should raise_error(Sequel::Error)
|
|
327
|
+
end
|
|
328
|
+
|
|
316
329
|
specify "should keep column attributes when dropping a column" do
|
|
317
330
|
@db.create_table! :test3 do
|
|
318
331
|
primary_key :id
|
|
@@ -412,14 +425,15 @@ describe "A SQLite database" do
|
|
|
412
425
|
specify "should choose a temporary table name that isn't already used when dropping or renaming columns" do
|
|
413
426
|
sqls = []
|
|
414
427
|
@db.loggers << (l=Class.new{%w'info error'.each{|m| define_method(m){|sql| sqls << sql}}}.new)
|
|
415
|
-
@db.
|
|
428
|
+
@db.tables.each{|t| @db.drop_table(t) if t.to_s =~ /test3/}
|
|
429
|
+
@db.create_table :test3 do
|
|
416
430
|
Integer :h
|
|
417
431
|
Integer :i
|
|
418
432
|
end
|
|
419
|
-
@db.create_table
|
|
433
|
+
@db.create_table :test3_backup0 do
|
|
420
434
|
Integer :j
|
|
421
435
|
end
|
|
422
|
-
@db.create_table
|
|
436
|
+
@db.create_table :test3_backup1 do
|
|
423
437
|
Integer :k
|
|
424
438
|
end
|
|
425
439
|
|
|
@@ -428,20 +442,20 @@ describe "A SQLite database" do
|
|
|
428
442
|
@db[:test3_backup1].columns.should == [:k]
|
|
429
443
|
sqls.clear
|
|
430
444
|
@db.drop_column(:test3, :i)
|
|
431
|
-
sqls.any?{|x| x =~ /\
|
|
432
|
-
sqls.any?{|x| x =~ /\
|
|
445
|
+
sqls.any?{|x| x =~ /\AALTER TABLE.*test3.*RENAME TO.*test3_backup2/}.should == true
|
|
446
|
+
sqls.any?{|x| x =~ /\AALTER TABLE.*test3.*RENAME TO.*test3_backup[01]/}.should == false
|
|
433
447
|
@db[:test3].columns.should == [:h]
|
|
434
448
|
@db[:test3_backup0].columns.should == [:j]
|
|
435
449
|
@db[:test3_backup1].columns.should == [:k]
|
|
436
450
|
|
|
437
|
-
@db.create_table
|
|
451
|
+
@db.create_table :test3_backup2 do
|
|
438
452
|
Integer :l
|
|
439
453
|
end
|
|
440
454
|
|
|
441
455
|
sqls.clear
|
|
442
456
|
@db.rename_column(:test3, :h, :i)
|
|
443
|
-
sqls.any?{|x| x =~ /\
|
|
444
|
-
sqls.any?{|x| x =~ /\
|
|
457
|
+
sqls.any?{|x| x =~ /\AALTER TABLE.*test3.*RENAME TO.*test3_backup3/}.should == true
|
|
458
|
+
sqls.any?{|x| x =~ /\AALTER TABLE.*test3.*RENAME TO.*test3_backup[012]/}.should == false
|
|
445
459
|
@db[:test3].columns.should == [:i]
|
|
446
460
|
@db[:test3_backup0].columns.should == [:j]
|
|
447
461
|
@db[:test3_backup1].columns.should == [:k]
|
|
@@ -84,7 +84,9 @@ describe "A connection pool handling connections" do
|
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
specify "#make_new should not make more than max_size connections" do
|
|
87
|
-
|
|
87
|
+
q = Queue.new
|
|
88
|
+
50.times{Thread.new{@cpool.hold{q.pop}}}
|
|
89
|
+
50.times{q.push nil}
|
|
88
90
|
@cpool.created_count.should <= @max_size
|
|
89
91
|
end
|
|
90
92
|
|
|
@@ -96,7 +98,8 @@ describe "A connection pool handling connections" do
|
|
|
96
98
|
|
|
97
99
|
specify "#hold should remove the connection if a DatabaseDisconnectError is raised" do
|
|
98
100
|
@cpool.created_count.should == 0
|
|
99
|
-
|
|
101
|
+
q, q1 = Queue.new, Queue.new
|
|
102
|
+
@cpool.hold{Thread.new{@cpool.hold{q1.pop; q.push nil}; q1.pop; q.push nil}; q1.push nil; q.pop; q1.push nil; q.pop}
|
|
100
103
|
@cpool.created_count.should == 2
|
|
101
104
|
proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
|
|
102
105
|
@cpool.created_count.should == 1
|
|
@@ -121,36 +124,30 @@ describe "A connection pool handling connection errors" do
|
|
|
121
124
|
end
|
|
122
125
|
end
|
|
123
126
|
|
|
124
|
-
class DummyConnection
|
|
125
|
-
@@value = 0
|
|
126
|
-
def initialize
|
|
127
|
-
@@value += 1
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def value
|
|
131
|
-
@@value
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
127
|
describe "ConnectionPool#hold" do
|
|
136
128
|
before do
|
|
137
|
-
|
|
129
|
+
value = 0
|
|
130
|
+
@c = Class.new do
|
|
131
|
+
define_method(:initialize){value += 1}
|
|
132
|
+
define_method(:value){value}
|
|
133
|
+
end
|
|
134
|
+
@pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS){@c.new}
|
|
138
135
|
end
|
|
139
136
|
|
|
140
137
|
specify "should pass the result of the connection maker proc to the supplied block" do
|
|
141
138
|
res = nil
|
|
142
139
|
@pool.hold {|c| res = c}
|
|
143
|
-
res.should be_a_kind_of(
|
|
140
|
+
res.should be_a_kind_of(@c)
|
|
144
141
|
res.value.should == 1
|
|
145
142
|
@pool.hold {|c| res = c}
|
|
146
|
-
res.should be_a_kind_of(
|
|
143
|
+
res.should be_a_kind_of(@c)
|
|
147
144
|
res.value.should == 1 # the connection maker is invoked only once
|
|
148
145
|
end
|
|
149
146
|
|
|
150
147
|
specify "should be re-entrant by the same thread" do
|
|
151
148
|
cc = nil
|
|
152
149
|
@pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
|
|
153
|
-
cc.should be_a_kind_of(
|
|
150
|
+
cc.should be_a_kind_of(@c)
|
|
154
151
|
end
|
|
155
152
|
|
|
156
153
|
specify "should catch exceptions and reraise them" do
|
|
@@ -166,15 +163,14 @@ describe "A connection pool with a max size of 1" do
|
|
|
166
163
|
|
|
167
164
|
specify "should let only one thread access the connection at any time" do
|
|
168
165
|
cc,c1, c2 = nil
|
|
169
|
-
|
|
166
|
+
q, q1 = Queue.new, Queue.new
|
|
170
167
|
|
|
171
|
-
t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup;
|
|
172
|
-
|
|
168
|
+
t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; q1.push nil; q.pop}}
|
|
169
|
+
q1.pop
|
|
173
170
|
cc.should == 'herro'
|
|
174
171
|
c1.should == 'herro'
|
|
175
172
|
|
|
176
|
-
t2 = Thread.new {@pool.hold {|c| c2 = c.dup;
|
|
177
|
-
sleep 0.02 * m
|
|
173
|
+
t2 = Thread.new {@pool.hold {|c| c2 = c.dup; q1.push nil; q.pop;}}
|
|
178
174
|
|
|
179
175
|
# connection held by t1
|
|
180
176
|
t1.should be_alive
|
|
@@ -186,26 +182,22 @@ describe "A connection pool with a max size of 1" do
|
|
|
186
182
|
|
|
187
183
|
@pool.available_connections.should be_empty
|
|
188
184
|
@pool.allocated.should == {t1=>cc}
|
|
189
|
-
|
|
185
|
+
|
|
190
186
|
cc.gsub!('rr', 'll')
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
187
|
+
q.push nil
|
|
188
|
+
q1.pop
|
|
189
|
+
|
|
194
190
|
t1.should_not be_alive
|
|
195
191
|
t2.should be_alive
|
|
196
|
-
|
|
192
|
+
|
|
197
193
|
c2.should == 'hello'
|
|
198
194
|
|
|
199
195
|
@pool.available_connections.should be_empty
|
|
200
196
|
@pool.allocated.should == {t2=>cc}
|
|
201
197
|
|
|
202
|
-
cc.gsub!('ll', 'rr')
|
|
203
|
-
sleep 0.05 * m
|
|
204
|
-
|
|
205
198
|
#connection released
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
cc.should == 'herro'
|
|
199
|
+
q.push nil
|
|
200
|
+
t2.join
|
|
209
201
|
|
|
210
202
|
@invoked_count.should == 1
|
|
211
203
|
@pool.size.should == 1
|
|
@@ -236,34 +228,42 @@ describe "A connection pool with a max size of 1" do
|
|
|
236
228
|
end
|
|
237
229
|
|
|
238
230
|
shared_examples_for "A threaded connection pool" do
|
|
231
|
+
specify "should raise a PoolTimeout error if a connection couldn't be acquired before timeout" do
|
|
232
|
+
x = nil
|
|
233
|
+
q, q1 = Queue.new, Queue.new
|
|
234
|
+
pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:max_connections=>1, :pool_timeout=>0)) {@invoked_count += 1}
|
|
235
|
+
t = Thread.new{pool.hold{|c| q1.push nil; q.pop}}
|
|
236
|
+
q1.pop
|
|
237
|
+
proc{pool.hold{|c|}}.should raise_error(Sequel::PoolTimeout)
|
|
238
|
+
q.push nil
|
|
239
|
+
t.join
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it "should not add a disconnected connection back to the pool if the disconnection_proc raises an error" do
|
|
243
|
+
pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:max_connections=>1, :pool_timeout=>0, :disconnection_proc=>proc{|c| raise Sequel::Error})) {@invoked_count += 1}
|
|
244
|
+
proc{pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::Error)
|
|
245
|
+
pool.available_connections.length.should == 0
|
|
246
|
+
end
|
|
247
|
+
|
|
239
248
|
specify "should let five threads simultaneously access separate connections" do
|
|
240
249
|
cc = {}
|
|
241
250
|
threads = []
|
|
242
|
-
|
|
251
|
+
q, q1, q2 = Queue.new, Queue.new, Queue.new
|
|
243
252
|
|
|
244
|
-
5.times
|
|
245
|
-
sleep 0.04
|
|
253
|
+
5.times{|i| threads << Thread.new{@pool.hold{|c| q.pop; cc[i] = c; q1.push nil; q2.pop}}; q.push nil; q1.pop}
|
|
246
254
|
threads.each {|t| t.should be_alive}
|
|
247
255
|
cc.size.should == 5
|
|
248
256
|
@invoked_count.should == 5
|
|
249
257
|
@pool.size.should == 5
|
|
250
258
|
@pool.available_connections.should be_empty
|
|
251
|
-
|
|
259
|
+
|
|
252
260
|
h = {}
|
|
261
|
+
i = 0
|
|
253
262
|
threads.each{|t| h[t] = (i+=1)}
|
|
254
263
|
@pool.allocated.should == h
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
threads[3].raise "your'e dead too"
|
|
259
|
-
|
|
260
|
-
sleep 0.02
|
|
261
|
-
|
|
262
|
-
@pool.available_connections.should == [1, 4]
|
|
263
|
-
@pool.allocated.should == {threads[1]=>2, threads[2]=>3, threads[4]=>5}
|
|
264
|
-
|
|
265
|
-
stop = true
|
|
266
|
-
sleep 0.04
|
|
264
|
+
@pool.available_connections.should == []
|
|
265
|
+
5.times{q2.push nil}
|
|
266
|
+
threads.each{|t| t.join}
|
|
267
267
|
|
|
268
268
|
@pool.available_connections.size.should == 5
|
|
269
269
|
@pool.allocated.should be_empty
|
|
@@ -272,16 +272,15 @@ shared_examples_for "A threaded connection pool" do
|
|
|
272
272
|
specify "should block threads until a connection becomes available" do
|
|
273
273
|
cc = {}
|
|
274
274
|
threads = []
|
|
275
|
-
|
|
275
|
+
q, q1 = Queue.new, Queue.new
|
|
276
276
|
|
|
277
|
-
5.times
|
|
278
|
-
|
|
277
|
+
5.times{|i| threads << Thread.new{@pool.hold{|c| cc[i] = c; q1.push nil; q.pop}}}
|
|
278
|
+
5.times{q1.pop}
|
|
279
279
|
threads.each {|t| t.should be_alive}
|
|
280
280
|
@pool.available_connections.should be_empty
|
|
281
281
|
|
|
282
|
-
3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
|
|
282
|
+
3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c; q1.push nil}}}
|
|
283
283
|
|
|
284
|
-
sleep 0.02
|
|
285
284
|
threads[5].should be_alive
|
|
286
285
|
threads[6].should be_alive
|
|
287
286
|
threads[7].should be_alive
|
|
@@ -290,8 +289,10 @@ shared_examples_for "A threaded connection pool" do
|
|
|
290
289
|
cc[6].should be_nil
|
|
291
290
|
cc[7].should be_nil
|
|
292
291
|
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
5.times{q.push nil}
|
|
293
|
+
5.times{|i| threads[i].join}
|
|
294
|
+
3.times{q1.pop}
|
|
295
|
+
3.times{|i| threads[i+5].join}
|
|
295
296
|
|
|
296
297
|
threads.each {|t| t.should_not be_alive}
|
|
297
298
|
|
|
@@ -305,7 +306,8 @@ end
|
|
|
305
306
|
describe "Threaded Unsharded Connection Pool" do
|
|
306
307
|
before do
|
|
307
308
|
@invoked_count = 0
|
|
308
|
-
@
|
|
309
|
+
@cp_opts = CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)
|
|
310
|
+
@pool = Sequel::ConnectionPool.get_pool(@cp_opts) {@invoked_count += 1}
|
|
309
311
|
end
|
|
310
312
|
|
|
311
313
|
it_should_behave_like "A threaded connection pool"
|
|
@@ -314,7 +316,8 @@ end
|
|
|
314
316
|
describe "Threaded Sharded Connection Pool" do
|
|
315
317
|
before do
|
|
316
318
|
@invoked_count = 0
|
|
317
|
-
@
|
|
319
|
+
@cp_opts = CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{})
|
|
320
|
+
@pool = Sequel::ConnectionPool.get_pool(@cp_opts) {@invoked_count += 1}
|
|
318
321
|
end
|
|
319
322
|
|
|
320
323
|
it_should_behave_like "A threaded connection pool"
|
|
@@ -324,19 +327,15 @@ describe "ConnectionPool#disconnect" do
|
|
|
324
327
|
before do
|
|
325
328
|
@count = 0
|
|
326
329
|
@pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{})) {{:id => @count += 1}}
|
|
330
|
+
threads = []
|
|
331
|
+
q, q1 = Queue.new, Queue.new
|
|
332
|
+
5.times {|i| threads << Thread.new {@pool.hold {|c| q1.push nil; q.pop}}}
|
|
333
|
+
5.times{q1.pop}
|
|
334
|
+
5.times{q.push nil}
|
|
335
|
+
threads.each {|t| t.join}
|
|
327
336
|
end
|
|
328
337
|
|
|
329
338
|
specify "should invoke the given block for each available connection" do
|
|
330
|
-
threads = []
|
|
331
|
-
stop = nil
|
|
332
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
|
|
333
|
-
while @pool.size < 5
|
|
334
|
-
sleep 0.02
|
|
335
|
-
end
|
|
336
|
-
stop = true
|
|
337
|
-
sleep 0.1
|
|
338
|
-
threads.each {|t| t.join}
|
|
339
|
-
|
|
340
339
|
@pool.size.should == 5
|
|
341
340
|
@pool.available_connections.size.should == 5
|
|
342
341
|
@pool.available_connections.each {|c| c[:id].should_not be_nil}
|
|
@@ -346,34 +345,13 @@ describe "ConnectionPool#disconnect" do
|
|
|
346
345
|
end
|
|
347
346
|
|
|
348
347
|
specify "should remove all available connections" do
|
|
349
|
-
threads = []
|
|
350
|
-
stop = nil
|
|
351
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
|
|
352
|
-
while @pool.size < 5
|
|
353
|
-
sleep 0.02
|
|
354
|
-
end
|
|
355
|
-
stop = true
|
|
356
|
-
sleep 0.1
|
|
357
|
-
threads.each {|t| t.join}
|
|
358
|
-
|
|
359
348
|
@pool.size.should == 5
|
|
360
349
|
@pool.disconnect
|
|
361
350
|
@pool.size.should == 0
|
|
362
351
|
end
|
|
363
352
|
|
|
364
353
|
specify "should disconnect connections in use as soon as they are no longer in use" do
|
|
365
|
-
threads = []
|
|
366
|
-
stop = nil
|
|
367
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
|
|
368
|
-
while @pool.size < 5
|
|
369
|
-
sleep 0.02
|
|
370
|
-
end
|
|
371
|
-
stop = true
|
|
372
|
-
sleep 0.1
|
|
373
|
-
threads.each {|t| t.join}
|
|
374
|
-
|
|
375
354
|
@pool.size.should == 5
|
|
376
|
-
|
|
377
355
|
@pool.hold do |conn|
|
|
378
356
|
@pool.available_connections.size.should == 4
|
|
379
357
|
@pool.available_connections.each {|c| c.should_not be(conn)}
|
|
@@ -556,9 +534,10 @@ describe "A connection pool with multiple servers" do
|
|
|
556
534
|
specify "#remove_servers should disconnect available connections immediately" do
|
|
557
535
|
pool = Sequel::ConnectionPool.get_pool(:max_connections=>5, :servers=>{:server1=>{}}){|s| s}
|
|
558
536
|
threads = []
|
|
559
|
-
|
|
560
|
-
5.times {|i| threads << Thread.new{pool.hold(:server1){|c|
|
|
561
|
-
|
|
537
|
+
q, q1 = Queue.new, Queue.new
|
|
538
|
+
5.times {|i| threads << Thread.new {pool.hold(:server1){|c| q1.push nil; q.pop}}}
|
|
539
|
+
5.times{q1.pop}
|
|
540
|
+
5.times{q.push nil}
|
|
562
541
|
threads.each {|t| t.join}
|
|
563
542
|
|
|
564
543
|
pool.size(:server1).should == 5
|
data/spec/core/core_sql_spec.rb
CHANGED
|
@@ -75,16 +75,16 @@ end
|
|
|
75
75
|
|
|
76
76
|
describe "String#lit" do
|
|
77
77
|
before do
|
|
78
|
-
@ds = ds =
|
|
78
|
+
@ds = ds = Sequel::Database.new[:t]
|
|
79
79
|
end
|
|
80
|
+
|
|
80
81
|
specify "should return an LiteralString object" do
|
|
81
82
|
'xyz'.lit.should be_a_kind_of(Sequel::LiteralString)
|
|
82
83
|
'xyz'.lit.to_s.should == 'xyz'
|
|
83
84
|
end
|
|
84
85
|
|
|
85
86
|
specify "should inhibit string literalization" do
|
|
86
|
-
|
|
87
|
-
"UPDATE t SET stamp = NOW()"
|
|
87
|
+
@ds.update_sql(:stamp => "NOW()".lit).should == "UPDATE t SET stamp = NOW()"
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
specify "should return a PlaceholderLiteralString object if args are given" do
|
|
@@ -176,10 +176,8 @@ end
|
|
|
176
176
|
|
|
177
177
|
describe "Column references" do
|
|
178
178
|
before do
|
|
179
|
-
@
|
|
180
|
-
|
|
181
|
-
end
|
|
182
|
-
@ds = @c.new(MockDatabase.new)
|
|
179
|
+
@ds = Sequel::Database.new.dataset
|
|
180
|
+
def @ds.quoted_identifier(c); "`#{c}`"; end
|
|
183
181
|
@ds.quote_identifiers = true
|
|
184
182
|
end
|
|
185
183
|
|
|
@@ -289,7 +287,7 @@ end
|
|
|
289
287
|
|
|
290
288
|
describe "Dataset#literal" do
|
|
291
289
|
before do
|
|
292
|
-
@ds =
|
|
290
|
+
@ds = Sequel::Database.new.dataset
|
|
293
291
|
end
|
|
294
292
|
|
|
295
293
|
specify "should convert qualified symbol notation into dot notation" do
|
|
@@ -325,17 +323,12 @@ end
|
|
|
325
323
|
|
|
326
324
|
describe "Symbol" do
|
|
327
325
|
before do
|
|
328
|
-
@ds = Sequel::
|
|
326
|
+
@ds = Sequel::Database.new.dataset
|
|
329
327
|
end
|
|
330
328
|
|
|
331
|
-
specify "should support
|
|
329
|
+
specify "should support sql_function method" do
|
|
332
330
|
:COUNT.sql_function('1').to_s(@ds).should == "COUNT('1')"
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
specify "should inhibit string literalization" do
|
|
336
|
-
db = Sequel::Database.new
|
|
337
|
-
ds = db[:t]
|
|
338
|
-
ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1') FROM t"
|
|
331
|
+
@ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1')"
|
|
339
332
|
end
|
|
340
333
|
|
|
341
334
|
specify "should support cast method" do
|
|
@@ -367,22 +360,18 @@ describe "Symbol" do
|
|
|
367
360
|
end
|
|
368
361
|
|
|
369
362
|
specify "should allow database independent types when casting" do
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
type
|
|
376
|
-
end
|
|
363
|
+
db = @ds.db
|
|
364
|
+
def db.cast_type_literal(type)
|
|
365
|
+
return :foo if type == Integer
|
|
366
|
+
return :bar if type == String
|
|
367
|
+
type
|
|
377
368
|
end
|
|
378
|
-
@
|
|
379
|
-
:abc.cast(String).to_s(@ds).should == "CAST(abc AS
|
|
380
|
-
:abc.
|
|
381
|
-
:abc.
|
|
382
|
-
:abc.
|
|
383
|
-
:abc.
|
|
384
|
-
:abc.cast_numeric.to_s(@ds2).should == "CAST(abc AS foo)"
|
|
385
|
-
:abc.cast_numeric(String).to_s(@ds2).should == "CAST(abc AS bar)"
|
|
369
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS bar)"
|
|
370
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS bar)"
|
|
371
|
+
:abc.cast_string.to_s(@ds).should == "CAST(abc AS bar)"
|
|
372
|
+
:abc.cast_string(Integer).to_s(@ds).should == "CAST(abc AS foo)"
|
|
373
|
+
:abc.cast_numeric.to_s(@ds).should == "CAST(abc AS foo)"
|
|
374
|
+
:abc.cast_numeric(String).to_s(@ds).should == "CAST(abc AS bar)"
|
|
386
375
|
end
|
|
387
376
|
|
|
388
377
|
specify "should support SQL EXTRACT function via #extract " do
|