amalgalite 0.10.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/HISTORY +201 -0
  2. data/LICENSE +29 -0
  3. data/README +51 -0
  4. data/bin/amalgalite-pack +126 -0
  5. data/examples/a.rb +9 -0
  6. data/examples/blob.rb +88 -0
  7. data/examples/bootstrap.rb +36 -0
  8. data/examples/define_aggregate.rb +75 -0
  9. data/examples/define_function.rb +104 -0
  10. data/examples/gem-db.rb +94 -0
  11. data/examples/gems.db +0 -0
  12. data/examples/require_me.rb +11 -0
  13. data/examples/requires.rb +42 -0
  14. data/examples/schema-info.rb +34 -0
  15. data/ext/amalgalite/amalgalite3.c +290 -0
  16. data/ext/amalgalite/amalgalite3.h +151 -0
  17. data/ext/amalgalite/amalgalite3_blob.c +240 -0
  18. data/ext/amalgalite/amalgalite3_constants.c +221 -0
  19. data/ext/amalgalite/amalgalite3_database.c +1148 -0
  20. data/ext/amalgalite/amalgalite3_requires_bootstrap.c +210 -0
  21. data/ext/amalgalite/amalgalite3_statement.c +639 -0
  22. data/ext/amalgalite/extconf.rb +36 -0
  23. data/ext/amalgalite/gen_constants.rb +130 -0
  24. data/ext/amalgalite/sqlite3.c +106729 -0
  25. data/ext/amalgalite/sqlite3.h +5626 -0
  26. data/ext/amalgalite/sqlite3_options.h +4 -0
  27. data/ext/amalgalite/sqlite3ext.h +380 -0
  28. data/gemspec.rb +60 -0
  29. data/lib/amalgalite.rb +43 -0
  30. data/lib/amalgalite/1.8/amalgalite3.so +0 -0
  31. data/lib/amalgalite/1.9/amalgalite3.so +0 -0
  32. data/lib/amalgalite/aggregate.rb +67 -0
  33. data/lib/amalgalite/blob.rb +186 -0
  34. data/lib/amalgalite/boolean.rb +42 -0
  35. data/lib/amalgalite/busy_timeout.rb +47 -0
  36. data/lib/amalgalite/column.rb +97 -0
  37. data/lib/amalgalite/core_ext/kernel/require.rb +21 -0
  38. data/lib/amalgalite/database.rb +947 -0
  39. data/lib/amalgalite/function.rb +61 -0
  40. data/lib/amalgalite/index.rb +43 -0
  41. data/lib/amalgalite/packer.rb +226 -0
  42. data/lib/amalgalite/paths.rb +70 -0
  43. data/lib/amalgalite/profile_tap.rb +131 -0
  44. data/lib/amalgalite/progress_handler.rb +21 -0
  45. data/lib/amalgalite/requires.rb +120 -0
  46. data/lib/amalgalite/schema.rb +191 -0
  47. data/lib/amalgalite/sqlite3.rb +6 -0
  48. data/lib/amalgalite/sqlite3/constants.rb +80 -0
  49. data/lib/amalgalite/sqlite3/database/function.rb +48 -0
  50. data/lib/amalgalite/sqlite3/database/status.rb +68 -0
  51. data/lib/amalgalite/sqlite3/status.rb +60 -0
  52. data/lib/amalgalite/sqlite3/version.rb +37 -0
  53. data/lib/amalgalite/statement.rb +414 -0
  54. data/lib/amalgalite/table.rb +90 -0
  55. data/lib/amalgalite/taps.rb +2 -0
  56. data/lib/amalgalite/taps/console.rb +27 -0
  57. data/lib/amalgalite/taps/io.rb +71 -0
  58. data/lib/amalgalite/trace_tap.rb +35 -0
  59. data/lib/amalgalite/type_map.rb +63 -0
  60. data/lib/amalgalite/type_maps/default_map.rb +167 -0
  61. data/lib/amalgalite/type_maps/storage_map.rb +40 -0
  62. data/lib/amalgalite/type_maps/text_map.rb +22 -0
  63. data/lib/amalgalite/version.rb +37 -0
  64. data/lib/amalgalite/view.rb +26 -0
  65. data/spec/aggregate_spec.rb +169 -0
  66. data/spec/amalgalite_spec.rb +4 -0
  67. data/spec/blob_spec.rb +81 -0
  68. data/spec/boolean_spec.rb +23 -0
  69. data/spec/busy_handler.rb +165 -0
  70. data/spec/database_spec.rb +494 -0
  71. data/spec/default_map_spec.rb +87 -0
  72. data/spec/function_spec.rb +94 -0
  73. data/spec/integeration_spec.rb +111 -0
  74. data/spec/packer_spec.rb +60 -0
  75. data/spec/paths_spec.rb +28 -0
  76. data/spec/progress_handler_spec.rb +105 -0
  77. data/spec/requires_spec.rb +23 -0
  78. data/spec/rtree_spec.rb +71 -0
  79. data/spec/schema_spec.rb +120 -0
  80. data/spec/spec_helper.rb +27 -0
  81. data/spec/sqlite3/constants_spec.rb +65 -0
  82. data/spec/sqlite3/database_status_spec.rb +36 -0
  83. data/spec/sqlite3/status_spec.rb +18 -0
  84. data/spec/sqlite3/version_spec.rb +14 -0
  85. data/spec/sqlite3_spec.rb +53 -0
  86. data/spec/statement_spec.rb +161 -0
  87. data/spec/storage_map_spec.rb +41 -0
  88. data/spec/tap_spec.rb +59 -0
  89. data/spec/text_map_spec.rb +23 -0
  90. data/spec/type_map_spec.rb +17 -0
  91. data/spec/version_spec.rb +15 -0
  92. data/tasks/announce.rake +43 -0
  93. data/tasks/config.rb +107 -0
  94. data/tasks/distribution.rake +77 -0
  95. data/tasks/documentation.rake +32 -0
  96. data/tasks/extension.rake +141 -0
  97. data/tasks/rspec.rake +33 -0
  98. data/tasks/rubyforge.rake +59 -0
  99. data/tasks/utils.rb +80 -0
  100. metadata +237 -0
