blob: 79298a050697fb9b9323b6593ceebef5628bc71f [file] [log] [blame]
dan373dc3b2017-12-29 20:19:03 +00001# 2017 December 9
2#
3# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
5#
6# May you do good and not evil.
7# May you find forgiveness for yourself and forgive others.
8# May you share freely, never taking more than you give.
9#
10#***********************************************************************
11#
12
mistachkinb5a4a702018-03-16 23:54:26 +000013package require Tcl 8.6
14
dan373dc3b2017-12-29 20:19:03 +000015set testdir [file dirname $argv0]
16source $testdir/tester.tcl
17set testprefix zipfile
18
danc48e0272018-01-09 18:31:11 +000019ifcapable !vtab {
20 finish_test; return
21}
mistachkinf2e8aa62018-01-05 20:13:33 +000022if {[catch {load_static_extension db zipfile} error]} {
23 puts "Skipping zipfile tests, hit load error: $error"
24 finish_test; return
25}
mistachkinb5a4a702018-03-16 23:54:26 +000026if {[catch {load_static_extension db fileio} error]} {
27 puts "Skipping zipfile tests, hit load error: $error"
28 finish_test; return
29}
dan373dc3b2017-12-29 20:19:03 +000030
danf8c4b992018-01-29 18:41:07 +000031proc readfile {f} {
32 set fd [open $f]
dan8005d602018-01-26 18:59:25 +000033 fconfigure $fd -translation binary -encoding binary
34 set data [read $fd]
35 close $fd
danf8c4b992018-01-29 18:41:07 +000036 set data
37}
dan8005d602018-01-26 18:59:25 +000038
mistachkinb5a4a702018-03-16 23:54:26 +000039unset -nocomplain ::UNZIP
40
41if {[catch {exec unzip} msg]==0 && \
42 [regexp -line {^UnZip \d+\.\d+ .*? Info-ZIP\.} $msg]} {
43 set ::UNZIP unzip
44 proc fix_stat_mode {name mode} {
45 if {$::tcl_platform(platform)=="windows"} {
46 #
47 # NOTE: Set or unset the write bits of the file permissions
48 # based on the read-only attribute because the Win32
49 # version of UnZip does this.
50 #
51 set writebits 0x12; # 0o22
52 set result $mode
53 if {[file attributes $name -readonly]} {
54 set result [expr {$result | $writebits}]
55 } else {
56 set result [expr {$result & ~$writebits}]
57 }
58 return $result
59 } else {
60 return $mode
61 }
62 }
danea4125b2018-01-29 19:47:32 +000063 proc do_unzip {file} {
64 forcedelete test_unzip
65 file mkdir test_unzip
mistachkinb5a4a702018-03-16 23:54:26 +000066 exec $::UNZIP -d test_unzip $file
67
68 db func modefix fix_stat_mode
69
70 set res [db eval {
71 SELECT replace(name,'test_unzip/',''),modefix(name,mode),mtime,data
danea4125b2018-01-29 19:47:32 +000072 FROM fsdir('test_unzip')
73 WHERE name!='test_unzip'
74 ORDER BY name
75 }]
76 set res
77 }
78}
79
dan44091ed2018-01-31 19:13:31 +000080
81# The argument is a blob (not a hex string) containing a zip archive.
82# This proc removes the extended timestamp fields from the archive
83# and returns the result.
84#
85proc remove_timestamps {blob} {
86 set hex [binary encode hex $blob]
87 set hex [string map {55540500 00000500} $hex]
88 binary decode hex $hex
89}
90
91
danf8c4b992018-01-29 18:41:07 +000092# Argument $file is the name of a zip archive on disk. This function
93# executes test cases to check that the results of each of the following
94# are the same:
95#
96# SELECT * FROM zipfile($file)
97# SELECT * FROM zipfile( readfile($file) )
98# SELECT * FROM zipfile(
99# (SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file))
100# )
101#
102proc do_zipfile_blob_test {tn file} {
dan26333ee2018-01-27 16:29:59 +0000103
danf8c4b992018-01-29 18:41:07 +0000104 db func r readfile
105 set q1 {SELECT name,mode,mtime,method,quote(data) FROM zipfile($file)}
106 set q2 {SELECT name,mode,mtime,method,quote(data) FROM zipfile( r($file) )}
107 set q3 {SELECT name,mode,mtime,method,quote(data) FROM zipfile(
108 ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) )
109 )}
dan26333ee2018-01-27 16:29:59 +0000110
dan26333ee2018-01-27 16:29:59 +0000111
danf8c4b992018-01-29 18:41:07 +0000112 set r1 [db eval $q1]
113 set r2 [db eval $q2]
114 set r3 [db eval $q3]
115 #puts $r1
116 #puts $r2
117 #puts $r3
dan26333ee2018-01-27 16:29:59 +0000118
danf8c4b992018-01-29 18:41:07 +0000119 uplevel [list do_test $tn.1 [list set {} $r2] $r1]
danea4125b2018-01-29 19:47:32 +0000120 uplevel [list do_test $tn.2 [list set {} $r3] $r1]
121}
122
123# Argument $file is a zip file on disk. This command runs tests to:
124#
125# 1. Unpack the archive with unix command [unzip] and compare the
126# results to reading the same archive using the zipfile() table
127# valued function.
128#
129# 2. Creates a new archive with the same contents using the zipfile()
130# aggregate function as follows:
131#
132# SELECT writefile('test_unzip.zip',
133# ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) )
134# );
135#
136# Then tests that unpacking the new archive using [unzip] produces
137# the same results as in (1).
138#
139proc do_unzip_test {tn file} {
danea4125b2018-01-29 19:47:32 +0000140 db func sss strip_slash
141
142 db eval {
143 SELECT writefile('test_unzip.zip',
144 ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) )
145 );
146 }
147
148 set r1 [db eval {
149 SELECT sss(name),mode,mtime,data FROM zipfile($file) ORDER BY name
150 }]
151 set r2 [do_unzip $file]
152 set r3 [do_unzip test_unzip.zip]
153
154 uplevel [list do_test $tn.1 [list set {} $r2] $r1]
155 uplevel [list do_test $tn.2 [list set {} $r3] $r1]
156}
157proc strip_slash {in} { regsub {/$} $in {} }
158
159proc do_zip_tests {tn file} {
160 uplevel do_zipfile_blob_test $tn.1 $file
dana8728e72018-03-29 16:39:09 +0000161 if {[info exists ::UNZIP]} {
162 uplevel do_unzip_test $tn.2 $file
163 }
dan8005d602018-01-26 18:59:25 +0000164}
165
dan373dc3b2017-12-29 20:19:03 +0000166forcedelete test.zip
167do_execsql_test 1.0 {
168 CREATE VIRTUAL TABLE temp.zz USING zipfile('test.zip');
169 PRAGMA table_info(zz);
170} {
dan66a3a912018-01-11 17:33:48 +0000171 0 name {} 1 {} 1
dan373dc3b2017-12-29 20:19:03 +0000172 1 mode {} 0 {} 0
173 2 mtime {} 0 {} 0
174 3 sz {} 0 {} 0
dan7c15ac12018-01-08 19:59:59 +0000175 4 rawdata {} 0 {} 0
176 5 data {} 0 {} 0
177 6 method {} 0 {} 0
dan373dc3b2017-12-29 20:19:03 +0000178}
179
dan2d620072018-01-15 19:00:35 +0000180do_catchsql_test 1.1.0.1 {
dan7c15ac12018-01-08 19:59:59 +0000181 INSERT INTO zz(name, mode, mtime, sz, rawdata, method)
182 VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
drh41a6f2c2018-03-10 13:21:41 +0000183} {1 {rawdata must be NULL}}
dan15daa6b2018-02-01 19:41:23 +0000184do_catchsql_test 1.1.0.2 {
185 INSERT INTO zz(name, mtime, sz, data, method)
dan7c15ac12018-01-08 19:59:59 +0000186 VALUES('g.txt', 1000000002, 5, '12345', 0);
drh41a6f2c2018-03-10 13:21:41 +0000187} {1 {sz must be NULL}}
dan15daa6b2018-02-01 19:41:23 +0000188do_catchsql_test 1.1.0.3 {
189 INSERT INTO zz(name, mtime, rawdata, method)
190 VALUES('g.txt', 1000000002, '12345', 0);
drh41a6f2c2018-03-10 13:21:41 +0000191} {1 {rawdata must be NULL}}
dan15daa6b2018-02-01 19:41:23 +0000192do_catchsql_test 1.1.0.4 {
193 INSERT INTO zz(name, data, method)
194 VALUES('g.txt', '12345', 7);
drh41a6f2c2018-03-10 13:21:41 +0000195} {1 {unknown compression method: 7}}
dan2d620072018-01-15 19:00:35 +0000196
197do_execsql_test 1.1.1 {
198 INSERT INTO zz(name, mode, mtime, data, method)
199 VALUES('f.txt', '-rw-r--r--', 1000000000, 'abcde', 0);
200}
201do_execsql_test 1.1.2 {
202 INSERT INTO zz(name, mode, mtime, data, method)
203 VALUES('g.txt', NULL, 1000000002, '12345', 0);
dan373dc3b2017-12-29 20:19:03 +0000204}
205
206do_execsql_test 1.2 {
dan0cde0c62017-12-30 18:32:27 +0000207 SELECT name, mtime, data FROM zipfile('test.zip')
dan373dc3b2017-12-29 20:19:03 +0000208} {
dan373dc3b2017-12-29 20:19:03 +0000209 f.txt 1000000000 abcde
dandb0cb302017-12-30 14:26:29 +0000210 g.txt 1000000002 12345
dan373dc3b2017-12-29 20:19:03 +0000211}
danea4125b2018-01-29 19:47:32 +0000212do_zip_tests 1.2a test.zip
dan373dc3b2017-12-29 20:19:03 +0000213
214do_execsql_test 1.3 {
dan7c15ac12018-01-08 19:59:59 +0000215 INSERT INTO zz(name, mode, mtime, data) VALUES('h.txt',
216 '-rw-r--r--', 1000000004, 'aaaaaaaaaabbbbbbbbbb'
dan373dc3b2017-12-29 20:19:03 +0000217 );
218}
danea4125b2018-01-29 19:47:32 +0000219do_zip_tests 1.3a test.zip
dan373dc3b2017-12-29 20:19:03 +0000220
221do_execsql_test 1.4 {
dan7c15ac12018-01-08 19:59:59 +0000222 SELECT name, mtime, data, method FROM zipfile('test.zip');
dan373dc3b2017-12-29 20:19:03 +0000223} {
dan373dc3b2017-12-29 20:19:03 +0000224 f.txt 1000000000 abcde 0
225 g.txt 1000000002 12345 0
dandb0cb302017-12-30 14:26:29 +0000226 h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8
dan373dc3b2017-12-29 20:19:03 +0000227}
228
danf1939372018-01-17 12:58:11 +0000229ifcapable json1 {
230 do_execsql_test 1.4.1 {
231 SELECT name, json_extract( zipfile_cds(z) , '$.crc32')!=0
232 FROM zipfile('test.zip');
233 } {
234 f.txt 1
235 g.txt 1
236 h.txt 1
237 }
dan28799522018-01-16 21:09:00 +0000238}
dan15daa6b2018-02-01 19:41:23 +0000239do_catchsql_test 1.4.2 {
240 SELECT zipfile_cds(mode) FROM zipfile('test.zip');
241} {0 {{} {} {}}}
dan28799522018-01-16 21:09:00 +0000242
dan0cde0c62017-12-30 18:32:27 +0000243do_execsql_test 1.5.1 {
244 BEGIN;
dan7c15ac12018-01-08 19:59:59 +0000245 INSERT INTO zz(name, mode, mtime, data, method)
246 VALUES('i.txt', '-rw-r--r--', 1000000006, 'zxcvb', 0);
dan0cde0c62017-12-30 18:32:27 +0000247 SELECT name FROM zz;
248 COMMIT;
249} {f.txt g.txt h.txt i.txt}
250do_execsql_test 1.5.2 {
251 SELECT name FROM zz;
252} {f.txt g.txt h.txt i.txt}
danf42884c2018-01-13 19:08:24 +0000253do_execsql_test 1.5.3 {
254 SELECT data FROM zz WHERE name='i.txt';
255} {zxcvb}
dan0cde0c62017-12-30 18:32:27 +0000256
257do_execsql_test 1.6.0 {
258 DELETE FROM zz WHERE name='g.txt';
259 SELECT name FROM zz;
260} {f.txt h.txt i.txt}
261
danf42884c2018-01-13 19:08:24 +0000262do_execsql_test 1.6.1 {
263 SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
264} {
265 f.txt 33188 1000000000 abcde 0
266 h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8
267 i.txt 33188 1000000006 zxcvb 0
268}
danea4125b2018-01-29 19:47:32 +0000269do_zip_tests 1.6.1a test.zip
danf42884c2018-01-13 19:08:24 +0000270
271do_execsql_test 1.6.2 {
272 UPDATE zz SET mtime=4 WHERE name='i.txt';
273 SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
274} {
275 f.txt 33188 1000000000 abcde 0
276 h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8
277 i.txt 33188 4 zxcvb 0
278}
279
mistachkinb5a4a702018-03-16 23:54:26 +0000280if {$::tcl_platform(platform)=="unix"} {
281 set modes -rw-r--r-x
282 set perms 33189
283} else {
284 set modes -rw-r--r--; # no execute bits on Win32
285 set perms 33188
danf42884c2018-01-13 19:08:24 +0000286}
mistachkinb5a4a702018-03-16 23:54:26 +0000287
288do_execsql_test 1.6.3 {
289 UPDATE zz SET mode=$modes WHERE name='h.txt';
290 SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
291} [string map [list %perms% $perms] {
292 f.txt 33188 1000000000 abcde 0
293 h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
294 i.txt 33188 4 zxcvb 0
295}]
danea4125b2018-01-29 19:47:32 +0000296do_zip_tests 1.6.3a test.zip
danf42884c2018-01-13 19:08:24 +0000297
298do_execsql_test 1.6.4 {
299 UPDATE zz SET name = 'blue.txt' WHERE name='f.txt';
300 SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
mistachkinb5a4a702018-03-16 23:54:26 +0000301} [string map [list %perms% $perms] {
danf42884c2018-01-13 19:08:24 +0000302 blue.txt 33188 1000000000 abcde 0
mistachkinb5a4a702018-03-16 23:54:26 +0000303 h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
danf42884c2018-01-13 19:08:24 +0000304 i.txt 33188 4 zxcvb 0
mistachkinb5a4a702018-03-16 23:54:26 +0000305}]
danea4125b2018-01-29 19:47:32 +0000306do_zip_tests 1.6.4a test.zip
danf42884c2018-01-13 19:08:24 +0000307
308do_execsql_test 1.6.5 {
309 UPDATE zz SET data = 'edcba' WHERE name='blue.txt';
310 SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
mistachkinb5a4a702018-03-16 23:54:26 +0000311} [string map [list %perms% $perms] {
danf42884c2018-01-13 19:08:24 +0000312 blue.txt 33188 1000000000 edcba 0
mistachkinb5a4a702018-03-16 23:54:26 +0000313 h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
danf42884c2018-01-13 19:08:24 +0000314 i.txt 33188 4 zxcvb 0
mistachkinb5a4a702018-03-16 23:54:26 +0000315}]
danf42884c2018-01-13 19:08:24 +0000316
317do_execsql_test 1.6.6 {
318 UPDATE zz SET mode=NULL, data = NULL WHERE name='blue.txt';
319 SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
mistachkinb5a4a702018-03-16 23:54:26 +0000320} [string map [list %perms% $perms] {
danf42884c2018-01-13 19:08:24 +0000321 blue.txt/ 16877 1000000000 {} 0
mistachkinb5a4a702018-03-16 23:54:26 +0000322 h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
danf42884c2018-01-13 19:08:24 +0000323 i.txt 33188 4 zxcvb 0
mistachkinb5a4a702018-03-16 23:54:26 +0000324}]
danf42884c2018-01-13 19:08:24 +0000325
326do_catchsql_test 1.6.7 {
327 UPDATE zz SET data=NULL WHERE name='i.txt'
drh41a6f2c2018-03-10 13:21:41 +0000328} {1 {zipfile: mode does not match data}}
danf42884c2018-01-13 19:08:24 +0000329do_execsql_test 1.6.8 {
330 SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
mistachkinb5a4a702018-03-16 23:54:26 +0000331} [string map [list %perms% $perms] {
danf42884c2018-01-13 19:08:24 +0000332 blue.txt/ 16877 1000000000 {} 0
mistachkinb5a4a702018-03-16 23:54:26 +0000333 h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
danf42884c2018-01-13 19:08:24 +0000334 i.txt 33188 4 zxcvb 0
mistachkinb5a4a702018-03-16 23:54:26 +0000335}]
dan15daa6b2018-02-01 19:41:23 +0000336
337do_execsql_test 1.6.9 {
mistachkinb5a4a702018-03-16 23:54:26 +0000338 UPDATE zz SET data = '' WHERE name='i.txt';
339 SELECT name,mode,mtime,data,method from zipfile('test.zip');
340} [string map [list %perms% $perms] {
341 blue.txt/ 16877 1000000000 {} 0
342 h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
343 i.txt 33188 4 {} 0
344}]
345
346do_execsql_test 1.6.10 {
dan15daa6b2018-02-01 19:41:23 +0000347 SELECT a.name, a.data
348 FROM zz AS a, zz AS b
349 WHERE a.name=+b.name AND +a.mode=b.mode
350} {
351 blue.txt/ {}
352 h.txt aaaaaaaaaabbbbbbbbbb
353 i.txt {}
354}
355
mistachkinb5a4a702018-03-16 23:54:26 +0000356do_execsql_test 1.6.11 {
dan15daa6b2018-02-01 19:41:23 +0000357 SELECT name, data FROM zz WHERE name LIKE '%txt'
358} {
359 h.txt aaaaaaaaaabbbbbbbbbb
360 i.txt {}
361}
362
363do_execsql_test 1.7 {
364 DELETE FROM zz;
365 SELECT * FROM zz;
366} {}
367
dan128011a2018-01-09 10:29:34 +0000368#-------------------------------------------------------------------------
369db close
370forcedelete test.zip
371reset_db
danea4125b2018-01-29 19:47:32 +0000372load_static_extension db fileio
dan128011a2018-01-09 10:29:34 +0000373load_static_extension db zipfile
374do_execsql_test 2.1 {
375 CREATE VIRTUAL TABLE zzz USING zipfile('test.zip');
376 INSERT INTO zzz(name, mode) VALUES('dirname', 'drwxr-xr-x');
377 SELECT name, mode, data FROM zzz;
danf2ed70e2018-01-10 16:30:40 +0000378} {dirname/ 16877 {}}
dan128011a2018-01-09 10:29:34 +0000379do_execsql_test 2.2 {
380 INSERT INTO zzz(name, data) VALUES('dirname2', NULL);
381 INSERT INTO zzz(name, data) VALUES('dirname2/file1.txt', 'abcdefghijklmnop');
382 SELECT name, mode, data FROM zzz;
383} {
danf2ed70e2018-01-10 16:30:40 +0000384 dirname/ 16877 {}
385 dirname2/ 16877 {}
dan128011a2018-01-09 10:29:34 +0000386 dirname2/file1.txt 33188 abcdefghijklmnop
387}
388
dan2c4df972018-01-09 20:44:04 +0000389do_catchsql_test 2.3 {
danf2ed70e2018-01-10 16:30:40 +0000390 UPDATE zzz SET name = 'dirname3' WHERE name = 'dirname/';
danf42884c2018-01-13 19:08:24 +0000391} {0 {}}
dan2c4df972018-01-09 20:44:04 +0000392do_execsql_test 2.4 {
393 SELECT name, mode, data FROM zzz;
394} {
danf42884c2018-01-13 19:08:24 +0000395 dirname3/ 16877 {}
danf2ed70e2018-01-10 16:30:40 +0000396 dirname2/ 16877 {}
dan2c4df972018-01-09 20:44:04 +0000397 dirname2/file1.txt 33188 abcdefghijklmnop
398}
danea4125b2018-01-29 19:47:32 +0000399do_zip_tests 2.4a test.zip
dan128011a2018-01-09 10:29:34 +0000400
mistachkinb5a4a702018-03-16 23:54:26 +0000401# Check that the [unzip] utility can unpack our archive.
danf2ed70e2018-01-10 16:30:40 +0000402#
mistachkinb5a4a702018-03-16 23:54:26 +0000403if {[info exists ::UNZIP]} {
danf2ed70e2018-01-10 16:30:40 +0000404 do_test 2.5.1 {
405 forcedelete dirname
danf42884c2018-01-13 19:08:24 +0000406 forcedelete dirname2
mistachkinb5a4a702018-03-16 23:54:26 +0000407 if {$::tcl_platform(platform)=="unix"} {
408 set null /dev/null
409 } else {
410 set null NUL
411 }
412 set rc [catch { exec $::UNZIP test.zip > $null } msg]
danf42884c2018-01-13 19:08:24 +0000413 list $rc $msg
danf2ed70e2018-01-10 16:30:40 +0000414 } {0 {}}
danf42884c2018-01-13 19:08:24 +0000415 do_test 2.5.2 { file isdir dirname3 } 1
danf2ed70e2018-01-10 16:30:40 +0000416 do_test 2.5.3 { file isdir dirname2 } 1
417 do_test 2.5.4 { file isdir dirname2/file1.txt } 0
418 do_test 2.5.5 {
419 set fd [open dirname2/file1.txt]
420 set data [read $fd]
421 close $fd
422 set data
423 } {abcdefghijklmnop}
424}
dan128011a2018-01-09 10:29:34 +0000425
dan4bfd1822018-01-10 17:37:58 +0000426#-------------------------------------------------------------------------
427reset_db
428forcedelete test.zip
429load_static_extension db zipfile
mistachkinb5a4a702018-03-16 23:54:26 +0000430load_static_extension db fileio
dan4bfd1822018-01-10 17:37:58 +0000431
432do_execsql_test 3.0 {
433 CREATE VIRTUAL TABLE temp.x1 USING zipfile('test.zip');
434 INSERT INTO x1(name, data) VALUES('dir1/', NULL);
435 INSERT INTO x1(name, data) VALUES('file1', '1234');
436 INSERT INTO x1(name, data) VALUES('dir1/file2', '5678');
437}
438foreach {tn fname} {
439 1 dir1
440 2 file1
441 3 dir1/file2
442} {
443 do_catchsql_test 3.1.$tn.0 {
444 INSERT INTO x1(name, data) VALUES($fname, NULL);
drh41a6f2c2018-03-10 13:21:41 +0000445 } [list 1 "duplicate name: \"$fname/\""]
dan4bfd1822018-01-10 17:37:58 +0000446 do_catchsql_test 3.1.$tn.1 {
447 INSERT INTO x1(name, data) VALUES($fname || '/', NULL);
drh41a6f2c2018-03-10 13:21:41 +0000448 } [list 1 "duplicate name: \"$fname/\""]
dan4bfd1822018-01-10 17:37:58 +0000449 do_catchsql_test 3.1.$tn.2 {
450 INSERT INTO x1(name, data) VALUES($fname, 'abcd');
drh41a6f2c2018-03-10 13:21:41 +0000451 } [list 1 "duplicate name: \"$fname\""]
dan4bfd1822018-01-10 17:37:58 +0000452}
453
dan66a3a912018-01-11 17:33:48 +0000454do_catchsql_test 3.2 {
455 SELECT rowid FROM x1
456} {1 {no such column: rowid}}
457
dan26333ee2018-01-27 16:29:59 +0000458#-------------------------------------------------------------------------
danfdcd9d42018-01-30 14:07:55 +0000459# Test some error conditions.
460#
461do_catchsql_test 4.1 {
462 CREATE VIRTUAL TABLE yyy USING zipfile();
463} {1 {zipfile constructor requires one argument}}
464do_catchsql_test 4.2 {
465 CREATE VIRTUAL TABLE yyy USING zipfile('test.zip', 'test.zip');
466} {1 {zipfile constructor requires one argument}}
dan26333ee2018-01-27 16:29:59 +0000467
dan15daa6b2018-02-01 19:41:23 +0000468do_catchsql_test 4.3 {
469 SELECT * FROM zipfile()
470} {1 {zipfile() function requires an argument}}
471
472do_catchsql_test 4.4 {
473 SELECT * FROM zipfile('/path/that/does/not/exist')
474} {1 {cannot open file: /path/that/does/not/exist}}
475
476foreach {tn mode} {
477 1 abcd
478 2 brwxrwxrwx
479 3 lrwxrrxrwx
480} {
481 do_catchsql_test 4.5.$tn {
482 WITH m(m) AS ( SELECT $mode)
483 SELECT zipfile('a.txt', m, 1000, 'xyz') FROM m
484 } [list 1 "zipfile: parse error in mode: $mode"]
485}
486
dan668845b2018-02-01 20:42:23 +0000487do_catchsql_test 4.6 {
488 WITH c(name,data) AS ( SELECT 'a.txt', 'abc')
489 SELECT zipfile(name) FROM c
490} {1 {wrong number of arguments to function zipfile()}}
491
492do_catchsql_test 4.7 {
493 WITH c(name,data) AS (
494 SELECT 'a.txt', 'abc' UNION ALL
495 SELECT NULL, 'def'
496 )
497 SELECT zipfile(name,data) FROM c
498} {1 {first argument to zipfile() must be non-NULL}}
499
mistachkinb5a4a702018-03-16 23:54:26 +0000500do_catchsql_test 4.8 {
dan668845b2018-02-01 20:42:23 +0000501 WITH c(name,data,method) AS (
502 SELECT 'a.txt', 'abc', 0
503 UNION SELECT 'b.txt', 'def', 8
504 UNION SELECT 'c.txt', 'ghi', 16
505 )
506 SELECT zipfile(name,NULL,NULL,data,method) FROM c
507} {1 {illegal method value: 16}}
508
mistachkinb5a4a702018-03-16 23:54:26 +0000509do_catchsql_test 4.9 {
dan668845b2018-02-01 20:42:23 +0000510 WITH c(name,data) AS (
511 SELECT 'a.txt', 'abc'
512 UNION SELECT 'b.txt', 'def'
513 UNION SELECT 'c.txt/', 'ghi'
514 )
515 SELECT zipfile(name,NULL,NULL,data) FROM c
516} {1 {non-directory name must not end with /}}
517
dan44091ed2018-01-31 19:13:31 +0000518#--------------------------------------------------------------------------
519
520db func rt remove_timestamps
521do_execsql_test 5.0 {
522 WITH c(name,mtime,data) AS (
523 SELECT 'a.txt', 946684800, 'abc'
524 )
525 SELECT name,mtime,data FROM zipfile(
dan668845b2018-02-01 20:42:23 +0000526 ( SELECT rt( zipfile(name,NULL,mtime,data,NULL) ) FROM c )
dan44091ed2018-01-31 19:13:31 +0000527 )
528} {
529 a.txt 946684800 abc
530}
531
mistachkinb5a4a702018-03-16 23:54:26 +0000532if {[info exists ::UNZIP]} {
dancfaffad2018-01-31 19:45:58 +0000533ifcapable datetime {
dancfaffad2018-01-31 19:45:58 +0000534 forcedelete test1.zip test2.zip
dan44091ed2018-01-31 19:13:31 +0000535 do_test 6.0 {
536 execsql {
537 WITH c(name,mtime,data) AS (
538 SELECT 'a.txt', 946684800, 'abc' UNION ALL
539 SELECT 'b.txt', 1000000000, 'abc' UNION ALL
540 SELECT 'c.txt', 1111111000, 'abc'
541 )
dancfaffad2018-01-31 19:45:58 +0000542 SELECT writefile('test1.zip', rt( zipfile(name, NULL, mtime, data) ) ),
543 writefile('test2.zip', ( zipfile(name, NULL, mtime, data) ) )
544 FROM c;
dan44091ed2018-01-31 19:13:31 +0000545 }
546 forcedelete test_unzip
547 file mkdir test_unzip
mistachkinb5a4a702018-03-16 23:54:26 +0000548 exec $::UNZIP -d test_unzip test1.zip
dan44091ed2018-01-31 19:13:31 +0000549
550 db eval {
dancfaffad2018-01-31 19:45:58 +0000551 SELECT name, strftime('%s', mtime, 'unixepoch', 'localtime')
552 FROM fsdir('test_unzip') WHERE name!='test_unzip'
dan44091ed2018-01-31 19:13:31 +0000553 ORDER BY name
554 }
555 } [list {*}{
556 test_unzip/a.txt 946684800
557 test_unzip/b.txt 1000000000
558 test_unzip/c.txt 1111111000
559 }]
dancfaffad2018-01-31 19:45:58 +0000560
drh3571e7b2018-03-15 15:09:45 +0000561 # fsdir() issue reported on the mailing list on 2018-03-14 by Jack Thaw.
562 do_test 6.0b {
563 db eval {
564 SELECT sum(name LIKE '%/a.txt')
565 FROM (VALUES(1),(2),(3)) CROSS JOIN fsdir('test_unzip')
566 }
567 } {3}
568
danc3ef23a2018-02-01 15:19:54 +0000569 do_execsql_test 6.1 {
570 SELECT name, mtime, data FROM zipfile('test1.zip')
571 } {
572 a.txt 946684800 abc
573 b.txt 1000000000 abc
574 c.txt 1111111000 abc
575 }
576
577 do_test 6.2 {
dancfaffad2018-01-31 19:45:58 +0000578 forcedelete test_unzip
579 file mkdir test_unzip
mistachkinb5a4a702018-03-16 23:54:26 +0000580 exec $::UNZIP -d test_unzip test2.zip
dancfaffad2018-01-31 19:45:58 +0000581
582 db eval {
583 SELECT name, mtime
584 FROM fsdir('test_unzip') WHERE name!='test_unzip'
585 ORDER BY name
586 }
587 } [list {*}{
588 test_unzip/a.txt 946684800
589 test_unzip/b.txt 1000000000
590 test_unzip/c.txt 1111111000
591 }]
danc3ef23a2018-02-01 15:19:54 +0000592
593 do_execsql_test 6.3 {
dan15daa6b2018-02-01 19:41:23 +0000594 SELECT name, mtime, sz, rawdata, data FROM zipfile('test2.zip')
danc3ef23a2018-02-01 15:19:54 +0000595 } {
dan15daa6b2018-02-01 19:41:23 +0000596 a.txt 946684800 3 abc abc
597 b.txt 1000000000 3 abc abc
598 c.txt 1111111000 3 abc abc
danc3ef23a2018-02-01 15:19:54 +0000599 }
dancfaffad2018-01-31 19:45:58 +0000600}
dan44091ed2018-01-31 19:13:31 +0000601}
dan26333ee2018-01-27 16:29:59 +0000602
danc3ef23a2018-02-01 15:19:54 +0000603#-------------------------------------------------------------------------
dan15daa6b2018-02-01 19:41:23 +0000604# Force an IO error by truncating the zip archive to zero bytes in size
605# while it is being read.
danc3ef23a2018-02-01 15:19:54 +0000606forcedelete test.zip
607do_test 7.0 {
608 execsql {
609 WITH c(name,data) AS (
610 SELECT '1', randomblob(1000000) UNION ALL
611 SELECT '2', randomblob(1000000) UNION ALL
612 SELECT '3', randomblob(1000000)
613 )
614 SELECT writefile('test.zip', zipfile(name, data) ) FROM c;
615 }
616
617 list [catch {
618 db eval { SELECT name, data FROM zipfile('test.zip') } {
619 if {$name==2} { close [open test.zip w+] }
620 }
621 } msg] $msg
622} {1 {error in fread()}}
623
dan15daa6b2018-02-01 19:41:23 +0000624forcedelete test.zip
625do_execsql_test 8.0.1 {
626 CREATE VIRTUAL TABLE zz USING zipfile('test.zip');
627 BEGIN;
628 INSERT INTO zz(name, data) VALUES('a.txt', '1');
629 INSERT INTO zz(name, data) VALUES('b.txt', '2');
630 INSERT INTO zz(name, data) VALUES('c.txt', '1');
631 INSERT INTO zz(name, data) VALUES('d.txt', '2');
632 SELECT name, data FROM zz;
633} {
634 a.txt 1 b.txt 2 c.txt 1 d.txt 2
635}
636do_test 8.0.2 {
637 db eval { SELECT name, data FROM zz } {
638 if { $data=="2" } { db eval { DELETE FROM zz WHERE name=$name } }
639 }
640 execsql { SELECT name, data FROM zz }
641} {a.txt 1 c.txt 1}
642do_test 8.0.3 {
643 db eval { SELECT name, data FROM zz } {
644 db eval { DELETE FROM zz WHERE name=$name }
645 }
646 execsql { SELECT name, data FROM zz }
647} {}
648execsql COMMIT
649
dand99f49f2018-03-29 23:54:00 +0000650catch { forcedelete test_unzip }
651catch { file mkdir test_unzip }
dan15daa6b2018-02-01 19:41:23 +0000652do_execsql_test 8.1.1 {
653 CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip');
654}
655do_catchsql_test 8.1.2 {
656 INSERT INTO nogood(name, data) VALUES('abc', 'def');
657} {1 {zipfile: failed to open file test_unzip for writing}}
658
659do_execsql_test 8.2.1 {
660 DROP TABLE nogood;
661 BEGIN;
662 CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip');
663}
664do_catchsql_test 8.2.2 {
665 INSERT INTO nogood(name, data) VALUES('abc', 'def');
666} {1 {zipfile: failed to open file test_unzip for writing}}
667do_execsql_test 8.2.3 {
668 COMMIT;
669}
670
671forcedelete test.zip
672do_execsql_test 8.3.1 {
673 BEGIN;
674 CREATE VIRTUAL TABLE ok USING zipfile('test.zip');
675 INSERT INTO ok(name, data) VALUES ('sqlite3', 'elf');
676 COMMIT;
677}
dan4bfd1822018-01-10 17:37:58 +0000678
dan668845b2018-02-01 20:42:23 +0000679#-------------------------------------------------------------------------
680# Test that the zipfile aggregate correctly adds and removes "/" from
681# the ends of directory file names.
682do_execsql_test 9.0 {
683 WITH src(nm) AS (
684 VALUES('dir1') UNION ALL
685 VALUES('dir2/') UNION ALL
686 VALUES('dir3//') UNION ALL
687 VALUES('dir4///') UNION ALL
688 VALUES('/')
689 )
690 SELECT name FROM zipfile((SELECT zipfile(nm, NULL) FROM src))
691} {dir1/ dir2/ dir3/ dir4/ /}
drh42f3c5f2018-03-10 14:17:01 +0000692
693#-------------------------------------------------------------------------
694# INSERT OR REPLACE and INSERT OR IGNORE
695#
696catch {db close}
697forcedelete test.zip test.db
698sqlite3 db :memory:
699load_static_extension db zipfile
mistachkinb5a4a702018-03-16 23:54:26 +0000700load_static_extension db fileio
701
drh42f3c5f2018-03-10 14:17:01 +0000702do_execsql_test 10.0 {
703 CREATE VIRTUAL TABLE z USING zipfile('test.zip');
704} {}
705do_catchsql_test 10.1 {
706 INSERT INTO z(name,data) VALUES('a0','one'),('a0','two');
707} {1 {duplicate name: "a0"}}
708do_execsql_test 10.2 {
709 SELECT name, data FROM z;
710} {a0 one}
711do_execsql_test 10.3 {
712 REPLACE INTO z(name,data) VALUES('a0','three'),('a0','four');
713} {}
714do_execsql_test 10.4 {
715 SELECT name, data FROM z;
716} {a0 four}
717do_execsql_test 10.5 {
718 INSERT OR IGNORE INTO z(name,data) VALUES('a0','five'),('a0','six');
719} {}
720do_execsql_test 10.6 {
721 SELECT name, data FROM z;
722} {a0 four}
723
mistachkin2cc8f482018-03-17 02:13:13 +0000724do_execsql_test 11.1 {
725 DELETE FROM z;
726} {}
727do_execsql_test 11.2 {
728 SELECT name, data FROM z;
729} {}
730do_execsql_test 11.3 {
731 INSERT INTO z (name,data) VALUES ('b0','one');
732 SELECT name, data FROM z;
733} {b0 one}
734do_execsql_test 11.4 {
735 UPDATE z SET name = 'b1' WHERE name = 'b0';
736 SELECT name, data FROM z;
737} {b1 one}
738do_execsql_test 11.5 {
739 INSERT INTO z (name,data) VALUES ('b0','one');
740 SELECT name, data FROM z ORDER BY name;
741} {b0 one b1 one}
742do_catchsql_test 11.6 {
743 UPDATE z SET name = 'b1' WHERE name = 'b0';
744} {1 {duplicate name: "b1"}}
745do_execsql_test 11.7 {
746 UPDATE z SET data = 'two' WHERE name = 'b0';
747 SELECT name, data FROM z ORDER BY name;
748} {b0 two b1 one}
749do_catchsql_test 11.8 {
750 UPDATE z SET name = 'b1';
751} {1 {duplicate name: "b1"}}
752do_catchsql_test 11.9 {
753 UPDATE z SET name = 'b2';
754} {1 {duplicate name: "b2"}}
755do_execsql_test 11.10 {
756 UPDATE z SET name = name;
757 SELECT name, data FROM z ORDER BY name;
758} {b0 two b2 one}
759do_execsql_test 11.11 {
760 UPDATE z SET name = name || 'suffix';
761 SELECT name, data FROM z ORDER BY name;
762} {b0suffix two b2suffix one}
drh42f3c5f2018-03-10 14:17:01 +0000763
dancbfaa072018-11-16 08:36:15 +0000764
765if {$tcl_platform(platform)!="windows"} {
766 do_test 12.0 {
767 catch { file delete -force subdir }
768 foreach {path sz} {
769 subdir/x1.txt 143
770 subdir/x2.txt 153
771 } {
772 set dir [file dirname $path]
773 catch { file mkdir $dir }
774 set fd [open $path w]
775 puts -nonewline $fd [string repeat 1 $sz]
776 close $fd
777 }
778 } {}
779
780 do_execsql_test 12.1 {
781 SELECT name FROM fsdir('subdir') ORDER BY 1;
782 } {subdir subdir/x1.txt subdir/x2.txt}
783
784 do_execsql_test 12.2 {
785 CREATE TABLE d AS SELECT 'subdir' d;
786 CREATE TABLE x AS SELECT 1 x;
787 }
788
789 do_execsql_test 12.4 {
790 SELECT name FROM d JOIN x JOIN fsdir(d) ORDER BY 1;
791 } {subdir subdir/x1.txt subdir/x2.txt}
792
793 do_execsql_test 12.5 {
794 SELECT name FROM d JOIN x JOIN fsdir('.', d) ORDER BY 1;
795 } {. ./x1.txt ./x2.txt}
796}
797
drh54d50102019-12-19 15:15:40 +0000798# 2019-12-18 Yongheng and Rui fuzzer
799#
800do_execsql_test 13.10 {
801 DROP TABLE IF EXISTS t0;
802 DROP TABLE IF EXISTS t1;
803 CREATE TABLE t0(a,b,c,d,e,f,g);
804 REPLACE INTO t0(c,b,f) VALUES(10,10,10);
805 CREATE VIRTUAL TABLE t1 USING zipfile('h.zip');
806 REPLACE INTO t1 SELECT * FROM t0;
807 SELECT quote(name),quote(mode),quote(mtime),quote(sz),quote(rawdata),
808 quote(data),quote(method) FROM t1;
809} {'' 10 10 2 X'3130' X'3130' 0}
810
drh1e490c42019-12-23 21:11:15 +0000811# 2019-12-23 Yongheng and Rui fuzzer
812# Run using valgrind to see the problem.
813#
814do_execsql_test 14.10 {
815 DROP TABLE t1;
816 CREATE TABLE t1(x char);
817 INSERT INTO t1(x) VALUES('1');
818 INSERT INTO t1(x) SELECT zipfile(x, 'xyz') FROM t1;
819 INSERT INTO t1(x) SELECT zipfile(x, 'uvw') FROM t1;
820 SELECT count(*) FROM t1;
821 PRAGMA integrity_check;
822} {3 ok}
drh54d50102019-12-19 15:15:40 +0000823
drh8d7f44c2019-12-27 00:19:53 +0000824# 2019-12-26 More problems in zipfile from the Yongheng and Rui fuzzer
825#
826do_execsql_test 15.10 {
827 DROP TABLE IF EXISTS t1;
828 CREATE VIRTUAL TABLE t1 USING zipfile(null);
829 REPLACE INTO t1 VALUES(null,null,0,null,null,null,null);
830} {}
831do_execsql_test 15.20 {
832 DROP TABLE IF EXISTS t2;
833 CREATE VIRTUAL TABLE t2 USING zipfile(null);
834 REPLACE INTO t2 values(null,null,null,null,null,10,null);
835} {}
836
drh0c4f8202020-01-02 21:30:13 +0000837# 2020-01-02 Yongheng fuzzer discovery
838#
839do_catchsql_test 16.10 {
840 DELETE FROM zipfile;
drh0d21eae2020-01-03 16:38:54 +0000841} {1 {zipfile: missing filename}}
842do_catchsql_test 16.20 {
843 REPLACE INTO zipfile VALUES(null,null,null,null,null,123,null);
844} {1 {zipfile: missing filename}}
drh8d7f44c2019-12-27 00:19:53 +0000845
dan373dc3b2017-12-29 20:19:03 +0000846finish_test