sqlite3 1.3.5 → 1.3.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +84 -0
- data/Gemfile +15 -0
- data/Manifest.txt +2 -0
- data/README.rdoc +29 -6
- data/ext/sqlite3/database.c +131 -27
- data/ext/sqlite3/extconf.rb +31 -7
- data/ext/sqlite3/sqlite3.c +112 -0
- data/ext/sqlite3/sqlite3_ruby.h +12 -4
- data/ext/sqlite3/statement.c +33 -22
- data/faq/faq.yml +1 -1
- data/lib/sqlite3.rb +6 -1
- data/lib/sqlite3/database.rb +36 -24
- data/lib/sqlite3/pragmas.rb +357 -49
- data/lib/sqlite3/resultset.rb +94 -25
- data/lib/sqlite3/statement.rb +13 -17
- data/lib/sqlite3/version.rb +2 -2
- data/setup.rb +2 -2
- data/tasks/gem.rake +12 -6
- data/tasks/native.rake +22 -7
- data/tasks/vendor_sqlite3.rake +69 -20
- data/test/helper.rb +17 -2
- data/test/test_backup.rb +2 -2
- data/test/test_collation.rb +1 -1
- data/test/test_database.rb +102 -7
- data/test/test_database_readonly.rb +10 -3
- data/test/test_deprecated.rb +8 -1
- data/test/test_encoding.rb +35 -1
- data/test/test_integration.rb +36 -15
- data/test/test_integration_open_close.rb +1 -1
- data/test/test_integration_pending.rb +2 -2
- data/test/test_integration_resultset.rb +6 -3
- data/test/test_integration_statement.rb +2 -2
- data/test/test_result_set.rb +37 -0
- data/test/test_sqlite3.rb +13 -1
- data/test/test_statement.rb +26 -4
- data/test/test_statement_execute.rb +1 -1
- metadata +125 -121
- data/.gemtest +0 -0
data/test/helper.rb
CHANGED
@@ -1,3 +1,18 @@
|
|
1
1
|
require 'sqlite3'
|
2
|
-
require '
|
3
|
-
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
unless RUBY_VERSION >= "1.9"
|
5
|
+
require 'iconv'
|
6
|
+
end
|
7
|
+
|
8
|
+
module SQLite3
|
9
|
+
class TestCase < Minitest::Test
|
10
|
+
alias :assert_not_equal :refute_equal
|
11
|
+
alias :assert_not_nil :refute_nil
|
12
|
+
alias :assert_raise :assert_raises
|
13
|
+
|
14
|
+
def assert_nothing_raised
|
15
|
+
yield
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/test/test_backup.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
module SQLite3
|
4
|
-
class TestBackup <
|
4
|
+
class TestBackup < SQLite3::TestCase
|
5
5
|
def setup
|
6
6
|
@sdb = SQLite3::Database.new(':memory:')
|
7
7
|
@ddb = SQLite3::Database.new(':memory:')
|
data/test/test_collation.rb
CHANGED
data/test/test_database.rb
CHANGED
@@ -1,17 +1,50 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'pathname'
|
2
4
|
|
3
5
|
module SQLite3
|
4
|
-
class TestDatabase <
|
6
|
+
class TestDatabase < SQLite3::TestCase
|
5
7
|
attr_reader :db
|
6
8
|
|
7
9
|
def setup
|
8
10
|
@db = SQLite3::Database.new(':memory:')
|
11
|
+
super
|
9
12
|
end
|
10
13
|
|
11
14
|
def test_segv
|
12
15
|
assert_raises(TypeError) { SQLite3::Database.new 1 }
|
13
16
|
end
|
14
17
|
|
18
|
+
def test_db_filename
|
19
|
+
tf = nil
|
20
|
+
assert_equal '', @db.filename('main')
|
21
|
+
tf = Tempfile.new 'thing'
|
22
|
+
@db = SQLite3::Database.new tf.path
|
23
|
+
assert_equal File.expand_path(tf.path), File.expand_path(@db.filename('main'))
|
24
|
+
ensure
|
25
|
+
tf.unlink if tf
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_filename
|
29
|
+
tf = nil
|
30
|
+
assert_equal '', @db.filename
|
31
|
+
tf = Tempfile.new 'thing'
|
32
|
+
@db = SQLite3::Database.new tf.path
|
33
|
+
assert_equal File.expand_path(tf.path), File.expand_path(@db.filename)
|
34
|
+
ensure
|
35
|
+
tf.unlink if tf
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_filename_with_attachment
|
39
|
+
tf = nil
|
40
|
+
assert_equal '', @db.filename
|
41
|
+
tf = Tempfile.new 'thing'
|
42
|
+
@db.execute "ATTACH DATABASE '#{tf.path}' AS 'testing'"
|
43
|
+
assert_equal File.expand_path(tf.path), File.expand_path(@db.filename('testing'))
|
44
|
+
ensure
|
45
|
+
tf.unlink if tf
|
46
|
+
end
|
47
|
+
|
15
48
|
def test_bignum
|
16
49
|
num = 4907021672125087844
|
17
50
|
db.execute 'CREATE TABLE "employees" ("token" integer(8), "name" varchar(20) NOT NULL)'
|
@@ -22,9 +55,9 @@ module SQLite3
|
|
22
55
|
|
23
56
|
def test_blob
|
24
57
|
@db.execute("CREATE TABLE blobs ( id INTEGER, hash BLOB(10) )")
|
25
|
-
|
26
|
-
@db.execute("INSERT INTO blobs VALUES (0, ?)", [
|
27
|
-
assert_equal [[0,
|
58
|
+
blob = Blob.new("foo\0bar")
|
59
|
+
@db.execute("INSERT INTO blobs VALUES (0, ?)", [blob])
|
60
|
+
assert_equal [[0, blob, blob.length, blob.length*2]], @db.execute("SELECT id, hash, length(hash), length(hex(hash)) FROM blobs")
|
28
61
|
end
|
29
62
|
|
30
63
|
def test_get_first_row
|
@@ -60,6 +93,14 @@ module SQLite3
|
|
60
93
|
assert_equal [[30]], @db.execute("select number from items")
|
61
94
|
end
|
62
95
|
|
96
|
+
def test_batch_last_comment_is_processed
|
97
|
+
# FIXME: nil as a successful return value is kinda dumb
|
98
|
+
assert_nil @db.execute_batch <<-eosql
|
99
|
+
CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT);
|
100
|
+
-- omg
|
101
|
+
eosql
|
102
|
+
end
|
103
|
+
|
63
104
|
def test_new
|
64
105
|
db = SQLite3::Database.new(':memory:')
|
65
106
|
assert db
|
@@ -77,8 +118,12 @@ module SQLite3
|
|
77
118
|
# determine if Ruby is running on Big Endian platform
|
78
119
|
utf16 = ([1].pack("I") == [1].pack("N")) ? "UTF-16BE" : "UTF-16LE"
|
79
120
|
|
80
|
-
|
81
|
-
|
121
|
+
if RUBY_VERSION >= "1.9"
|
122
|
+
db = SQLite3::Database.new(':memory:'.encode(utf16), :utf16 => true)
|
123
|
+
else
|
124
|
+
db = SQLite3::Database.new(Iconv.conv(utf16, 'UTF-8', ':memory:'),
|
125
|
+
:utf16 => true)
|
126
|
+
end
|
82
127
|
assert db
|
83
128
|
end
|
84
129
|
|
@@ -97,12 +142,33 @@ module SQLite3
|
|
97
142
|
assert thing.closed?
|
98
143
|
end
|
99
144
|
|
145
|
+
def test_block_closes_self_even_raised
|
146
|
+
thing = nil
|
147
|
+
begin
|
148
|
+
SQLite3::Database.new(':memory:') do |db|
|
149
|
+
thing = db
|
150
|
+
raise
|
151
|
+
end
|
152
|
+
rescue
|
153
|
+
end
|
154
|
+
assert thing.closed?
|
155
|
+
end
|
156
|
+
|
100
157
|
def test_prepare
|
101
158
|
db = SQLite3::Database.new(':memory:')
|
102
159
|
stmt = db.prepare('select "hello world"')
|
103
160
|
assert_instance_of(SQLite3::Statement, stmt)
|
104
161
|
end
|
105
162
|
|
163
|
+
def test_block_prepare_does_not_double_close
|
164
|
+
db = SQLite3::Database.new(':memory:')
|
165
|
+
r = db.prepare('select "hello world"') do |stmt|
|
166
|
+
stmt.close
|
167
|
+
:foo
|
168
|
+
end
|
169
|
+
assert_equal :foo, r
|
170
|
+
end
|
171
|
+
|
106
172
|
def test_total_changes
|
107
173
|
db = SQLite3::Database.new(':memory:')
|
108
174
|
db.execute("create table foo ( a integer primary key, b text )")
|
@@ -223,18 +289,47 @@ module SQLite3
|
|
223
289
|
assert_equal [2.2, 'foo', nil], called_with
|
224
290
|
end
|
225
291
|
|
292
|
+
def test_call_func_blob
|
293
|
+
called_with = nil
|
294
|
+
@db.define_function("hello") do |a, b|
|
295
|
+
called_with = [a, b, a.length]
|
296
|
+
nil
|
297
|
+
end
|
298
|
+
blob = Blob.new("a\0fine\0kettle\0of\0fish")
|
299
|
+
@db.execute("select hello(?, length(?))", [blob, blob])
|
300
|
+
assert_equal [blob, blob.length, 21], called_with
|
301
|
+
end
|
302
|
+
|
226
303
|
def test_function_return
|
227
304
|
@db.define_function("hello") { |a| 10 }
|
228
305
|
assert_equal [10], @db.execute("select hello('world')").first
|
229
306
|
end
|
230
307
|
|
231
308
|
def test_function_return_types
|
232
|
-
[10, 2.2, nil, "foo"].each do |thing|
|
309
|
+
[10, 2.2, nil, "foo", Blob.new("foo\0bar")].each do |thing|
|
233
310
|
@db.define_function("hello") { |a| thing }
|
234
311
|
assert_equal [thing], @db.execute("select hello('world')").first
|
235
312
|
end
|
236
313
|
end
|
237
314
|
|
315
|
+
def test_function_gc_segfault
|
316
|
+
@db.create_function("bug", -1) { |func, *values| func.result = values.join }
|
317
|
+
# With a lot of data and a lot of threads, try to induce a GC segfault.
|
318
|
+
params = Array.new(127, "?" * 28000)
|
319
|
+
proc = Proc.new {
|
320
|
+
db.execute("select bug(#{Array.new(params.length, "?").join(",")})", params)
|
321
|
+
}
|
322
|
+
m = Mutex.new
|
323
|
+
30.times.map { Thread.new { m.synchronize { proc.call } } }.each(&:join)
|
324
|
+
end
|
325
|
+
|
326
|
+
def test_function_return_type_round_trip
|
327
|
+
[10, 2.2, nil, "foo", Blob.new("foo\0bar")].each do |thing|
|
328
|
+
@db.define_function("hello") { |a| a }
|
329
|
+
assert_equal [thing], @db.execute("select hello(hello(?))", [thing]).first
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
238
333
|
def test_define_function_closed
|
239
334
|
@db.close
|
240
335
|
assert_raise(SQLite3::Exception) do
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
module SQLite3
|
4
|
-
class TestDatabaseReadonly <
|
4
|
+
class TestDatabaseReadonly < SQLite3::TestCase
|
5
5
|
def setup
|
6
|
-
File.unlink 'test-readonly.db' if File.
|
6
|
+
File.unlink 'test-readonly.db' if File.exist?('test-readonly.db')
|
7
7
|
@db = SQLite3::Database.new('test-readonly.db')
|
8
8
|
@db.execute("CREATE TABLE foos (id integer)")
|
9
9
|
@db.close
|
@@ -11,7 +11,7 @@ module SQLite3
|
|
11
11
|
|
12
12
|
def teardown
|
13
13
|
@db.close unless @db.closed?
|
14
|
-
File.unlink 'test-readonly.db'
|
14
|
+
File.unlink 'test-readonly.db' if File.exist?('test-readonly.db')
|
15
15
|
end
|
16
16
|
|
17
17
|
def test_open_readonly_database
|
@@ -19,6 +19,13 @@ module SQLite3
|
|
19
19
|
assert @db.readonly?
|
20
20
|
end
|
21
21
|
|
22
|
+
def test_open_readonly_not_exists_database
|
23
|
+
File.unlink 'test-readonly.db'
|
24
|
+
assert_raise(SQLite3::CantOpenException) do
|
25
|
+
@db = SQLite3::Database.new('test-readonly.db', :readonly => true)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
22
29
|
def test_insert_readonly_database
|
23
30
|
@db = SQLite3::Database.new('test-readonly.db', :readonly => true)
|
24
31
|
assert_raise(SQLite3::ReadOnlyException) do
|
data/test/test_deprecated.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
module SQLite3
|
4
|
-
class TestDeprecated <
|
4
|
+
class TestDeprecated < SQLite3::TestCase
|
5
|
+
attr_reader :db
|
6
|
+
|
5
7
|
def setup
|
6
8
|
super
|
7
9
|
@warn_before = $-w
|
8
10
|
$-w = false
|
9
11
|
@db = SQLite3::Database.new(':memory:')
|
12
|
+
@db.execute 'CREATE TABLE test_table (name text, age int)'
|
10
13
|
end
|
11
14
|
|
12
15
|
def teardown
|
@@ -14,6 +17,10 @@ module SQLite3
|
|
14
17
|
$-w = @warn_before
|
15
18
|
end
|
16
19
|
|
20
|
+
def test_query_with_many_bind_params_not_nil
|
21
|
+
assert_equal [[1, 2]], db.query('select ?, ?', 1, 2).to_a
|
22
|
+
end
|
23
|
+
|
17
24
|
def test_execute_with_many_bind_params_not_nil
|
18
25
|
assert_equal [[1, 2]], @db.execute("select ?, ?", 1, 2).to_a
|
19
26
|
end
|
data/test/test_encoding.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'helper'
|
4
4
|
|
5
5
|
module SQLite3
|
6
|
-
class TestEncoding <
|
6
|
+
class TestEncoding < SQLite3::TestCase
|
7
7
|
def setup
|
8
8
|
@db = SQLite3::Database.new(':memory:')
|
9
9
|
@create = "create table ex(id int, data string)"
|
@@ -11,6 +11,40 @@ module SQLite3
|
|
11
11
|
@db.execute(@create);
|
12
12
|
end
|
13
13
|
|
14
|
+
def test_select_encoding_on_utf_16
|
15
|
+
str = "foo"
|
16
|
+
utf16 = ([1].pack("I") == [1].pack("N")) ? "UTF-16BE" : "UTF-16LE"
|
17
|
+
db = SQLite3::Database.new(':memory:'.encode(utf16))
|
18
|
+
db.execute @create
|
19
|
+
db.execute "insert into ex (id, data) values (1, \"#{str}\")"
|
20
|
+
|
21
|
+
stmt = db.prepare 'select * from ex where data = ?'
|
22
|
+
['US-ASCII', utf16, 'EUC-JP', 'UTF-8'].each do |enc|
|
23
|
+
stmt.bind_param 1, str.encode(enc)
|
24
|
+
assert_equal 1, stmt.to_a.length
|
25
|
+
stmt.reset!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_insert_encoding
|
30
|
+
str = "foo"
|
31
|
+
utf16 = ([1].pack("I") == [1].pack("N")) ? "UTF-16BE" : "UTF-16LE"
|
32
|
+
db = SQLite3::Database.new(':memory:'.encode(utf16))
|
33
|
+
db.execute @create
|
34
|
+
stmt = db.prepare @insert
|
35
|
+
|
36
|
+
['US-ASCII', utf16, 'EUC-JP', 'UTF-8'].each_with_index do |enc,i|
|
37
|
+
stmt.bind_param 1, i
|
38
|
+
stmt.bind_param 2, str.encode(enc)
|
39
|
+
stmt.to_a
|
40
|
+
stmt.reset!
|
41
|
+
end
|
42
|
+
|
43
|
+
db.execute('select data from ex').flatten.each do |s|
|
44
|
+
assert_equal str, s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
14
48
|
def test_default_internal_is_honored
|
15
49
|
warn_before = $-w
|
16
50
|
$-w = false
|
data/test/test_integration.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
class TC_Database_Integration <
|
3
|
+
class TC_Database_Integration < SQLite3::TestCase
|
4
4
|
def setup
|
5
5
|
@db = SQLite3::Database.new(":memory:")
|
6
6
|
@db.transaction do
|
@@ -21,12 +21,14 @@ class TC_Database_Integration < Test::Unit::TestCase
|
|
21
21
|
|
22
22
|
def test_table_info_with_defaults_for_version_3_3_8_and_higher
|
23
23
|
@db.transaction do
|
24
|
-
@db.execute "create table defaults_test ( a string default NULL, b string default 'Hello' )"
|
24
|
+
@db.execute "create table defaults_test ( a string default NULL, b string default 'Hello', c string default '--- []\n' )"
|
25
25
|
data = @db.table_info( "defaults_test" )
|
26
26
|
assert_equal({"name" => "a", "type" => "string", "dflt_value" => nil, "notnull" => 0, "cid" => 0, "pk" => 0},
|
27
27
|
data[0])
|
28
28
|
assert_equal({"name" => "b", "type" => "string", "dflt_value" => "Hello", "notnull" => 0, "cid" => 1, "pk" => 0},
|
29
29
|
data[1])
|
30
|
+
assert_equal({"name" => "c", "type" => "string", "dflt_value" => "--- []\n", "notnull" => 0, "cid" => 2, "pk" => 0},
|
31
|
+
data[2])
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
@@ -236,7 +238,7 @@ class TC_Database_Integration < Test::Unit::TestCase
|
|
236
238
|
|
237
239
|
def test_execute2_with_block_with_bind_with_match
|
238
240
|
called = 0
|
239
|
-
@db.execute2( "select * from foo where a = ?", 1 ) do
|
241
|
+
@db.execute2( "select * from foo where a = ?", 1 ) do
|
240
242
|
called += 1
|
241
243
|
end
|
242
244
|
assert_equal 2, called
|
@@ -497,6 +499,10 @@ class TC_Database_Integration < Test::Unit::TestCase
|
|
497
499
|
|
498
500
|
value = @db.get_first_value( "select accumulate(a) from foo" )
|
499
501
|
assert_equal 6, value
|
502
|
+
|
503
|
+
# calling #get_first_value twice don't add up to the latest result
|
504
|
+
value = @db.get_first_value( "select accumulate(a) from foo" )
|
505
|
+
assert_equal 6, value
|
500
506
|
end
|
501
507
|
|
502
508
|
def test_create_aggregate_with_block
|
@@ -528,21 +534,36 @@ class TC_Database_Integration < Test::Unit::TestCase
|
|
528
534
|
assert_equal 0, value
|
529
535
|
end
|
530
536
|
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
537
|
+
class AggregateHandler
|
538
|
+
class << self
|
539
|
+
def arity; 1; end
|
540
|
+
def text_rep; SQLite3::Constants::TextRep::ANY; end
|
541
|
+
def name; "multiply"; end
|
542
|
+
end
|
543
|
+
def step(ctx, a)
|
544
|
+
ctx[:buffer] ||= 1
|
545
|
+
ctx[:buffer] *= a.to_i
|
546
|
+
end
|
547
|
+
def finalize(ctx); ctx.result = ctx[:buffer]; end
|
548
|
+
end
|
549
|
+
|
550
|
+
def test_aggregate_initialized_twice
|
551
|
+
initialized = 0
|
552
|
+
handler = Class.new(AggregateHandler) do
|
553
|
+
define_method(:initialize) do
|
554
|
+
initialized += 1
|
555
|
+
super()
|
541
556
|
end
|
542
|
-
def finalize(ctx); ctx.result = ctx[:buffer]; end
|
543
557
|
end
|
544
558
|
|
545
|
-
@db.create_aggregate_handler
|
559
|
+
@db.create_aggregate_handler handler
|
560
|
+
@db.get_first_value( "select multiply(a) from foo" )
|
561
|
+
@db.get_first_value( "select multiply(a) from foo" )
|
562
|
+
assert_equal 2, initialized
|
563
|
+
end
|
564
|
+
|
565
|
+
def test_create_aggregate_handler
|
566
|
+
@db.create_aggregate_handler AggregateHandler
|
546
567
|
value = @db.get_first_value( "select multiply(a) from foo" )
|
547
568
|
assert_equal 6, value
|
548
569
|
end
|
@@ -3,7 +3,7 @@ require 'helper'
|
|
3
3
|
require 'thread'
|
4
4
|
require 'benchmark'
|
5
5
|
|
6
|
-
class TC_Integration_Pending <
|
6
|
+
class TC_Integration_Pending < SQLite3::TestCase
|
7
7
|
def setup
|
8
8
|
@db = SQLite3::Database.new("test.db")
|
9
9
|
@db.transaction do
|
@@ -69,7 +69,7 @@ class TC_Integration_Pending < Test::Unit::TestCase
|
|
69
69
|
end
|
70
70
|
sleep 1
|
71
71
|
|
72
|
-
@db.busy_handler do
|
72
|
+
@db.busy_handler do
|
73
73
|
handler_call_count += 1
|
74
74
|
false
|
75
75
|
end
|