@@ -0,0 +1,40 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ require 'amalgalite/type_map'
7
+
8
+ module Amalgalite::TypeMaps
9
+ ##
10
+ # An Amalagliate TypeMap that has a one-to-one conversion between SQLite types
11
+ # and Ruby classes
12
+ #
13
+ class StorageMap < ::Amalgalite::TypeMap
14
+ ##
15
+ # A straight logical mapping (for me at least) of basic Ruby classes to SQLite types, if
16
+ # nothing can be found then default to TEXT.
17
+ #
18
+ def bind_type_of( obj )
19
+ case obj
20
+ when Float
21
+ ::Amalgalite::SQLite3::Constants::DataType::FLOAT
22
+ when Fixnum
23
+ ::Amalgalite::SQLite3::Constants::DataType::INTEGER
24
+ when NilClass
25
+ ::Amalgalite::SQLite3::Constants::DataType::NULL
26
+ when ::Amalgalite::Blob
27
+ ::Amalgalite::SQLite3::Constants::DataType::BLOB
28
+ else
29
+ ::Amalgalite::SQLite3::Constants::DataType::TEXT
30
+ end
31
+ end
32
+
33
+ ##
34
+ # Do no mapping, just return the value as it was retrieved from SQLite.
35
+ #
36
+ def result_value_of( delcared_type, value )
37
+ return value
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+ #
6
+ require 'amalgalite/type_map'
7
+
8
+ module Amalgalite::TypeMaps
9
+ ##
10
+ # An Amalagliate TypeMap that converts both bind parameters and result
11
+ # parameters to a String, no matter what.
12
+ #
13
+ class TextMap < ::Amalgalite::TypeMap
14
+ def bind_type_of( obj )
15
+ return ::Amalgalite::SQLite3::Constants::DataType::TEXT
16
+ end
17
+
18
+ def result_value_of( delcared_type, value )
19
+ return value.to_s
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for licensingn details
4
+ #++
5
+
6
+ module Amalgalite
7
+ # Version information for Amagalite
8
+ module Version
9
+
10
+ MAJOR = 0
11
+ MINOR = 10
12
+ BUILD = 1
13
+
14
+ #
15
+ # return the Version as an array of MAJOR, MINOR, BUILD
16
+ #
17
+ def self.to_a
18
+ [MAJOR, MINOR, BUILD]
19
+ end
20
+
21
+ # return the Version as a dotted String MAJOR.MINOR.BUILD
22
+ def self.to_s
23
+ to_a.join(".")
24
+ end
25
+
26
+ # return the Vesion as a hash
27
+ def self.to_hash
28
+ { :major => MAJOR, :minor => MINOR, :build => BUILD }
29
+ end
30
+
31
+ # Version string constant
32
+ STRING = Version.to_s.freeze
33
+ end
34
+
35
+ # Version string constant
36
+ VERSION = Version.to_s.freeze
37
+ end
@@ -0,0 +1,26 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module Amalgalite
7
+ #
8
+ # a class representing the meta information about an SQLite view
9
+ #
10
+ class View
11
+ # the schame this view is assciated with
12
+ attr_accessor :schema
13
+
14
+ # the table name
15
+ attr_reader :name
16
+
17
+ # the original sql that was used to create this table
18
+ attr_reader :sql
19
+
20
+ def initialize( name, sql )
21
+ @name = name
22
+ @sql = sql
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,169 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
5
+
6
+ require 'amalgalite'
7
+ require 'amalgalite/database'
8
+
9
+ class AggregateTest1 < ::Amalgalite::Aggregate
10
+ def initialize
11
+ @name = 'atest1'
12
+ @arity = -1
13
+ @count = 0
14
+ end
15
+ def step( *args )
16
+ @count += 1
17
+ end
18
+ def finalize
19
+ return @count
20
+ end
21
+ end
22
+
23
+
24
+ describe "Aggregate SQL Functions" do
25
+
26
+ before(:each) do
27
+ @schema = IO.read( SpecInfo.test_schema_file )
28
+ @iso_db_file = SpecInfo.make_iso_db
29
+ @iso_db = Amalgalite::Database.new( SpecInfo.make_iso_db )
30
+ end
31
+
32
+ after(:each) do
33
+ File.unlink SpecInfo.test_db if File.exist?( SpecInfo.test_db )
34
+ @iso_db.close
35
+ File.unlink @iso_db_file if File.exist?( @iso_db_file )
36
+ end
37
+
38
+
39
+ it "must have a finalize method implemented" do
40
+ ag = ::Amalgalite::Aggregate.new
41
+ lambda { ag.finalize }.should raise_error( NotImplementedError, /Aggregate#finalize must be implemented/ )
42
+ end
43
+
44
+ it "can define a custom SQL aggregate as a class with N params" do
45
+ @iso_db.define_aggregate("atest1", AggregateTest1 )
46
+ r = @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country")
47
+ r.first['a'].should eql(r.first['c'])
48
+ r.first['a'].should eql(242)
49
+ end
50
+
51
+ it "can remove a custom SQL aggregate by class" do
52
+ @iso_db.define_aggregate("atest1", AggregateTest1 )
53
+ @iso_db.aggregates.size.should eql(1)
54
+ r = @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country")
55
+ r.first['a'].should eql(r.first['c'])
56
+ r.first['a'].should eql(242)
57
+ @iso_db.remove_aggregate( "atest1", AggregateTest1 )
58
+ @iso_db.aggregates.size.should eql(0)
59
+ 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/ )
60
+ end
61
+
62
+ it "can remove a custom SQL aggregate by arity" do
63
+ @iso_db.define_aggregate("atest1", AggregateTest1 )
64
+ @iso_db.aggregates.size.should eql(1)
65
+ r = @iso_db.execute("SELECT atest1(id,name) as a, count(*) as c FROM country")
66
+ r.first['a'].should eql(r.first['c'])
67
+ r.first['a'].should eql(242)
68
+ @iso_db.remove_aggregate( "atest1", -1)
69
+ @iso_db.aggregates.size.should eql(0)
70
+ 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/ )
71
+ end
72
+
73
+ it "can remove all custom SQL aggregates with the same name" do
74
+ class AT2 < AggregateTest1
75
+ def arity() 1; end
76
+ end
77
+ @iso_db.define_aggregate("atest1", AggregateTest1 )
78
+ @iso_db.define_aggregate("atest1", AT2)
79
+ @iso_db.aggregates.size.should eql(2)
80
+ r = @iso_db.execute("SELECT atest1(id,name) as a, atest1(id), count(*) as c FROM country")
81
+ r.first['a'].should eql(r.first['c'])
82
+ r.first['a'].should eql(242)
83
+ @iso_db.remove_aggregate( "atest1" )
84
+ @iso_db.aggregates.size.should eql(0)
85
+ 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/ )
86
+ end
87
+
88
+
89
+
90
+ it "does not allow mixing of arbitrary and mandatory arguments to an SQL function" do
91
+ class AggregateTest2 < AggregateTest1
92
+ def name() "atest2"; end
93
+ def arity() -2; end
94
+ end
95
+ lambda { @iso_db.define_aggregate("atest2", AggregateTest2 ) }.should raise_error( ::Amalgalite::Database::AggregateError,
96
+ /Use only mandatory or arbitrary parameters in an SQL Aggregate, not both/ )
97
+ end
98
+
99
+ it "does not allow outrageous arity" do
100
+ class AggregateTest3 < AggregateTest1
101
+ def name() "atest3"; end
102
+ def arity() 128; end
103
+ end
104
+ lambda { @iso_db.define_aggregate("atest3", AggregateTest3 ) }.should raise_error( ::Amalgalite::SQLite3::Error, /SQLITE_ERROR .* Library used incorrectly/ )
105
+ end
106
+
107
+ it "does not allow registering a function which does not match the defined name " do
108
+ class AggregateTest4 < AggregateTest1
109
+ def name() "name_mismatch"; end
110
+ end
111
+ lambda { @iso_db.define_aggregate("atest4", AggregateTest4 ) }.should raise_error( ::Amalgalite::Database::AggregateError,
112
+ /Aggregate implementation name 'name_mismatch' does not match defined name 'atest4'/)
113
+ end
114
+
115
+ it "handles an error being thrown during the step function" do
116
+ class AggregateTest5 < AggregateTest1
117
+ def initialize
118
+ @name = "atest5"
119
+ @arity = -1
120
+ @count = 0
121
+ end
122
+
123
+ def step( *args )
124
+ @count += 1
125
+ if @count > 50 then
126
+ raise "Stepwise error!" if @count > 50
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ @iso_db.define_aggregate( "atest5", AggregateTest5 )
133
+ lambda { @iso_db.execute( "SELECT atest5(*) AS a FROM country" ) }.should raise_error( ::Amalgalite::SQLite3::Error, /Stepwise error!/ )
134
+ end
135
+
136
+ it "handles an error being thrown during the finalize function" do
137
+ class AggregateTest6 < AggregateTest1
138
+ def initialize
139
+ @name = "atest6"
140
+ @count = 0
141
+ @arity = -1
142
+ end
143
+ def finalize
144
+ raise "Finalize error!"
145
+ end
146
+ end
147
+ @iso_db.define_aggregate( "atest6", AggregateTest6 )
148
+ lambda { @iso_db.execute( "SELECT atest6(*) AS a FROM country" ) }.should raise_error( ::Amalgalite::SQLite3::Error, /Finalize error!/ )
149
+ end
150
+
151
+ it "handles an error being thrown during initialization in the C extension" do
152
+ class AggregateTest7 < AggregateTest1
153
+ @@instance_count = 0
154
+ def initialize
155
+ @name = "atest7"
156
+ @count = 0
157
+ @arity = -1
158
+ if @@instance_count > 0 then
159
+ raise "Initialization error!"
160
+ else
161
+ @@instance_count += 1
162
+ end
163
+ end
164
+ end
165
+ @iso_db.define_aggregate( "atest7", AggregateTest7 )
166
+ lambda { @iso_db.execute( "SELECT atest7(*) AS a FROM country" ) }.should raise_error( ::Amalgalite::SQLite3::Error, /Initialization error!/ )
167
+ end
168
+ end
169
+
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),"spec_helper.rb"))
2
+
3
+ describe Amalgalite do
4
+ end
data/spec/blob_spec.rb ADDED
@@ -0,0 +1,81 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+ require 'amalgalite'
6
+
7
+ describe Amalgalite::Blob do
8
+ DATA_FILE = File.expand_path( File.join( File.dirname(__FILE__), "iso-3166-country.txt" ) )
9
+ before(:each) do
10
+ @blob_db_name = File.join(File.dirname( __FILE__ ), "blob.db")
11
+ File.unlink @blob_db_name if File.exist?( @blob_db_name )
12
+ @db = Amalgalite::Database.new( @blob_db_name )
13
+ @schema_sql = <<-SQL
14
+ CREATE TABLE blobs(
15
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
16
+ name VARCHAR(128) NOT NULL UNIQUE,
17
+ data TEXT );
18
+ SQL
19
+ @db.execute( @schema_sql )
20
+ @junk_file = File.join( File.dirname(__FILE__), "test_output")
21
+ end
22
+
23
+ after(:each) do
24
+ @db.close
25
+ File.unlink @blob_db_name if File.exist?( @blob_db_name )
26
+ File.unlink @junk_file if File.exist?( @junk_file )
27
+ end
28
+
29
+ { :file => DATA_FILE,
30
+ :string => IO.read( DATA_FILE ),
31
+ :io => StringIO.new( IO.read( DATA_FILE ) ) }.each_pair do |style, data |
32
+ describe "inserts a blob from a #{style}" do
33
+ before(:each) do
34
+ column = @db.schema.tables['blobs'].columns['data']
35
+ @db.execute("INSERT INTO blobs(name, data) VALUES ($name, $data)",
36
+ { "$name" => DATA_FILE,
37
+ "$data" => Amalgalite::Blob.new( style => data,
38
+ :column => column ) } )
39
+ @db.execute("VACUUM")
40
+ end
41
+
42
+ after(:each) do
43
+ @db.execute("DELETE FROM blobs")
44
+ data.rewind if data.respond_to?( :rewind )
45
+ end
46
+
47
+ it "and retrieves the data as a single value" do
48
+ all_rows = @db.execute("SELECT name,data FROM blobs")
49
+ all_rows.size.should eql(1)
50
+ all_rows.first['name'].should eql(DATA_FILE)
51
+ all_rows.first['data'].should_not be_incremental
52
+ all_rows.first['data'].to_string_io.string.should eql(IO.read( DATA_FILE ))
53
+ end
54
+
55
+ it "and retrieves the data using incremental IO" do
56
+ all_rows = @db.execute("SELECT * FROM blobs")
57
+ all_rows.size.should eql(1)
58
+ all_rows.first['name'].should eql(DATA_FILE)
59
+ all_rows.first['data'].should be_incremental
60
+ all_rows.first['data'].to_string_io.string.should eql(IO.read( DATA_FILE ))
61
+ end
62
+
63
+ it "writes the data to a file " do
64
+ all_rows = @db.execute("SELECT * FROM blobs")
65
+ all_rows.size.should eql(1)
66
+ all_rows.first['name'].should eql(DATA_FILE)
67
+ all_rows.first['data'].should be_incremental
68
+ all_rows.first['data'].write_to_file( @junk_file )
69
+ IO.read( @junk_file).should eql(IO.read( DATA_FILE ))
70
+ end
71
+ end
72
+ end
73
+
74
+
75
+
76
+ it "raises an error if initialized incorrectly" do
77
+ lambda{ Amalgalite::Blob.new( :file => "/dev/null", :string => "foo" ) }.should raise_error( Amalgalite::Blob::Error )
78
+ end
79
+ end
80
+
81
+
@@ -0,0 +1,23 @@
1
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
2
+ require 'amalgalite'
3
+ require 'amalgalite/boolean'
4
+
5
+ describe Amalgalite::Boolean do
6
+ %w[ True Y Yes T 1 ].each do |v|
7
+ it "converts #{v} to true" do
8
+ Amalgalite::Boolean.to_bool(v).should == true
9
+ end
10
+ end
11
+
12
+ %w[ False F f No n 0 ].each do |v|
13
+ it "converts #{v} to false " do
14
+ Amalgalite::Boolean.to_bool(v).should == false
15
+ end
16
+ end
17
+
18
+ %w[ other things nil ].each do |v|
19
+ it "converts #{v} to nil" do
20
+ Amalgalite::Boolean.to_bool(v).should == nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,165 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper.rb' ) )
5
+
6
+ require 'amalgalite'
7
+ require 'amalgalite/database'
8
+
9
+ class BusyHandlerTest < Amalgalite::BusyHandler
10
+ attr_accessor :call_count
11
+ def initialize( max = 5 )
12
+ @max = max
13
+ @call_count = 0
14
+ end
15
+
16
+ def call( c )
17
+ @call_count += 1
18
+ if call_count >= @max then
19
+ return false
20
+ end
21
+ return true
22
+ end
23
+ end
24
+
25
+ describe "Busy Handlers" do
26
+ before(:each) do
27
+ @db_name = SpecInfo.make_iso_db
28
+ @read_db = Amalgalite::Database.new( @db_name )
29
+ @write_db = Amalgalite::Database.new( @db_name )
30
+ end
31
+
32
+ after(:each) do
33
+ @write_db.close
34
+ @read_db.close
35
+ File.unlink @db_name if File.exist?( @db_name )
36
+ end
37
+
38
+ it "raises NotImplemented if #call is not overwritten" do
39
+ bh = ::Amalgalite::BusyHandler.new
40
+ lambda { bh.call( 42 ) }.should raise_error( ::NotImplementedError, /The busy handler call\(N\) method must be implemented/ )
41
+ end
42
+
43
+ it "can be registered as block" do
44
+ call_count = 0
45
+ @write_db.busy_handler do |x|
46
+ call_count = x
47
+ if call_count >= 20 then
48
+ false
49
+ else
50
+ true
51
+ end
52
+ end
53
+
54
+ # put a read lock on the database
55
+ @read_db.transaction( "DEFERRED" )
56
+
57
+ # put a read lock on the database, but want to go to an exclusive
58
+ @write_db.transaction( "IMMEDIATE" )
59
+
60
+ # do a read operation
61
+ @read_db.execute("SELECT count(*) FROM subcountry")
62
+
63
+ # attempt to do a write operation and commit it
64
+ @write_db.execute("DELETE FROM subcountry")
65
+ lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
66
+ call_count.should == 20
67
+ end
68
+
69
+ it "can be registered as lambda" do
70
+ call_count = 0
71
+ callable = lambda do |x|
72
+ call_count = x
73
+ if call_count >= 40 then
74
+ false
75
+ else
76
+ true
77
+ end
78
+ end
79
+
80
+ @write_db.busy_handler( callable )
81
+
82
+ # put a read lock on the database
83
+ @read_db.transaction( "DEFERRED" )
84
+
85
+ # put a read lock on the database, but want to go to an exclusive
86
+ @write_db.transaction( "IMMEDIATE" )
87
+
88
+ # do a read operation
89
+ @read_db.execute("SELECT count(*) FROM subcountry")
90
+
91
+ # attempt to do a write operation and commit it
92
+ @write_db.execute("DELETE FROM subcountry")
93
+ lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
94
+ call_count.should == 40
95
+ end
96
+
97
+ it "can be registered as a class" do
98
+ h = BusyHandlerTest.new( 10 )
99
+ @write_db.busy_handler( h )
100
+
101
+ # put a read lock on the database
102
+ @read_db.transaction( "DEFERRED" )
103
+
104
+ # put a read lock on the database, but want to go to an exclusive
105
+ @write_db.transaction( "IMMEDIATE" )
106
+
107
+ # do a read operation
108
+ @read_db.execute("SELECT count(*) FROM subcountry")
109
+
110
+ # attempt to do a write operation and commit it
111
+ @write_db.execute("DELETE FROM subcountry")
112
+ lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
113
+ h.call_count.should == 10
114
+ end
115
+
116
+ it "has a default timeout class available " do
117
+ to = ::Amalgalite::BusyTimeout.new( 5, 10 )
118
+ @write_db.busy_handler( to )
119
+
120
+ # put a read lock on the database
121
+ @read_db.transaction( "DEFERRED" )
122
+
123
+ # put a read lock on the database, but want to go to an exclusive
124
+ @write_db.transaction( "IMMEDIATE" )
125
+
126
+ # do a read operation
127
+ @read_db.execute("SELECT count(*) FROM subcountry")
128
+
129
+ # attempt to do a write operation and commit it
130
+ @write_db.execute("DELETE FROM subcountry")
131
+ before = Time.now
132
+ lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
133
+ after = Time.now
134
+ to.call_count.should > 5
135
+ (after - before).should > 0.05
136
+ end
137
+
138
+ it "cannot register a block with the wrong arity" do
139
+ lambda do
140
+ @write_db.define_busy_handler { |x,y| puts "What!" }
141
+ end.should raise_error( ::Amalgalite::Database::BusyHandlerError, /A busy handler expects 1 and only 1 argument/ )
142
+ end
143
+
144
+ it "can remove a busy handler" do
145
+ bht = BusyHandlerTest.new
146
+
147
+ @write_db.busy_handler( bht )
148
+
149
+ # put a read lock on the database
150
+ @read_db.transaction( "DEFERRED" )
151
+
152
+ # put a read lock on the database, but want to go to an exclusive
153
+ @write_db.transaction( "IMMEDIATE" )
154
+
155
+ # do a read operation
156
+ @read_db.execute("SELECT count(*) FROM subcountry")
157
+
158
+ # attempt to do a write operation and commit it
159
+ @write_db.execute("DELETE FROM subcountry")
160
+ @write_db.remove_busy_handler
161
+ lambda { @write_db.execute("COMMIT"); }.should raise_error( ::Amalgalite::SQLite3::Error, /database is locked/ )
162
+ bht.call_count.should == 0
163
+ end
164
+
165
+ end