sqlite3 1.5.0-arm64-darwin
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sqlite3 might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/API_CHANGES.md +49 -0
- data/CHANGELOG.md +425 -0
- data/CONTRIBUTING.md +24 -0
- data/ChangeLog.cvs +88 -0
- data/Gemfile +3 -0
- data/LICENSE +27 -0
- data/LICENSE-DEPENDENCIES +20 -0
- data/README.md +233 -0
- data/ext/sqlite3/aggregator.c +274 -0
- data/ext/sqlite3/aggregator.h +12 -0
- data/ext/sqlite3/backup.c +168 -0
- data/ext/sqlite3/backup.h +15 -0
- data/ext/sqlite3/database.c +853 -0
- data/ext/sqlite3/database.h +17 -0
- data/ext/sqlite3/exception.c +98 -0
- data/ext/sqlite3/exception.h +8 -0
- data/ext/sqlite3/extconf.rb +252 -0
- data/ext/sqlite3/sqlite3.c +163 -0
- data/ext/sqlite3/sqlite3_ruby.h +48 -0
- data/ext/sqlite3/statement.c +442 -0
- data/ext/sqlite3/statement.h +16 -0
- data/faq/faq.md +431 -0
- data/faq/faq.rb +145 -0
- data/faq/faq.yml +426 -0
- data/lib/sqlite3/2.6/sqlite3_native.bundle +0 -0
- data/lib/sqlite3/2.7/sqlite3_native.bundle +0 -0
- data/lib/sqlite3/3.0/sqlite3_native.bundle +0 -0
- data/lib/sqlite3/3.1/sqlite3_native.bundle +0 -0
- data/lib/sqlite3/constants.rb +50 -0
- data/lib/sqlite3/database.rb +741 -0
- data/lib/sqlite3/errors.rb +35 -0
- data/lib/sqlite3/pragmas.rb +595 -0
- data/lib/sqlite3/resultset.rb +187 -0
- data/lib/sqlite3/statement.rb +145 -0
- data/lib/sqlite3/translator.rb +118 -0
- data/lib/sqlite3/value.rb +57 -0
- data/lib/sqlite3/version.rb +23 -0
- data/lib/sqlite3.rb +15 -0
- data/test/helper.rb +27 -0
- data/test/test_backup.rb +33 -0
- data/test/test_collation.rb +82 -0
- data/test/test_database.rb +545 -0
- data/test/test_database_flags.rb +95 -0
- data/test/test_database_readonly.rb +36 -0
- data/test/test_database_readwrite.rb +41 -0
- data/test/test_deprecated.rb +44 -0
- data/test/test_encoding.rb +155 -0
- data/test/test_integration.rb +507 -0
- data/test/test_integration_aggregate.rb +336 -0
- data/test/test_integration_open_close.rb +30 -0
- data/test/test_integration_pending.rb +115 -0
- data/test/test_integration_resultset.rb +142 -0
- data/test/test_integration_statement.rb +194 -0
- data/test/test_result_set.rb +37 -0
- data/test/test_sqlite3.rb +30 -0
- data/test/test_statement.rb +263 -0
- data/test/test_statement_execute.rb +35 -0
- metadata +190 -0
@@ -0,0 +1,545 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module SQLite3
|
6
|
+
class TestDatabase < SQLite3::TestCase
|
7
|
+
attr_reader :db
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@db = SQLite3::Database.new(':memory:')
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_segv
|
15
|
+
assert_raises { SQLite3::Database.new 1 }
|
16
|
+
end
|
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.realdirpath(tf.path), File.realdirpath(@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.realdirpath(tf.path), File.realdirpath(@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
|
+
|
44
|
+
assert_equal File.realdirpath(tf.path), File.realdirpath(@db.filename('testing'))
|
45
|
+
ensure
|
46
|
+
tf.unlink if tf
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def test_filename_to_path
|
51
|
+
tf = Tempfile.new 'thing'
|
52
|
+
pn = Pathname tf.path
|
53
|
+
db = SQLite3::Database.new pn
|
54
|
+
assert_equal pn.realdirpath.to_s, File.realdirpath(db.filename)
|
55
|
+
ensure
|
56
|
+
tf.close! if tf
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def test_error_code
|
61
|
+
begin
|
62
|
+
db.execute 'SELECT'
|
63
|
+
rescue SQLite3::SQLException => e
|
64
|
+
end
|
65
|
+
assert_equal 1, e.code
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_extended_error_code
|
69
|
+
db.extended_result_codes = true
|
70
|
+
db.execute 'CREATE TABLE "employees" ("token" integer NOT NULL)'
|
71
|
+
begin
|
72
|
+
db.execute 'INSERT INTO employees (token) VALUES (NULL)'
|
73
|
+
rescue SQLite3::ConstraintException => e
|
74
|
+
end
|
75
|
+
assert_equal 1299, e.code
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_bignum
|
79
|
+
num = 4907021672125087844
|
80
|
+
db.execute 'CREATE TABLE "employees" ("token" integer(8), "name" varchar(20) NOT NULL)'
|
81
|
+
db.execute "INSERT INTO employees(name, token) VALUES('employee-1', ?)", [num]
|
82
|
+
rows = db.execute 'select token from employees'
|
83
|
+
assert_equal num, rows.first.first
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_blob
|
87
|
+
@db.execute("CREATE TABLE blobs ( id INTEGER, hash BLOB(10) )")
|
88
|
+
blob = Blob.new("foo\0bar")
|
89
|
+
@db.execute("INSERT INTO blobs VALUES (0, ?)", [blob])
|
90
|
+
assert_equal [[0, blob, blob.length, blob.length*2]], @db.execute("SELECT id, hash, length(hash), length(hex(hash)) FROM blobs")
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_get_first_row
|
94
|
+
assert_equal [1], @db.get_first_row('SELECT 1')
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_get_first_row_with_type_translation_and_hash_results
|
98
|
+
@db.results_as_hash = true
|
99
|
+
@db.type_translation = true
|
100
|
+
assert_equal({"1"=>1}, @db.get_first_row('SELECT 1'))
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_execute_with_type_translation_and_hash
|
104
|
+
@db.results_as_hash = true
|
105
|
+
@db.type_translation = true
|
106
|
+
rows = []
|
107
|
+
@db.execute('SELECT 1') { |row| rows << row }
|
108
|
+
|
109
|
+
assert_equal({"1"=>1}, rows.first)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_encoding
|
113
|
+
assert @db.encoding, 'database has encoding'
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_changes
|
117
|
+
@db.execute("CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT, number integer)")
|
118
|
+
assert_equal 0, @db.changes
|
119
|
+
@db.execute("INSERT INTO items (number) VALUES (10)")
|
120
|
+
assert_equal 1, @db.changes
|
121
|
+
@db.execute_batch(
|
122
|
+
"UPDATE items SET number = (number + :nn) WHERE (number = :n)",
|
123
|
+
{"nn" => 20, "n" => 10})
|
124
|
+
assert_equal 1, @db.changes
|
125
|
+
assert_equal [[30]], @db.execute("select number from items")
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_batch_last_comment_is_processed
|
129
|
+
# FIXME: nil as a successful return value is kinda dumb
|
130
|
+
assert_nil @db.execute_batch <<-eosql
|
131
|
+
CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT);
|
132
|
+
-- omg
|
133
|
+
eosql
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_execute_batch2
|
137
|
+
@db.results_as_hash = true
|
138
|
+
return_value = @db.execute_batch2 <<-eosql
|
139
|
+
CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT, name string);
|
140
|
+
INSERT INTO items (name) VALUES ("foo");
|
141
|
+
INSERT INTO items (name) VALUES ("bar");
|
142
|
+
SELECT * FROM items;
|
143
|
+
eosql
|
144
|
+
assert_equal return_value, [{"id"=>"1","name"=>"foo"}, {"id"=>"2", "name"=>"bar"}]
|
145
|
+
|
146
|
+
return_value = @db.execute_batch2('SELECT * FROM items;') do |result|
|
147
|
+
result["id"] = result["id"].to_i
|
148
|
+
result
|
149
|
+
end
|
150
|
+
assert_equal return_value, [{"id"=>1,"name"=>"foo"}, {"id"=>2, "name"=>"bar"}]
|
151
|
+
|
152
|
+
return_value = @db.execute_batch2('INSERT INTO items (name) VALUES ("oof")')
|
153
|
+
assert_equal return_value, []
|
154
|
+
|
155
|
+
return_value = @db.execute_batch2(
|
156
|
+
'CREATE TABLE employees (id integer PRIMARY KEY AUTOINCREMENT, name string, age integer(3));
|
157
|
+
INSERT INTO employees (age) VALUES (30);
|
158
|
+
INSERT INTO employees (age) VALUES (40);
|
159
|
+
INSERT INTO employees (age) VALUES (20);
|
160
|
+
SELECT age FROM employees;') do |result|
|
161
|
+
result["age"] = result["age"].to_i
|
162
|
+
result
|
163
|
+
end
|
164
|
+
assert_equal return_value, [{"age"=>30}, {"age"=>40}, {"age"=>20}]
|
165
|
+
|
166
|
+
return_value = @db.execute_batch2('SELECT name FROM employees');
|
167
|
+
assert_equal return_value, [{"name"=>nil}, {"name"=>nil}, {"name"=>nil}]
|
168
|
+
|
169
|
+
@db.results_as_hash = false
|
170
|
+
return_value = @db.execute_batch2(
|
171
|
+
'CREATE TABLE managers (id integer PRIMARY KEY AUTOINCREMENT, age integer(3));
|
172
|
+
INSERT INTO managers (age) VALUES (50);
|
173
|
+
INSERT INTO managers (age) VALUES (60);
|
174
|
+
SELECT id, age from managers;') do |result|
|
175
|
+
result = result.map do |res|
|
176
|
+
res.to_i
|
177
|
+
end
|
178
|
+
result
|
179
|
+
end
|
180
|
+
assert_equal return_value, [[1, 50], [2, 60]]
|
181
|
+
|
182
|
+
assert_raises (RuntimeError) do
|
183
|
+
# "names" is not a valid column
|
184
|
+
@db.execute_batch2 'INSERT INTO items (names) VALUES ("bazz")'
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_new
|
190
|
+
db = SQLite3::Database.new(':memory:')
|
191
|
+
assert db
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_new_yields_self
|
195
|
+
thing = nil
|
196
|
+
SQLite3::Database.new(':memory:') do |db|
|
197
|
+
thing = db
|
198
|
+
end
|
199
|
+
assert_instance_of(SQLite3::Database, thing)
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_new_with_options
|
203
|
+
# determine if Ruby is running on Big Endian platform
|
204
|
+
utf16 = ([1].pack("I") == [1].pack("N")) ? "UTF-16BE" : "UTF-16LE"
|
205
|
+
|
206
|
+
if RUBY_VERSION >= "1.9"
|
207
|
+
db = SQLite3::Database.new(':memory:'.encode(utf16), :utf16 => true)
|
208
|
+
else
|
209
|
+
db = SQLite3::Database.new(Iconv.conv(utf16, 'UTF-8', ':memory:'),
|
210
|
+
:utf16 => true)
|
211
|
+
end
|
212
|
+
assert db
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_close
|
216
|
+
db = SQLite3::Database.new(':memory:')
|
217
|
+
db.close
|
218
|
+
assert db.closed?
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_block_closes_self
|
222
|
+
thing = nil
|
223
|
+
SQLite3::Database.new(':memory:') do |db|
|
224
|
+
thing = db
|
225
|
+
assert !thing.closed?
|
226
|
+
end
|
227
|
+
assert thing.closed?
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_block_closes_self_even_raised
|
231
|
+
thing = nil
|
232
|
+
begin
|
233
|
+
SQLite3::Database.new(':memory:') do |db|
|
234
|
+
thing = db
|
235
|
+
raise
|
236
|
+
end
|
237
|
+
rescue
|
238
|
+
end
|
239
|
+
assert thing.closed?
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_prepare
|
243
|
+
db = SQLite3::Database.new(':memory:')
|
244
|
+
stmt = db.prepare('select "hello world"')
|
245
|
+
assert_instance_of(SQLite3::Statement, stmt)
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_block_prepare_does_not_double_close
|
249
|
+
db = SQLite3::Database.new(':memory:')
|
250
|
+
r = db.prepare('select "hello world"') do |stmt|
|
251
|
+
stmt.close
|
252
|
+
:foo
|
253
|
+
end
|
254
|
+
assert_equal :foo, r
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_total_changes
|
258
|
+
db = SQLite3::Database.new(':memory:')
|
259
|
+
db.execute("create table foo ( a integer primary key, b text )")
|
260
|
+
db.execute("insert into foo (b) values ('hello')")
|
261
|
+
assert_equal 1, db.total_changes
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_execute_returns_list_of_hash
|
265
|
+
db = SQLite3::Database.new(':memory:', :results_as_hash => true)
|
266
|
+
db.execute("create table foo ( a integer primary key, b text )")
|
267
|
+
db.execute("insert into foo (b) values ('hello')")
|
268
|
+
rows = db.execute("select * from foo")
|
269
|
+
assert_equal [{"a"=>1, "b"=>"hello"}], rows
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_execute_yields_hash
|
273
|
+
db = SQLite3::Database.new(':memory:', :results_as_hash => true)
|
274
|
+
db.execute("create table foo ( a integer primary key, b text )")
|
275
|
+
db.execute("insert into foo (b) values ('hello')")
|
276
|
+
db.execute("select * from foo") do |row|
|
277
|
+
assert_equal({"a"=>1, "b"=>"hello"}, row)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_table_info
|
282
|
+
db = SQLite3::Database.new(':memory:', :results_as_hash => true)
|
283
|
+
db.execute("create table foo ( a integer primary key, b text )")
|
284
|
+
info = [{
|
285
|
+
"name" => "a",
|
286
|
+
"pk" => 1,
|
287
|
+
"notnull" => 0,
|
288
|
+
"type" => "integer",
|
289
|
+
"dflt_value" => nil,
|
290
|
+
"cid" => 0
|
291
|
+
},
|
292
|
+
{
|
293
|
+
"name" => "b",
|
294
|
+
"pk" => 0,
|
295
|
+
"notnull" => 0,
|
296
|
+
"type" => "text",
|
297
|
+
"dflt_value" => nil,
|
298
|
+
"cid" => 1
|
299
|
+
}]
|
300
|
+
assert_equal info, db.table_info('foo')
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_total_changes_closed
|
304
|
+
db = SQLite3::Database.new(':memory:')
|
305
|
+
db.close
|
306
|
+
assert_raise(SQLite3::Exception) do
|
307
|
+
db.total_changes
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def test_trace_requires_opendb
|
312
|
+
@db.close
|
313
|
+
assert_raise(SQLite3::Exception) do
|
314
|
+
@db.trace { |x| }
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def test_trace_with_block
|
319
|
+
result = nil
|
320
|
+
@db.trace { |sql| result = sql }
|
321
|
+
@db.execute "select 'foo'"
|
322
|
+
assert_equal "select 'foo'", result
|
323
|
+
end
|
324
|
+
|
325
|
+
def test_trace_with_object
|
326
|
+
obj = Class.new {
|
327
|
+
attr_accessor :result
|
328
|
+
def call sql; @result = sql end
|
329
|
+
}.new
|
330
|
+
|
331
|
+
@db.trace(obj)
|
332
|
+
@db.execute "select 'foo'"
|
333
|
+
assert_equal "select 'foo'", obj.result
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_trace_takes_nil
|
337
|
+
@db.trace(nil)
|
338
|
+
@db.execute "select 'foo'"
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_last_insert_row_id_closed
|
342
|
+
@db.close
|
343
|
+
assert_raise(SQLite3::Exception) do
|
344
|
+
@db.last_insert_row_id
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_define_function
|
349
|
+
called_with = nil
|
350
|
+
@db.define_function("hello") do |value|
|
351
|
+
called_with = value
|
352
|
+
end
|
353
|
+
@db.execute("select hello(10)")
|
354
|
+
assert_equal 10, called_with
|
355
|
+
end
|
356
|
+
|
357
|
+
def test_call_func_arg_type
|
358
|
+
called_with = nil
|
359
|
+
@db.define_function("hello") do |b, c, d|
|
360
|
+
called_with = [b, c, d]
|
361
|
+
nil
|
362
|
+
end
|
363
|
+
@db.execute("select hello(2.2, 'foo', NULL)")
|
364
|
+
|
365
|
+
assert_in_delta(2.2, called_with[0], 0.0001)
|
366
|
+
assert_equal("foo", called_with[1])
|
367
|
+
assert_nil(called_with[2])
|
368
|
+
end
|
369
|
+
|
370
|
+
def test_define_varargs
|
371
|
+
called_with = nil
|
372
|
+
@db.define_function("hello") do |*args|
|
373
|
+
called_with = args
|
374
|
+
nil
|
375
|
+
end
|
376
|
+
@db.execute("select hello(2.2, 'foo', NULL)")
|
377
|
+
|
378
|
+
assert_in_delta(2.2, called_with[0], 0.0001)
|
379
|
+
assert_equal("foo", called_with[1])
|
380
|
+
assert_nil(called_with[2])
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_call_func_blob
|
384
|
+
called_with = nil
|
385
|
+
@db.define_function("hello") do |a, b|
|
386
|
+
called_with = [a, b, a.length]
|
387
|
+
nil
|
388
|
+
end
|
389
|
+
blob = Blob.new("a\0fine\0kettle\0of\0fish")
|
390
|
+
@db.execute("select hello(?, length(?))", [blob, blob])
|
391
|
+
assert_equal [blob, blob.length, 21], called_with
|
392
|
+
end
|
393
|
+
|
394
|
+
def test_function_return
|
395
|
+
@db.define_function("hello") { |a| 10 }
|
396
|
+
assert_equal [10], @db.execute("select hello('world')").first
|
397
|
+
end
|
398
|
+
|
399
|
+
def test_function_return_types
|
400
|
+
[10, 2.2, nil, "foo", Blob.new("foo\0bar")].each do |thing|
|
401
|
+
@db.define_function("hello") { |a| thing }
|
402
|
+
assert_equal [thing], @db.execute("select hello('world')").first
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def test_function_gc_segfault
|
407
|
+
@db.create_function("bug", -1) { |func, *values| func.result = values.join }
|
408
|
+
# With a lot of data and a lot of threads, try to induce a GC segfault.
|
409
|
+
params = Array.new(127, "?" * 28000)
|
410
|
+
proc = Proc.new {
|
411
|
+
db.execute("select bug(#{Array.new(params.length, "?").join(",")})", params)
|
412
|
+
}
|
413
|
+
m = Mutex.new
|
414
|
+
30.times.map { Thread.new { m.synchronize { proc.call } } }.each(&:join)
|
415
|
+
end
|
416
|
+
|
417
|
+
def test_function_return_type_round_trip
|
418
|
+
[10, 2.2, nil, "foo", Blob.new("foo\0bar")].each do |thing|
|
419
|
+
@db.define_function("hello") { |a| a }
|
420
|
+
assert_equal [thing], @db.execute("select hello(hello(?))", [thing]).first
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_define_function_closed
|
425
|
+
@db.close
|
426
|
+
assert_raise(SQLite3::Exception) do
|
427
|
+
@db.define_function('foo') { }
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
def test_inerrupt_closed
|
432
|
+
@db.close
|
433
|
+
assert_raise(SQLite3::Exception) do
|
434
|
+
@db.interrupt
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
def test_define_aggregate
|
439
|
+
@db.execute "create table foo ( a integer primary key, b text )"
|
440
|
+
@db.execute "insert into foo ( b ) values ( 'foo' )"
|
441
|
+
@db.execute "insert into foo ( b ) values ( 'bar' )"
|
442
|
+
@db.execute "insert into foo ( b ) values ( 'baz' )"
|
443
|
+
|
444
|
+
acc = Class.new {
|
445
|
+
attr_reader :sum
|
446
|
+
alias :finalize :sum
|
447
|
+
def initialize
|
448
|
+
@sum = 0
|
449
|
+
end
|
450
|
+
|
451
|
+
def step a
|
452
|
+
@sum += a
|
453
|
+
end
|
454
|
+
}.new
|
455
|
+
|
456
|
+
@db.define_aggregator("accumulate", acc)
|
457
|
+
value = @db.get_first_value( "select accumulate(a) from foo" )
|
458
|
+
assert_equal 6, value
|
459
|
+
end
|
460
|
+
|
461
|
+
def test_authorizer_ok
|
462
|
+
@db.authorizer = Class.new {
|
463
|
+
def call action, a, b, c, d; true end
|
464
|
+
}.new
|
465
|
+
@db.prepare("select 'fooooo'")
|
466
|
+
|
467
|
+
@db.authorizer = Class.new {
|
468
|
+
def call action, a, b, c, d; 0 end
|
469
|
+
}.new
|
470
|
+
@db.prepare("select 'fooooo'")
|
471
|
+
end
|
472
|
+
|
473
|
+
def test_authorizer_ignore
|
474
|
+
@db.authorizer = Class.new {
|
475
|
+
def call action, a, b, c, d; nil end
|
476
|
+
}.new
|
477
|
+
stmt = @db.prepare("select 'fooooo'")
|
478
|
+
assert_nil stmt.step
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_authorizer_fail
|
482
|
+
@db.authorizer = Class.new {
|
483
|
+
def call action, a, b, c, d; false end
|
484
|
+
}.new
|
485
|
+
assert_raises(SQLite3::AuthorizationException) do
|
486
|
+
@db.prepare("select 'fooooo'")
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
def test_remove_auth
|
491
|
+
@db.authorizer = Class.new {
|
492
|
+
def call action, a, b, c, d; false end
|
493
|
+
}.new
|
494
|
+
assert_raises(SQLite3::AuthorizationException) do
|
495
|
+
@db.prepare("select 'fooooo'")
|
496
|
+
end
|
497
|
+
|
498
|
+
@db.authorizer = nil
|
499
|
+
@db.prepare("select 'fooooo'")
|
500
|
+
end
|
501
|
+
|
502
|
+
def test_close_with_open_statements
|
503
|
+
@db.prepare("select 'foo'")
|
504
|
+
assert_raises(SQLite3::BusyException) do
|
505
|
+
@db.close
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
def test_execute_with_empty_bind_params
|
510
|
+
assert_equal [['foo']], @db.execute("select 'foo'", [])
|
511
|
+
end
|
512
|
+
|
513
|
+
def test_query_with_named_bind_params
|
514
|
+
assert_equal [['foo']], @db.query("select :n", {'n' => 'foo'}).to_a
|
515
|
+
end
|
516
|
+
|
517
|
+
def test_execute_with_named_bind_params
|
518
|
+
assert_equal [['foo']], @db.execute("select :n", {'n' => 'foo'})
|
519
|
+
end
|
520
|
+
|
521
|
+
def test_strict_mode
|
522
|
+
unless Gem::Requirement.new(">= 3.29.0").satisfied_by?(Gem::Version.new(SQLite3::SQLITE_VERSION))
|
523
|
+
skip("strict mode feature not available in #{SQLite3::SQLITE_VERSION}")
|
524
|
+
end
|
525
|
+
|
526
|
+
db = SQLite3::Database.new(':memory:')
|
527
|
+
db.execute('create table numbers (val int);')
|
528
|
+
db.execute('create index index_numbers_nope ON numbers ("nope");') # nothing raised
|
529
|
+
|
530
|
+
db = SQLite3::Database.new(':memory:', :strict => true)
|
531
|
+
db.execute('create table numbers (val int);')
|
532
|
+
error = assert_raises SQLite3::SQLException do
|
533
|
+
db.execute('create index index_numbers_nope ON numbers ("nope");')
|
534
|
+
end
|
535
|
+
assert_includes error.message, "no such column: nope"
|
536
|
+
end
|
537
|
+
|
538
|
+
def test_load_extension_with_nonstring_argument
|
539
|
+
db = SQLite3::Database.new(':memory:')
|
540
|
+
skip("extensions are not enabled") unless db.respond_to?(:load_extension)
|
541
|
+
assert_raises(TypeError) { db.load_extension(1) }
|
542
|
+
assert_raises(TypeError) { db.load_extension(Pathname.new("foo.so")) }
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
@@ -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,36 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module SQLite3
|
4
|
+
class TestDatabaseReadonly < SQLite3::TestCase
|
5
|
+
def setup
|
6
|
+
File.unlink 'test-readonly.db' if File.exist?('test-readonly.db')
|
7
|
+
@db = SQLite3::Database.new('test-readonly.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-readonly.db' if File.exist?('test-readonly.db')
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_open_readonly_database
|
18
|
+
@db = SQLite3::Database.new('test-readonly.db', :readonly => true)
|
19
|
+
assert @db.readonly?
|
20
|
+
end
|
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
|
+
|
29
|
+
def test_insert_readonly_database
|
30
|
+
@db = SQLite3::Database.new('test-readonly.db', :readonly => true)
|
31
|
+
assert_raise(SQLite3::ReadOnlyException) do
|
32
|
+
@db.execute("INSERT INTO foos (id) VALUES (12)")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|