v / vlib / db / sqlite / sqlite_vfs_lowlevel_test.v
319 lines · 250 sloc · 7.52 KB · 07c796b670d9e498ccb25605af189617f61ec295
Raw
1// vtest build: present_sqlite3?
2import db.sqlite
3import rand
4
5const max_file_name_len = 256
6
7fn test_vfs_register() {
8 org_default_vfs := sqlite.get_default_vfs()!
9
10 assert org_default_vfs.zName != 0
11
12 vfs_name := 'sometest'
13 mut vfs_descr := &sqlite.Sqlite3_vfs{
14 zName: vfs_name.str
15 iVersion: 2
16 }
17
18 if _ := sqlite.get_vfs(vfs_name) {
19 panic('expected that vfs is not known')
20 }
21
22 vfs_descr.register_as_nondefault() or { panic('vfs register failed ${err}') }
23
24 sqlite.get_vfs(vfs_name)!
25
26 now_default_vfs := sqlite.get_default_vfs()!
27
28 assert now_default_vfs.zName == org_default_vfs.zName
29
30 vfs_descr.unregister() or { panic('vfs unregister failed ${err}') }
31
32 if _ := sqlite.get_vfs(vfs_name) {
33 panic('vfs supposedly unregistered yet somehow still foundable')
34 }
35}
36
37// minimal vfs based on example https://www.sqlite.org/src/doc/trunk/src/test_demovfs.c
38fn test_verify_vfs_is_actually_used() {
39 wrapped := sqlite.get_default_vfs()!
40
41 vfs_name := 'sometest'
42 mut vfs_state := &ExampleVfsState{
43 log: []string{cap: 100}
44 }
45 mut vfs_descr := &sqlite.Sqlite3_vfs{
46 iVersion: 2
47 szOsFile: int(sizeof(ExampleVfsOpenedFile))
48 mxPathname: max_file_name_len
49 zName: vfs_name.str
50 pAppData: vfs_state
51 xOpen: example_vfs_open
52 xDelete: example_vfs_delete
53 xAccess: example_vfs_access
54 xFullPathname: example_vfs_fullpathname
55 xDlOpen: wrapped.xDlOpen
56 xDlError: wrapped.xDlError
57 xDlSym: wrapped.xDlSym
58 xDlClose: wrapped.xDlClose
59 xRandomness: wrapped.xRandomness
60 xSleep: wrapped.xSleep
61 xCurrentTime: wrapped.xCurrentTime
62 xGetLastError: example_vfs_getlasterror
63 xCurrentTimeInt64: wrapped.xCurrentTimeInt64
64 }
65
66 vfs_descr.register_as_nondefault()!
67
68 // normally this would be written to disk
69 mut db := sqlite.connect_full('foo.db', [.readwrite, .create], vfs_name)!
70 assert ['fullpathname from=foo.db to=foo.db}', 'open temp?=false name=foo.db', 'read file=foo.db'] == vfs_state.log
71 vfs_state.log.clear()
72
73 db.close()!
74 assert ['close file=foo.db'] == vfs_state.log
75}
76
77struct ExampleVfsState {
78mut:
79 log []string
80}
81
82struct ExampleVfsOpenedFile {
83mut:
84 base sqlite.Sqlite3_file
85 name string
86 vfs_state &ExampleVfsState
87}
88
89fn to_vfsstate(t &sqlite.Sqlite3_vfs) &ExampleVfsState {
90 unsafe {
91 p := t.pAppData
92 if p == 0 {
93 assert false, 'p should not be 0'
94 }
95 return &ExampleVfsState(p)
96 }
97}
98
99fn to_vfsopenedfile(t &sqlite.Sqlite3_file) &ExampleVfsOpenedFile {
100 unsafe {
101 if t == 0 {
102 assert false, 't should not be 0'
103 }
104 return &ExampleVfsOpenedFile(t)
105 }
106}
107
108fn example_vfs_fullpathname(vfs &sqlite.Sqlite3_vfs, input &char, size_of_output int, output &char) int {
109 println('fullpathname called')
110
111 mut vfs_state := to_vfsstate(vfs)
112
113 from := unsafe { cstring_to_vstring(input) }
114
115 unsafe {
116 vmemcpy(output, input, from.len)
117 output[from.len] = u8(0)
118 }
119 result := unsafe { cstring_to_vstring(output) }
120
121 vfs_state.log << 'fullpathname from=${from} to=${result}}'
122
123 return sqlite.sqlite_ok
124}
125
126fn example_vfs_access(vfs &sqlite.Sqlite3_vfs, zPath &char, flags int, pResOut &int) int {
127 println('access called')
128 mut vfs_state := &ExampleVfsState{}
129
130 unsafe {
131 assert 0 != vfs.pAppData
132 vfs_state = &ExampleVfsState(vfs.pAppData)
133 }
134 vfs_state.log << 'accessed'
135
136 return sqlite.sqlite_ok
137}
138
139fn example_vfs_open(vfs &sqlite.Sqlite3_vfs, file_name_or_null_for_tempfile &char, vfs_opened_file &sqlite.Sqlite3_file,
140 in_flags int, out_flags &int) int {
141 println('open called')
142
143 mut is_temp := false
144 mut file_name := ''
145
146 unsafe {
147 if file_name_or_null_for_tempfile == nil {
148 is_temp = true
149 file_name = rand.uuid_v4()
150 } else {
151 file_name = cstring_to_vstring(file_name_or_null_for_tempfile)
152 }
153 }
154 mut vfs_state := to_vfsstate(vfs)
155
156 unsafe {
157 mut outp := to_vfsopenedfile(vfs_opened_file)
158 outp.base.pMethods = &sqlite.Sqlite3_io_methods{
159 iVersion: 1
160 xClose: example_vfsfile_close
161 xRead: example_vfsfile_read
162 xWrite: example_vfsfile_write
163 xTruncate: example_vfsfile_truncate
164 xSync: example_vfsfile_sync
165 xFileSize: example_vfsfile_size
166 xLock: example_vfsfile_lock
167 xUnlock: example_vfsfile_unlock
168 xCheckReservedLock: example_vfsfile_checkreservedlock
169 xFileControl: example_vfsfile_filecontrol
170 xSectorSize: example_vfsfile_sectorsize
171 xDeviceCharacteristics: example_vfsfile_devicecharacteristics
172 }
173
174 outp.name = file_name.clone()
175 outp.vfs_state = vfs_state
176 }
177 vfs_state.log << 'open temp?=${is_temp} name=${file_name}'
178
179 return sqlite.sqlite_ok
180}
181
182fn example_vfsfile_checkreservedlock(file &sqlite.Sqlite3_file, pResOut &int) int {
183 println('file checkreservedlock')
184
185 unsafe {
186 *pResOut = 0
187 }
188 return sqlite.sqlite_ok
189}
190
191fn example_vfsfile_filecontrol(file &sqlite.Sqlite3_file, op int, arg voidptr) int {
192 println('file filecontrol')
193
194 return 0
195}
196
197fn example_vfsfile_devicecharacteristics(file &sqlite.Sqlite3_file) int {
198 println('file devicecharacteristics')
199
200 return 0
201}
202
203fn example_vfsfile_size(file &sqlite.Sqlite3_file, result &i64) int {
204 println('file size')
205
206 return sqlite.sqlite_ok
207}
208
209fn example_vfsfile_read(file &sqlite.Sqlite3_file, output voidptr, amount int, offset i64) int {
210 println('file read')
211
212 assert amount > 0
213
214 unsafe {
215 mut vfsfile := to_vfsopenedfile(file)
216 vfsfile.vfs_state.log << 'read file=${vfsfile.name}'
217 }
218 unsafe {
219 vmemset(output, 0, amount)
220 }
221
222 return sqlite.sqlite_ioerr_short_read
223}
224
225fn example_vfsfile_truncate(file &sqlite.Sqlite3_file, size i64) int {
226 println('file truncate')
227
228 return sqlite.sqlite_ok
229}
230
231fn example_vfsfile_sectorsize(file &sqlite.Sqlite3_file) int {
232 println('file sectorsize')
233
234 return 0
235}
236
237fn example_vfsfile_sync(file &sqlite.Sqlite3_file, flags int) int {
238 println('file sync called')
239
240 return sqlite.sqlite_ok
241}
242
243fn example_vfsfile_lock(file &sqlite.Sqlite3_file, elock int) int {
244 println('file lock called')
245
246 return sqlite.sqlite_ok
247}
248
249fn example_vfsfile_unlock(file &sqlite.Sqlite3_file, elock int) int {
250 println('file unlock called')
251
252 return sqlite.sqlite_ok
253}
254
255fn example_vfsfile_write(file &sqlite.Sqlite3_file, buf voidptr, amount int, offset i64) int {
256 println('file write called')
257
258 return sqlite.sqlite_ok
259}
260
261fn example_vfsfile_close(file &sqlite.Sqlite3_file) int {
262 println('file close called')
263
264 unsafe {
265 mut vfsfile := to_vfsopenedfile(file)
266 vfsfile.vfs_state.log << 'close file=${vfsfile.name}'
267 }
268 return sqlite.sqlite_ok
269}
270
271fn example_vfs_delete(vfs &sqlite.Sqlite3_vfs, name &char, sync_dir int) int {
272 println('vfs delete called')
273
274 return sqlite.sqlite_ok
275}
276
277fn example_vfs_getlasterror(vfs &sqlite.Sqlite3_vfs, i int, o &char) int {
278 println('vfs getlasterror called')
279
280 unsafe {
281 *o = 0
282 }
283 return sqlite.sqlite_ok
284}
285
286////////////////////////////////////////////////
287
288struct Human {
289 name string
290 age f32
291}
292
293fn check_connect_full_default_vfs(vfs_name string) ! {
294 mut db := sqlite.connect_full(':memory:', [.readwrite, .create, .fullmutex], '')!
295 sql db {
296 create table Human
297 }!
298 h := Human{'Bilbo', 56}
299 sql db {
300 insert h into Human
301 }!
302 res := sql db {
303 select from Human
304 }!
305 db.close()!
306 assert res.len == 1
307 assert res[0] == h
308}
309
310fn test_connect_full_default_vfs() {
311 // passing '' here as vfs_name should work everywhere, and it should be equivalent
312 // to 'unix' or 'win32', depending on the current system:
313 check_connect_full_default_vfs('')!
314 $if windows {
315 check_connect_full_default_vfs('win32')!
316 } $else {
317 check_connect_full_default_vfs('unix')!
318 }
319}
320