amalgalite 0.5.1-x86-mswin32-60 → 0.6.0-x86-mswin32-60
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/HISTORY +15 -2
- data/README +3 -0
- data/examples/define_aggregate.rb +75 -0
- data/examples/define_function.rb +104 -0
- data/examples/gems.db +0 -0
- data/ext/amalgalite3.h +28 -2
- data/ext/amalgalite3_blob.c +1 -2
- data/ext/amalgalite3_database.c +567 -46
- data/ext/amalgalite3_requires_bootstrap.c +1 -3
- data/ext/amalgalite3_statement.c +2 -2
- data/ext/extconf.rb +1 -0
- data/ext/sqlite3.c +6521 -4518
- data/ext/sqlite3.h +50 -43
- data/ext/test_error.c +77 -0
- data/lib/amalgalite.rb +5 -0
- data/lib/amalgalite/aggregate.rb +67 -0
- data/lib/amalgalite/busy_timeout.rb +47 -0
- data/lib/amalgalite/column.rb +1 -1
- data/lib/amalgalite/database.rb +271 -2
- data/lib/amalgalite/function.rb +61 -0
- data/lib/amalgalite/progress_handler.rb +21 -0
- data/lib/amalgalite/sqlite3.rb +1 -0
- data/lib/amalgalite/sqlite3/database/function.rb +48 -0
- data/lib/amalgalite/version.rb +2 -2
- data/lib/amalgalite3.so +0 -0
- data/spec/aggregate_spec.rb +168 -0
- data/spec/busy_handler.rb +164 -0
- data/spec/database_spec.rb +97 -3
- data/spec/function_spec.rb +86 -0
- data/spec/progress_handler_spec.rb +103 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/sqlite3/version_spec.rb +2 -2
- metadata +21 -3
data/lib/amalgalite/version.rb
CHANGED
data/lib/amalgalite3.so
CHANGED
Binary file
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
|
4
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
|
5
|
+
require 'amalgalite'
|
6
|
+
require 'amalgalite/database'
|
7
|
+
|
8
|
+
class AggregateTest1 < ::Amalgalite::Aggregate
|
9
|
+
def initialize
|
10
|
+
@name = 'atest1'
|
11
|
+
@arity = -1
|
12
|
+
@count = 0
|
13
|
+
end
|
14
|
+
def step( *args )
|
15
|
+
@count += 1
|
16
|
+
end
|
17
|
+
def finalize
|
18
|
+
return @count
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
describe "Aggregate SQL Functions" do
|
24
|
+
|
25
|
+
before(:each) do
|
26
|
+
@schema = IO.read( SpecInfo.test_schema_file )
|
27
|
+
@iso_db_file = SpecInfo.make_iso_db
|
28
|
+
@iso_db = Amalgalite::Database.new( SpecInfo.make_iso_db )
|
29
|
+
end
|
30
|
+
|
31
|
+
after(:each) do
|
32
|
+
File.unlink SpecInfo.test_db if File.exist?( SpecInfo.test_db )
|
33
|
+
@iso_db.close
|
34
|
+
File.unlink @iso_db_file if File.exist?( @iso_db_file )
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
it "must have a finalize method implemented" do
|
39
|
+
ag = ::Amalgalite::Aggregate.new
|
40
|
+
lambda { ag.finalize }.should raise_error( NotImplementedError, /Aggregate#finalize must be implemented/ )
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can define a custom SQL aggregate as a class with N params" do
|
44
|
+
@iso_db.define_aggregate("atest1", AggregateTest1 )
|
45
|
+
r = @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country")
|
46
|
+
r.first['a'].should == r.first['c']
|
47
|
+
r.first['a'].should == 242
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can remove a custom SQL aggregate by class" do
|
51
|
+
@iso_db.define_aggregate("atest1", AggregateTest1 )
|
52
|
+
@iso_db.aggregates.size.should == 1
|
53
|
+
r = @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country")
|
54
|
+
r.first['a'].should == r.first['c']
|
55
|
+
r.first['a'].should == 242
|
56
|
+
@iso_db.remove_aggregate( "atest1", AggregateTest1 )
|
57
|
+
@iso_db.aggregates.size.should == 0
|
58
|
+
lambda{ @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country") }.should raise_error(::Amalgalite::SQLite3::Error, /no such function: atest1/ )
|
59
|
+
end
|
60
|
+
|
61
|
+
it "can remove a custom SQL aggregate by arity" do
|
62
|
+
@iso_db.define_aggregate("atest1", AggregateTest1 )
|
63
|
+
@iso_db.aggregates.size.should == 1
|
64
|
+
r = @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country")
|
65
|
+
r.first['a'].should == r.first['c']
|
66
|
+
r.first['a'].should == 242
|
67
|
+
@iso_db.remove_aggregate( "atest1", -1)
|
68
|
+
@iso_db.aggregates.size.should == 0
|
69
|
+
lambda{ @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country") }.should raise_error(::Amalgalite::SQLite3::Error, /no such function: atest1/ )
|
70
|
+
end
|
71
|
+
|
72
|
+
it "can remove all custom SQL aggregates with the same name" do
|
73
|
+
class AT2 < AggregateTest1
|
74
|
+
def arity() 1; end
|
75
|
+
end
|
76
|
+
@iso_db.define_aggregate("atest1", AggregateTest1 )
|
77
|
+
@iso_db.define_aggregate("atest1", AT2)
|
78
|
+
@iso_db.aggregates.size.should == 2
|
79
|
+
r = @iso_db.execute("SELECT atest1(id,name) as a, atest1(id), count(*) as c FROM country")
|
80
|
+
r.first['a'].should == r.first['c']
|
81
|
+
r.first['a'].should == 242
|
82
|
+
@iso_db.remove_aggregate( "atest1" )
|
83
|
+
@iso_db.aggregates.size.should == 0
|
84
|
+
lambda{ @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country") }.should raise_error(::Amalgalite::SQLite3::Error, /no such function: atest1/ )
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
it "does not allow mixing of arbitrary and mandatory arguments to an SQL function" do
|
90
|
+
class AggregateTest2 < AggregateTest1
|
91
|
+
def name() "atest2"; end
|
92
|
+
def arity() -2; end
|
93
|
+
end
|
94
|
+
lambda { @iso_db.define_aggregate("atest2", AggregateTest2 ) }.should raise_error( ::Amalgalite::Database::AggregateError,
|
95
|
+
/Use only mandatory or arbitrary parameters in an SQL Aggregate, not both/ )
|
96
|
+
end
|
97
|
+
|
98
|
+
it "does not allow outrageous arity" do
|
99
|
+
class AggregateTest3 < AggregateTest1
|
100
|
+
def name() "atest3"; end
|
101
|
+
def arity() 101; end
|
102
|
+
end
|
103
|
+
lambda { @iso_db.define_aggregate("atest3", AggregateTest3 ) }.should raise_error( ::Amalgalite::SQLite3::Error, /SQLITE_ERROR .* bad parameters/ )
|
104
|
+
end
|
105
|
+
|
106
|
+
it "does not allow registering a function which does not match the defined name " do
|
107
|
+
class AggregateTest4 < AggregateTest1
|
108
|
+
def name() "name_mismatch"; end
|
109
|
+
end
|
110
|
+
lambda { @iso_db.define_aggregate("atest4", AggregateTest4 ) }.should raise_error( ::Amalgalite::Database::AggregateError,
|
111
|
+
/Aggregate implementation name 'name_mismatch' does not match defined name 'atest4'/)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "handles an error being thrown during the step function" do
|
115
|
+
class AggregateTest5 < AggregateTest1
|
116
|
+
def initialize
|
117
|
+
@name = "atest5"
|
118
|
+
@arity = -1
|
119
|
+
@count = 0
|
120
|
+
end
|
121
|
+
|
122
|
+
def step( *args )
|
123
|
+
@count += 1
|
124
|
+
if @count > 50 then
|
125
|
+
raise "Stepwise error!" if @count > 50
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
@iso_db.define_aggregate( "atest5", AggregateTest5 )
|
132
|
+
lambda { @iso_db.execute( "SELECT atest5(*) AS a FROM country" ) }.should raise_error( ::Amalgalite::SQLite3::Error, /Stepwise error!/ )
|
133
|
+
end
|
134
|
+
|
135
|
+
it "handles an error being thrown during the finalize function" do
|
136
|
+
class AggregateTest6 < AggregateTest1
|
137
|
+
def initialize
|
138
|
+
@name = "atest6"
|
139
|
+
@count = 0
|
140
|
+
@arity = -1
|
141
|
+
end
|
142
|
+
def finalize
|
143
|
+
raise "Finalize error!"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
@iso_db.define_aggregate( "atest6", AggregateTest6 )
|
147
|
+
lambda { @iso_db.execute( "SELECT atest6(*) AS a FROM country" ) }.should raise_error( ::Amalgalite::SQLite3::Error, /Finalize error!/ )
|
148
|
+
end
|
149
|
+
|
150
|
+
it "handles an error being thrown during initialization in the C extension" do
|
151
|
+
class AggregateTest7 < AggregateTest1
|
152
|
+
@@instance_count = 0
|
153
|
+
def initialize
|
154
|
+
@name = "atest7"
|
155
|
+
@count = 0
|
156
|
+
@arity = -1
|
157
|
+
if @@instance_count > 0 then
|
158
|
+
raise "Initialization error!"
|
159
|
+
else
|
160
|
+
@@instance_count += 1
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
@iso_db.define_aggregate( "atest7", AggregateTest7 )
|
165
|
+
lambda { @iso_db.execute( "SELECT atest7(*) AS a FROM country" ) }.should raise_error( ::Amalgalite::SQLite3::Error, /Initialization error!/ )
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
|
4
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
|
5
|
+
require 'amalgalite'
|
6
|
+
require 'amalgalite/database'
|
7
|
+
|
8
|
+
class BusyHandlerTest < Amalgalite::BusyHandler
|
9
|
+
attr_accessor :call_count
|
10
|
+
def initialize( max = 5 )
|
11
|
+
@max = max
|
12
|
+
@call_count = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def call( c )
|
16
|
+
@call_count += 1
|
17
|
+
if call_count >= @max then
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "Busy Handlers" do
|
25
|
+
before(:each) do
|
26
|
+
@db_name = SpecInfo.make_iso_db
|
27
|
+
@read_db = Amalgalite::Database.new( @db_name )
|
28
|
+
@write_db = Amalgalite::Database.new( @db_name )
|
29
|
+
end
|
30
|
+
|
31
|
+
after(:each) do
|
32
|
+
@write_db.close
|
33
|
+
@read_db.close
|
34
|
+
File.unlink @db_name if File.exist?( @db_name )
|
35
|
+
end
|
36
|
+
|
37
|
+
it "raises NotImplemented if #call is not overwritten" do
|
38
|
+
bh = ::Amalgalite::BusyHandler.new
|
39
|
+
lambda { bh.call( 42 ) }.should raise_error( ::NotImplementedError, /The busy handler call\(N\) method must be implemented/ )
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can be registered as block" do
|
43
|
+
call_count = 0
|
44
|
+
@write_db.busy_handler do |x|
|
45
|
+
call_count = x
|
46
|
+
if call_count >= 20 then
|
47
|
+
false
|
48
|
+
else
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# put a read lock on the database
|
54
|
+
@read_db.transaction( "DEFERRED" )
|
55
|
+
|
56
|
+
# put a read lock on the database, but want to go to an exclusive
|
57
|
+
@write_db.transaction( "IMMEDIATE" )
|
58
|
+
|
59
|
+
# do a read operation
|
60
|
+
@read_db.execute("SELECT count(*) FROM subcountry")
|
61
|
+
|
62
|
+
# attempt to do a write operation and commit it
|
63
|
+
@write_db.execute("DELETE FROM subcountry")
|
64
|
+
lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
|
65
|
+
call_count.should == 20
|
66
|
+
end
|
67
|
+
|
68
|
+
it "can be registered as lambda" do
|
69
|
+
call_count = 0
|
70
|
+
callable = lambda do |x|
|
71
|
+
call_count = x
|
72
|
+
if call_count >= 40 then
|
73
|
+
false
|
74
|
+
else
|
75
|
+
true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
@write_db.busy_handler( callable )
|
80
|
+
|
81
|
+
# put a read lock on the database
|
82
|
+
@read_db.transaction( "DEFERRED" )
|
83
|
+
|
84
|
+
# put a read lock on the database, but want to go to an exclusive
|
85
|
+
@write_db.transaction( "IMMEDIATE" )
|
86
|
+
|
87
|
+
# do a read operation
|
88
|
+
@read_db.execute("SELECT count(*) FROM subcountry")
|
89
|
+
|
90
|
+
# attempt to do a write operation and commit it
|
91
|
+
@write_db.execute("DELETE FROM subcountry")
|
92
|
+
lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
|
93
|
+
call_count.should == 40
|
94
|
+
end
|
95
|
+
|
96
|
+
it "can be registered as a class" do
|
97
|
+
h = BusyHandlerTest.new( 10 )
|
98
|
+
@write_db.busy_handler( h )
|
99
|
+
|
100
|
+
# put a read lock on the database
|
101
|
+
@read_db.transaction( "DEFERRED" )
|
102
|
+
|
103
|
+
# put a read lock on the database, but want to go to an exclusive
|
104
|
+
@write_db.transaction( "IMMEDIATE" )
|
105
|
+
|
106
|
+
# do a read operation
|
107
|
+
@read_db.execute("SELECT count(*) FROM subcountry")
|
108
|
+
|
109
|
+
# attempt to do a write operation and commit it
|
110
|
+
@write_db.execute("DELETE FROM subcountry")
|
111
|
+
lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
|
112
|
+
h.call_count.should == 10
|
113
|
+
end
|
114
|
+
|
115
|
+
it "has a default timeout class available " do
|
116
|
+
to = ::Amalgalite::BusyTimeout.new( 5, 10 )
|
117
|
+
@write_db.busy_handler( to )
|
118
|
+
|
119
|
+
# put a read lock on the database
|
120
|
+
@read_db.transaction( "DEFERRED" )
|
121
|
+
|
122
|
+
# put a read lock on the database, but want to go to an exclusive
|
123
|
+
@write_db.transaction( "IMMEDIATE" )
|
124
|
+
|
125
|
+
# do a read operation
|
126
|
+
@read_db.execute("SELECT count(*) FROM subcountry")
|
127
|
+
|
128
|
+
# attempt to do a write operation and commit it
|
129
|
+
@write_db.execute("DELETE FROM subcountry")
|
130
|
+
before = Time.now
|
131
|
+
lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
|
132
|
+
after = Time.now
|
133
|
+
to.call_count.should > 5
|
134
|
+
(after - before).should > 0.05
|
135
|
+
end
|
136
|
+
|
137
|
+
it "cannot register a block with the wrong arity" do
|
138
|
+
lambda do
|
139
|
+
@write_db.define_busy_handler { |x,y| puts "What!" }
|
140
|
+
end.should raise_error( ::Amalgalite::Database::BusyHandlerError, /A busy handler expects 1 and only 1 argument/ )
|
141
|
+
end
|
142
|
+
|
143
|
+
it "can remove a busy handler" do
|
144
|
+
bht = BusyHandlerTest.new
|
145
|
+
|
146
|
+
@write_db.busy_handler( bht )
|
147
|
+
|
148
|
+
# put a read lock on the database
|
149
|
+
@read_db.transaction( "DEFERRED" )
|
150
|
+
|
151
|
+
# put a read lock on the database, but want to go to an exclusive
|
152
|
+
@write_db.transaction( "IMMEDIATE" )
|
153
|
+
|
154
|
+
# do a read operation
|
155
|
+
@read_db.execute("SELECT count(*) FROM subcountry")
|
156
|
+
|
157
|
+
# attempt to do a write operation and commit it
|
158
|
+
@write_db.execute("DELETE FROM subcountry")
|
159
|
+
@write_db.remove_busy_handler
|
160
|
+
lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
|
161
|
+
bht.call_count.should == 0
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
data/spec/database_spec.rb
CHANGED
@@ -5,6 +5,7 @@ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
|
|
5
5
|
require 'amalgalite'
|
6
6
|
require 'amalgalite/taps/io'
|
7
7
|
require 'amalgalite/taps/console'
|
8
|
+
require 'amalgalite/database'
|
8
9
|
|
9
10
|
describe Amalgalite::Database do
|
10
11
|
before(:each) do
|
@@ -110,8 +111,6 @@ describe Amalgalite::Database do
|
|
110
111
|
db.close
|
111
112
|
end
|
112
113
|
|
113
|
-
|
114
|
-
|
115
114
|
it "can immediately execute an sql statement " do
|
116
115
|
db = Amalgalite::Database.new( SpecInfo.test_db )
|
117
116
|
db.execute( "CREATE TABLE t1( x, y, z )" ).should be_empty
|
@@ -234,5 +233,100 @@ describe Amalgalite::Database do
|
|
234
233
|
@iso_db.execute("SELECT count(1) as cnt FROM country").first['cnt'].should == 242
|
235
234
|
end
|
236
235
|
end
|
237
|
-
end
|
238
236
|
|
237
|
+
describe "#define_function" do
|
238
|
+
it "does not allow mixing of arbitrary and mandatory arguments to an SQL function" do
|
239
|
+
class FunctionTest2 < ::Amalgalite::Function
|
240
|
+
def initialize
|
241
|
+
super( 'ftest2', -2 )
|
242
|
+
end
|
243
|
+
def call( a, *args ); end
|
244
|
+
end
|
245
|
+
lambda { @iso_db.define_function("ftest2", FunctionTest2.new ) }.should raise_error( ::Amalgalite::Database::FunctionError )
|
246
|
+
end
|
247
|
+
|
248
|
+
it "does not allow outrageous arity" do
|
249
|
+
class FunctionTest3 < ::Amalgalite::Function
|
250
|
+
def initialize
|
251
|
+
super( 'ftest3', 101 )
|
252
|
+
end
|
253
|
+
def call( *args) ; end
|
254
|
+
end
|
255
|
+
lambda { @iso_db.define_function("ftest3", FunctionTest3.new ) }.should raise_error( ::Amalgalite::SQLite3::Error )
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
describe "#remove_function" do
|
261
|
+
it "unregisters a single function by name and arity" do
|
262
|
+
@iso_db.define_function( "rtest" ) do
|
263
|
+
"rtest called"
|
264
|
+
end
|
265
|
+
@iso_db.functions.size.should == 1
|
266
|
+
|
267
|
+
r = @iso_db.execute( "select rtest() AS r" )
|
268
|
+
r.first['r'].should == "rtest called"
|
269
|
+
@iso_db.remove_function("rtest", -1)
|
270
|
+
lambda { @iso_db.execute( "select rtest() as r" )}.should raise_error( ::Amalgalite::SQLite3::Error, /no such function: rtest/ )
|
271
|
+
@iso_db.functions.size.should == 0
|
272
|
+
end
|
273
|
+
|
274
|
+
it "unregisters a function by instances" do
|
275
|
+
class FunctionTest5 < ::Amalgalite::Function
|
276
|
+
def initialize
|
277
|
+
super( 'ftest5', 0)
|
278
|
+
end
|
279
|
+
def call( *args) "ftest5 called"; end
|
280
|
+
end
|
281
|
+
@iso_db.define_function("ftest5", FunctionTest5.new )
|
282
|
+
@iso_db.functions.size.should == 1
|
283
|
+
r = @iso_db.execute( "select ftest5() AS r" )
|
284
|
+
r.first['r'].should == "ftest5 called"
|
285
|
+
@iso_db.remove_function("ftest5", FunctionTest5.new )
|
286
|
+
lambda { @iso_db.execute( "select ftest5() as r" )}.should raise_error( ::Amalgalite::SQLite3::Error, /no such function: ftest5/ )
|
287
|
+
@iso_db.functions.size.should == 0
|
288
|
+
end
|
289
|
+
|
290
|
+
it "unregisters all functions with the same name" do
|
291
|
+
@iso_db.function( "rtest" ) do |x|
|
292
|
+
"rtest #{x} called"
|
293
|
+
end
|
294
|
+
|
295
|
+
@iso_db.function( "rtest" ) do ||
|
296
|
+
"rtest/0 called"
|
297
|
+
end
|
298
|
+
|
299
|
+
@iso_db.functions.size.should == 2
|
300
|
+
r = @iso_db.execute( "select rtest(1) AS r")
|
301
|
+
r.first['r'].should == "rtest 1 called"
|
302
|
+
r = @iso_db.execute( "select rtest() AS r")
|
303
|
+
r.first['r'].should == "rtest/0 called"
|
304
|
+
@iso_db.remove_function( 'rtest' )
|
305
|
+
lambda { @iso_db.execute( "select rtest(1) AS r") }.should raise_error( ::Amalgalite::SQLite3::Error )
|
306
|
+
lambda { @iso_db.execute( "select rtest() AS r") }.should raise_error( ::Amalgalite::SQLite3::Error )
|
307
|
+
@iso_db.functions.size.should == 0
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
it "can interrupt another thread that is also running in this database" do
|
312
|
+
had_error = nil
|
313
|
+
executions = 0
|
314
|
+
other = Thread.new( @iso_db ) do |db|
|
315
|
+
loop do
|
316
|
+
begin
|
317
|
+
db.execute("select count(id) from country")
|
318
|
+
executions += 1
|
319
|
+
rescue => e
|
320
|
+
had_error = e
|
321
|
+
break
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
sleep 0.01
|
326
|
+
@iso_db.interrupt!
|
327
|
+
other.join
|
328
|
+
executions.should > 10
|
329
|
+
had_error.should be_an_instance_of( ::Amalgalite::SQLite3::Error )
|
330
|
+
had_error.message.should =~ / interrupted/
|
331
|
+
end
|
332
|
+
end
|