sqlite3 1.3.13 → 1.4.2
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 +5 -5
- data/.gemtest +0 -0
- data/.travis.yml +33 -0
- data/CHANGELOG.rdoc +27 -1
- data/Gemfile +6 -4
- data/Manifest.txt +12 -4
- data/README.rdoc +1 -1
- data/Rakefile +0 -2
- data/appveyor.yml +36 -0
- data/ext/sqlite3/aggregator.c +273 -0
- data/ext/sqlite3/aggregator.h +12 -0
- data/ext/sqlite3/database.c +140 -201
- data/ext/sqlite3/database.h +2 -0
- data/ext/sqlite3/exception.c +6 -2
- data/ext/sqlite3/extconf.rb +39 -10
- data/ext/sqlite3/sqlite3.c +10 -1
- data/ext/sqlite3/sqlite3_ruby.h +0 -7
- data/ext/sqlite3/statement.c +13 -18
- data/lib/sqlite3/constants.rb +1 -0
- data/lib/sqlite3/database.rb +196 -51
- data/lib/sqlite3/errors.rb +1 -10
- data/lib/sqlite3/pragmas.rb +7 -7
- data/lib/sqlite3/resultset.rb +2 -10
- data/lib/sqlite3/version.rb +3 -3
- data/{tasks → rakelib}/faq.rake +0 -0
- data/{tasks → rakelib}/gem.rake +6 -4
- data/{tasks → rakelib}/native.rake +4 -0
- data/{tasks → rakelib}/vendor_sqlite3.rake +0 -0
- data/test/test_database.rb +79 -6
- data/test/test_database_flags.rb +95 -0
- data/test/test_database_readwrite.rb +41 -0
- data/test/test_integration.rb +12 -81
- data/test/test_integration_aggregate.rb +336 -0
- data/test/test_integration_resultset.rb +0 -17
- data/test/test_statement.rb +11 -8
- metadata +56 -27
data/test/test_database.rb
CHANGED
@@ -12,7 +12,7 @@ module SQLite3
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_segv
|
15
|
-
assert_raises
|
15
|
+
assert_raises { SQLite3::Database.new 1 }
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_db_filename
|
@@ -45,6 +45,24 @@ module SQLite3
|
|
45
45
|
tf.unlink if tf
|
46
46
|
end
|
47
47
|
|
48
|
+
def test_error_code
|
49
|
+
begin
|
50
|
+
db.execute 'SELECT'
|
51
|
+
rescue SQLite3::SQLException => e
|
52
|
+
end
|
53
|
+
assert_equal 1, e.code
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_extended_error_code
|
57
|
+
db.extended_result_codes = true
|
58
|
+
db.execute 'CREATE TABLE "employees" ("token" integer NOT NULL)'
|
59
|
+
begin
|
60
|
+
db.execute 'INSERT INTO employees (token) VALUES (NULL)'
|
61
|
+
rescue SQLite3::ConstraintException => e
|
62
|
+
end
|
63
|
+
assert_equal 1299, e.code
|
64
|
+
end
|
65
|
+
|
48
66
|
def test_bignum
|
49
67
|
num = 4907021672125087844
|
50
68
|
db.execute 'CREATE TABLE "employees" ("token" integer(8), "name" varchar(20) NOT NULL)'
|
@@ -66,15 +84,17 @@ module SQLite3
|
|
66
84
|
|
67
85
|
def test_get_first_row_with_type_translation_and_hash_results
|
68
86
|
@db.results_as_hash = true
|
69
|
-
|
87
|
+
@db.type_translation = true
|
88
|
+
assert_equal({"1"=>1}, @db.get_first_row('SELECT 1'))
|
70
89
|
end
|
71
90
|
|
72
91
|
def test_execute_with_type_translation_and_hash
|
73
92
|
@db.results_as_hash = true
|
93
|
+
@db.type_translation = true
|
74
94
|
rows = []
|
75
95
|
@db.execute('SELECT 1') { |row| rows << row }
|
76
96
|
|
77
|
-
assert_equal({
|
97
|
+
assert_equal({"1"=>1}, rows.first)
|
78
98
|
end
|
79
99
|
|
80
100
|
def test_encoding
|
@@ -101,6 +121,59 @@ module SQLite3
|
|
101
121
|
eosql
|
102
122
|
end
|
103
123
|
|
124
|
+
def test_execute_batch2
|
125
|
+
@db.results_as_hash = true
|
126
|
+
return_value = @db.execute_batch2 <<-eosql
|
127
|
+
CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT, name string);
|
128
|
+
INSERT INTO items (name) VALUES ("foo");
|
129
|
+
INSERT INTO items (name) VALUES ("bar");
|
130
|
+
SELECT * FROM items;
|
131
|
+
eosql
|
132
|
+
assert_equal return_value, [{"id"=>"1","name"=>"foo"}, {"id"=>"2", "name"=>"bar"}]
|
133
|
+
|
134
|
+
return_value = @db.execute_batch2('SELECT * FROM items;') do |result|
|
135
|
+
result["id"] = result["id"].to_i
|
136
|
+
result
|
137
|
+
end
|
138
|
+
assert_equal return_value, [{"id"=>1,"name"=>"foo"}, {"id"=>2, "name"=>"bar"}]
|
139
|
+
|
140
|
+
return_value = @db.execute_batch2('INSERT INTO items (name) VALUES ("oof")')
|
141
|
+
assert_equal return_value, []
|
142
|
+
|
143
|
+
return_value = @db.execute_batch2(
|
144
|
+
'CREATE TABLE employees (id integer PRIMARY KEY AUTOINCREMENT, name string, age integer(3));
|
145
|
+
INSERT INTO employees (age) VALUES (30);
|
146
|
+
INSERT INTO employees (age) VALUES (40);
|
147
|
+
INSERT INTO employees (age) VALUES (20);
|
148
|
+
SELECT age FROM employees;') do |result|
|
149
|
+
result["age"] = result["age"].to_i
|
150
|
+
result
|
151
|
+
end
|
152
|
+
assert_equal return_value, [{"age"=>30}, {"age"=>40}, {"age"=>20}]
|
153
|
+
|
154
|
+
return_value = @db.execute_batch2('SELECT name FROM employees');
|
155
|
+
assert_equal return_value, [{"name"=>nil}, {"name"=>nil}, {"name"=>nil}]
|
156
|
+
|
157
|
+
@db.results_as_hash = false
|
158
|
+
return_value = @db.execute_batch2(
|
159
|
+
'CREATE TABLE managers (id integer PRIMARY KEY AUTOINCREMENT, age integer(3));
|
160
|
+
INSERT INTO managers (age) VALUES (50);
|
161
|
+
INSERT INTO managers (age) VALUES (60);
|
162
|
+
SELECT id, age from managers;') do |result|
|
163
|
+
result = result.map do |res|
|
164
|
+
res.to_i
|
165
|
+
end
|
166
|
+
result
|
167
|
+
end
|
168
|
+
assert_equal return_value, [[1, 50], [2, 60]]
|
169
|
+
|
170
|
+
assert_raises (RuntimeError) do
|
171
|
+
# "names" is not a valid column
|
172
|
+
@db.execute_batch2 'INSERT INTO items (names) VALUES ("bazz")'
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
104
177
|
def test_new
|
105
178
|
db = SQLite3::Database.new(':memory:')
|
106
179
|
assert db
|
@@ -181,7 +254,7 @@ module SQLite3
|
|
181
254
|
db.execute("create table foo ( a integer primary key, b text )")
|
182
255
|
db.execute("insert into foo (b) values ('hello')")
|
183
256
|
rows = db.execute("select * from foo")
|
184
|
-
assert_equal [{
|
257
|
+
assert_equal [{"a"=>1, "b"=>"hello"}], rows
|
185
258
|
end
|
186
259
|
|
187
260
|
def test_execute_yields_hash
|
@@ -189,7 +262,7 @@ module SQLite3
|
|
189
262
|
db.execute("create table foo ( a integer primary key, b text )")
|
190
263
|
db.execute("insert into foo (b) values ('hello')")
|
191
264
|
db.execute("select * from foo") do |row|
|
192
|
-
assert_equal({
|
265
|
+
assert_equal({"a"=>1, "b"=>"hello"}, row)
|
193
266
|
end
|
194
267
|
end
|
195
268
|
|
@@ -384,7 +457,7 @@ module SQLite3
|
|
384
457
|
def call action, a, b, c, d; nil end
|
385
458
|
}.new
|
386
459
|
stmt = @db.prepare("select 'fooooo'")
|
387
|
-
|
460
|
+
assert_nil stmt.step
|
388
461
|
end
|
389
462
|
|
390
463
|
def test_authorizer_fail
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module SQLite3
|
4
|
+
class TestDatabaseFlags < SQLite3::TestCase
|
5
|
+
def setup
|
6
|
+
File.unlink 'test-flags.db' if File.exist?('test-flags.db')
|
7
|
+
@db = SQLite3::Database.new('test-flags.db')
|
8
|
+
@db.execute("CREATE TABLE foos (id integer)")
|
9
|
+
@db.close
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
@db.close unless @db.closed?
|
14
|
+
File.unlink 'test-flags.db' if File.exist?('test-flags.db')
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_open_database_flags_constants
|
18
|
+
defined_to_date = [:READONLY, :READWRITE, :CREATE, :DELETEONCLOSE,
|
19
|
+
:EXCLUSIVE, :MAIN_DB, :TEMP_DB, :TRANSIENT_DB,
|
20
|
+
:MAIN_JOURNAL, :TEMP_JOURNAL, :SUBJOURNAL,
|
21
|
+
:MASTER_JOURNAL, :NOMUTEX, :FULLMUTEX]
|
22
|
+
if SQLite3::SQLITE_VERSION_NUMBER > 3007002
|
23
|
+
defined_to_date += [:AUTOPROXY, :SHAREDCACHE, :PRIVATECACHE, :WAL]
|
24
|
+
end
|
25
|
+
if SQLite3::SQLITE_VERSION_NUMBER > 3007007
|
26
|
+
defined_to_date += [:URI]
|
27
|
+
end
|
28
|
+
if SQLite3::SQLITE_VERSION_NUMBER > 3007013
|
29
|
+
defined_to_date += [:MEMORY]
|
30
|
+
end
|
31
|
+
assert defined_to_date.sort == SQLite3::Constants::Open.constants.sort
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_open_database_flags_conflicts_with_readonly
|
35
|
+
assert_raise(RuntimeError) do
|
36
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => 2, :readonly => true)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_open_database_flags_conflicts_with_readwrite
|
41
|
+
assert_raise(RuntimeError) do
|
42
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => 2, :readwrite => true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_open_database_readonly_flags
|
47
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => SQLite3::Constants::Open::READONLY)
|
48
|
+
assert @db.readonly?
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_open_database_readwrite_flags
|
52
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => SQLite3::Constants::Open::READWRITE)
|
53
|
+
assert !@db.readonly?
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_open_database_readonly_flags_cant_open
|
57
|
+
File.unlink 'test-flags.db'
|
58
|
+
assert_raise(SQLite3::CantOpenException) do
|
59
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => SQLite3::Constants::Open::READONLY)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_open_database_readwrite_flags_cant_open
|
64
|
+
File.unlink 'test-flags.db'
|
65
|
+
assert_raise(SQLite3::CantOpenException) do
|
66
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => SQLite3::Constants::Open::READWRITE)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_open_database_misuse_flags
|
71
|
+
assert_raise(SQLite3::MisuseException) do
|
72
|
+
flags = SQLite3::Constants::Open::READONLY | SQLite3::Constants::Open::READWRITE # <== incompatible flags
|
73
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => flags)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_open_database_create_flags
|
78
|
+
File.unlink 'test-flags.db'
|
79
|
+
flags = SQLite3::Constants::Open::READWRITE | SQLite3::Constants::Open::CREATE
|
80
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => flags) do |db|
|
81
|
+
db.execute("CREATE TABLE foos (id integer)")
|
82
|
+
db.execute("INSERT INTO foos (id) VALUES (12)")
|
83
|
+
end
|
84
|
+
assert File.exist?('test-flags.db')
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_open_database_exotic_flags
|
88
|
+
flags = SQLite3::Constants::Open::READWRITE | SQLite3::Constants::Open::CREATE
|
89
|
+
exotic_flags = SQLite3::Constants::Open::NOMUTEX | SQLite3::Constants::Open::TEMP_DB
|
90
|
+
@db = SQLite3::Database.new('test-flags.db', :flags => flags | exotic_flags)
|
91
|
+
@db.execute("INSERT INTO foos (id) VALUES (12)")
|
92
|
+
assert @db.changes == 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module SQLite3
|
4
|
+
class TestDatabaseReadwrite < SQLite3::TestCase
|
5
|
+
def setup
|
6
|
+
File.unlink 'test-readwrite.db' if File.exist?('test-readwrite.db')
|
7
|
+
@db = SQLite3::Database.new('test-readwrite.db')
|
8
|
+
@db.execute("CREATE TABLE foos (id integer)")
|
9
|
+
@db.close
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
@db.close unless @db.closed?
|
14
|
+
File.unlink 'test-readwrite.db' if File.exist?('test-readwrite.db')
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_open_readwrite_database
|
18
|
+
@db = SQLite3::Database.new('test-readwrite.db', :readwrite => true)
|
19
|
+
assert !@db.readonly?
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_open_readwrite_readonly_database
|
23
|
+
assert_raise(RuntimeError) do
|
24
|
+
@db = SQLite3::Database.new('test-readwrite.db', :readwrite => true, :readonly => true)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_open_readwrite_not_exists_database
|
29
|
+
File.unlink 'test-readwrite.db'
|
30
|
+
assert_raise(SQLite3::CantOpenException) do
|
31
|
+
@db = SQLite3::Database.new('test-readwrite.db', :readonly => true)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_insert_readwrite_database
|
36
|
+
@db = SQLite3::Database.new('test-readwrite.db', :readwrite => true)
|
37
|
+
@db.execute("INSERT INTO foos (id) VALUES (12)")
|
38
|
+
assert @db.changes == 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/test/test_integration.rb
CHANGED
@@ -359,21 +359,33 @@ class TC_Database_Integration < SQLite3::TestCase
|
|
359
359
|
def test_get_first_value_no_bind_no_match
|
360
360
|
result = @db.get_first_value( "select b, a from foo where a=100" )
|
361
361
|
assert_nil result
|
362
|
+
@db.results_as_hash = true
|
363
|
+
result = @db.get_first_value( "select b, a from foo where a=100" )
|
364
|
+
assert_nil result
|
362
365
|
end
|
363
366
|
|
364
367
|
def test_get_first_value_no_bind_with_match
|
365
368
|
result = @db.get_first_value( "select b, a from foo where a=1" )
|
366
369
|
assert_equal "foo", result
|
370
|
+
@db.results_as_hash = true
|
371
|
+
result = @db.get_first_value( "select b, a from foo where a=1" )
|
372
|
+
assert_equal "foo", result
|
367
373
|
end
|
368
374
|
|
369
375
|
def test_get_first_value_with_bind_no_match
|
370
376
|
result = @db.get_first_value( "select b, a from foo where a=?", 100 )
|
371
377
|
assert_nil result
|
378
|
+
@db.results_as_hash = true
|
379
|
+
result = @db.get_first_value( "select b, a from foo where a=?", 100 )
|
380
|
+
assert_nil result
|
372
381
|
end
|
373
382
|
|
374
383
|
def test_get_first_value_with_bind_with_match
|
375
384
|
result = @db.get_first_value( "select b, a from foo where a=?", 1 )
|
376
385
|
assert_equal "foo", result
|
386
|
+
@db.results_as_hash = true
|
387
|
+
result = @db.get_first_value( "select b, a from foo where a=?", 1 )
|
388
|
+
assert_equal "foo", result
|
377
389
|
end
|
378
390
|
|
379
391
|
def test_last_insert_row_id
|
@@ -487,87 +499,6 @@ class TC_Database_Integration < SQLite3::TestCase
|
|
487
499
|
assert_match( />>>.*<<</, value )
|
488
500
|
end
|
489
501
|
|
490
|
-
def test_create_aggregate_without_block
|
491
|
-
step = proc do |ctx,a|
|
492
|
-
ctx[:sum] ||= 0
|
493
|
-
ctx[:sum] += a.to_i
|
494
|
-
end
|
495
|
-
|
496
|
-
final = proc { |ctx| ctx.result = ctx[:sum] }
|
497
|
-
|
498
|
-
@db.create_aggregate( "accumulate", 1, step, final )
|
499
|
-
|
500
|
-
value = @db.get_first_value( "select accumulate(a) from foo" )
|
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
|
506
|
-
end
|
507
|
-
|
508
|
-
def test_create_aggregate_with_block
|
509
|
-
@db.create_aggregate( "accumulate", 1 ) do
|
510
|
-
step do |ctx,a|
|
511
|
-
ctx[:sum] ||= 0
|
512
|
-
ctx[:sum] += a.to_i
|
513
|
-
end
|
514
|
-
|
515
|
-
finalize { |ctx| ctx.result = ctx[:sum] }
|
516
|
-
end
|
517
|
-
|
518
|
-
value = @db.get_first_value( "select accumulate(a) from foo" )
|
519
|
-
assert_equal 6, value
|
520
|
-
end
|
521
|
-
|
522
|
-
def test_create_aggregate_with_no_data
|
523
|
-
@db.create_aggregate( "accumulate", 1 ) do
|
524
|
-
step do |ctx,a|
|
525
|
-
ctx[:sum] ||= 0
|
526
|
-
ctx[:sum] += a.to_i
|
527
|
-
end
|
528
|
-
|
529
|
-
finalize { |ctx| ctx.result = ctx[:sum] || 0 }
|
530
|
-
end
|
531
|
-
|
532
|
-
value = @db.get_first_value(
|
533
|
-
"select accumulate(a) from foo where a = 100" )
|
534
|
-
assert_equal 0, value
|
535
|
-
end
|
536
|
-
|
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()
|
556
|
-
end
|
557
|
-
end
|
558
|
-
|
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
|
567
|
-
value = @db.get_first_value( "select multiply(a) from foo" )
|
568
|
-
assert_equal 6, value
|
569
|
-
end
|
570
|
-
|
571
502
|
def test_bind_array_parameter
|
572
503
|
result = @db.get_first_value( "select b from foo where a=? and b=?",
|
573
504
|
[ 1, "foo" ] )
|