sqlite3 1.3.5 → 1.3.13
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.
- 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
|