Snapshot of upstream SQLite 3.43.2
[sqlcipher.git] / test / zipfile.test
blob4d09e08b1c6c60a4173567418df159d18189dd71
1 # 2017 December 9
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
13 package require Tcl 8.6
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
17 set testprefix zipfile
19 ifcapable !vtab {
20   finish_test; return
22 if {[catch {load_static_extension db zipfile} error]} {
23   puts "Skipping zipfile tests, hit load error: $error"
24   finish_test; return
26 if {[catch {load_static_extension db fileio} error]} {
27   puts "Skipping zipfile tests, hit load error: $error"
28   finish_test; return
31 proc readfile {f} {
32   set fd [open $f]
33   fconfigure $fd -translation binary -encoding binary
34   set data [read $fd]
35   close $fd
36   set data
39 unset -nocomplain ::UNZIP
41 if {[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   }
63   proc do_unzip {file} {
64     forcedelete test_unzip
65     file mkdir test_unzip
66     exec $::UNZIP -d test_unzip $file
68     db func modefix fix_stat_mode
70     set res [db eval {
71       SELECT replace(name,'test_unzip/',''),modefix(name,mode),mtime,data
72       FROM fsdir('test_unzip') 
73       WHERE name!='test_unzip'
74       ORDER BY name
75     }]
76     set res
77   }
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.
85 proc remove_timestamps {blob} {
86   set hex [binary encode hex $blob]
87   set hex [string map {55540500 00000500} $hex]
88   binary decode hex $hex
92 # 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:
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 #         )
102 proc do_zipfile_blob_test {tn file} {
104   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   )}
112   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
119   uplevel [list do_test $tn.1 [list set {} $r2] $r1]
120   uplevel [list do_test $tn.2 [list set {} $r3] $r1]
123 # Argument $file is a zip file on disk. This command runs tests to:
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.
129 #   2. Creates a new archive with the same contents using the zipfile()
130 #      aggregate function as follows:
132 #      SELECT writefile('test_unzip.zip',
133 #          ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) )
134 #      );
136 #      Then tests that unpacking the new archive using [unzip] produces
137 #      the same results as in (1).
139 proc do_unzip_test {tn file} {
140   db func sss strip_slash
142   db eval {
143     SELECT writefile('test_unzip.zip',
144         ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) )
145     );
146   }
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]
154   uplevel [list do_test $tn.1 [list set {} $r2] $r1]
155   uplevel [list do_test $tn.2 [list set {} $r3] $r1]
157 proc strip_slash {in} { regsub {/$} $in {} }
159 proc do_zip_tests {tn file} {
160   uplevel do_zipfile_blob_test $tn.1 $file
161   if {[info exists ::UNZIP]} {
162     uplevel do_unzip_test $tn.2 $file
163   }
166 forcedelete test.zip
167 do_execsql_test 1.0 {
168   CREATE VIRTUAL TABLE temp.zz USING zipfile('test.zip');
169   PRAGMA table_info(zz);
170 } {
171   0 name {} 1 {} 1 
172   1 mode {} 0 {} 0 
173   2 mtime {} 0 {} 0 
174   3 sz {} 0 {} 0 
175   4 rawdata {} 0 {} 0
176   5 data {} 0 {} 0
177   6 method {} 0 {} 0
180 do_catchsql_test 1.1.0.1 {
181   INSERT INTO zz(name, mode, mtime, sz, rawdata, method) 
182   VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
183 } {1 {rawdata must be NULL}}
184 do_catchsql_test 1.1.0.2 {
185   INSERT INTO zz(name, mtime, sz, data, method) 
186   VALUES('g.txt', 1000000002, 5, '12345', 0);
187 } {1 {sz must be NULL}}
188 do_catchsql_test 1.1.0.3 {
189   INSERT INTO zz(name, mtime, rawdata, method) 
190   VALUES('g.txt', 1000000002, '12345', 0);
191 } {1 {rawdata must be NULL}}
192 do_catchsql_test 1.1.0.4 {
193   INSERT INTO zz(name, data, method) 
194   VALUES('g.txt', '12345', 7);
195 } {1 {unknown compression method: 7}}
197 do_execsql_test 1.1.1 {
198   INSERT INTO zz(name, mode, mtime, data, method) 
199   VALUES('f.txt', '-rw-r--r--', 1000000000, 'abcde', 0);
201 do_execsql_test 1.1.2 {
202   INSERT INTO zz(name, mode, mtime, data, method) 
203   VALUES('g.txt', NULL, 1000000002, '12345', 0);
206 do_execsql_test 1.2 {
207   SELECT name, mtime, data FROM zipfile('test.zip')
208 } {
209   f.txt 1000000000 abcde 
210   g.txt 1000000002 12345
212 do_zip_tests 1.2a test.zip
214 do_execsql_test 1.3 {
215   INSERT INTO zz(name, mode, mtime, data) VALUES('h.txt', 
216     '-rw-r--r--', 1000000004, 'aaaaaaaaaabbbbbbbbbb'
217   );
219 do_zip_tests 1.3a test.zip
221 do_execsql_test 1.4 {
222   SELECT name, mtime, data, method FROM zipfile('test.zip');
223 } {
224   f.txt 1000000000 abcde 0
225   g.txt 1000000002 12345 0
226   h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8
229 ifcapable 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   }
239 do_catchsql_test 1.4.2 {
240   SELECT zipfile_cds(mode) FROM zipfile('test.zip');
241 } {0 {{} {} {}}}
243 do_execsql_test 1.5.1 {
244   BEGIN;
245     INSERT INTO zz(name, mode, mtime, data, method)
246     VALUES('i.txt', '-rw-r--r--', 1000000006, 'zxcvb', 0);
247     SELECT name FROM zz;
248   COMMIT;
249 } {f.txt g.txt h.txt i.txt}
250 do_execsql_test 1.5.2 {
251   SELECT name FROM zz;
252 } {f.txt g.txt h.txt i.txt}
253 do_execsql_test 1.5.3 {
254   SELECT data FROM zz WHERE name='i.txt';
255 } {zxcvb}
257 do_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}
262 do_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
269 do_zip_tests 1.6.1a test.zip
271 do_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
280 if {$::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
288 do_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
296 do_zip_tests 1.6.3a test.zip
298 do_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');
301 } [string map [list %perms% $perms] {
302   blue.txt 33188 1000000000 abcde 0
303   h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
304   i.txt 33188 4 zxcvb 0
306 do_zip_tests 1.6.4a test.zip
308 do_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');
311 } [string map [list %perms% $perms] {
312   blue.txt 33188 1000000000 edcba 0
313   h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
314   i.txt 33188 4 zxcvb 0
317 do_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');
320 } [string map [list %perms% $perms] {
321   blue.txt/ 16877 1000000000 {} 0
322   h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
323   i.txt 33188 4 zxcvb 0
326 do_catchsql_test 1.6.7 {
327   UPDATE zz SET data=NULL WHERE name='i.txt'
328 } {1 {zipfile: mode does not match data}}
329 do_execsql_test 1.6.8 {
330   SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
331 } [string map [list %perms% $perms] {
332   blue.txt/ 16877 1000000000 {} 0
333   h.txt %perms% 1000000004 aaaaaaaaaabbbbbbbbbb 8
334   i.txt 33188 4 zxcvb 0
337 do_execsql_test 1.6.9 {
338   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
346 do_execsql_test 1.6.10 {
347   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 {}
356 do_execsql_test 1.6.11 {
357   SELECT name, data FROM zz WHERE name LIKE '%txt'
358 } {
359   h.txt aaaaaaaaaabbbbbbbbbb
360   i.txt {}
363 do_execsql_test 1.7 {
364   DELETE FROM zz;
365   SELECT * FROM zz;
366 } {}
368 #-------------------------------------------------------------------------
369 db close
370 forcedelete test.zip
371 reset_db
372 load_static_extension db fileio
373 load_static_extension db zipfile
374 do_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;
378 } {dirname/ 16877 {}}
379 do_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 } {
384   dirname/ 16877 {}
385   dirname2/ 16877 {}
386   dirname2/file1.txt 33188 abcdefghijklmnop
389 do_catchsql_test 2.3 {
390   UPDATE zzz SET name = 'dirname3' WHERE name = 'dirname/';
391 } {0 {}}
392 do_execsql_test 2.4 {
393   SELECT name, mode, data FROM zzz;
394 } {
395   dirname3/ 16877 {}
396   dirname2/ 16877 {}
397   dirname2/file1.txt 33188 abcdefghijklmnop
399 do_zip_tests 2.4a test.zip
401 # Check that the [unzip] utility can unpack our archive.
403 if {[info exists ::UNZIP]} {
404   do_test 2.5.1 {
405     forcedelete dirname
406     forcedelete dirname2
407     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]
413     list $rc $msg
414   } {0 {}}
415   do_test 2.5.2 { file isdir dirname3 } 1
416   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}
426 #-------------------------------------------------------------------------
427 reset_db
428 forcedelete test.zip
429 load_static_extension db zipfile
430 load_static_extension db fileio
432 do_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');
438 foreach {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);
445   } [list 1 "duplicate name: \"$fname/\""]
446   do_catchsql_test 3.1.$tn.1 {
447     INSERT INTO x1(name, data) VALUES($fname || '/', NULL);
448   } [list 1 "duplicate name: \"$fname/\""]
449   do_catchsql_test 3.1.$tn.2 {
450     INSERT INTO x1(name, data) VALUES($fname, 'abcd');
451   } [list 1 "duplicate name: \"$fname\""]
454 do_catchsql_test 3.2 {
455   SELECT rowid FROM x1
456 } {1 {no such column: rowid}}
458 #-------------------------------------------------------------------------
459 # Test some error conditions.
461 do_catchsql_test 4.1 {
462   CREATE VIRTUAL TABLE yyy USING zipfile();
463 } {1 {zipfile constructor requires one argument}}
464 do_catchsql_test 4.2 {
465   CREATE VIRTUAL TABLE yyy USING zipfile('test.zip', 'test.zip');
466 } {1 {zipfile constructor requires one argument}}
468 do_catchsql_test 4.3 {
469   SELECT * FROM zipfile()
470 } {1 {zipfile() function requires an argument}}
472 do_catchsql_test 4.4 {
473   SELECT * FROM zipfile('/path/that/does/not/exist')
474 } {1 {cannot open file: /path/that/does/not/exist}}
476 foreach {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"]
487 do_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()}}
492 do_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}}
500 do_catchsql_test 4.8 {
501   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}}
509 do_catchsql_test 4.9 {
510   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 /}}
518 #--------------------------------------------------------------------------
520 db func rt remove_timestamps
521 do_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(
526     ( SELECT rt( zipfile(name,NULL,mtime,data,NULL) ) FROM c )
527   )
528 } {
529   a.txt 946684800 abc
532 if {[info exists ::UNZIP]} {
533 ifcapable datetime {
534   forcedelete test1.zip test2.zip
535   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       )
542       SELECT writefile('test1.zip', rt( zipfile(name, NULL, mtime, data) ) ),
543              writefile('test2.zip',   ( zipfile(name, NULL, mtime, data) ) ) 
544       FROM c;
545     }
546     forcedelete test_unzip
547     file mkdir test_unzip
548     exec $::UNZIP -d test_unzip test1.zip
550     db eval {
551       SELECT name, strftime('%s', mtime, 'unixepoch', 'localtime') 
552       FROM fsdir('test_unzip') WHERE name!='test_unzip'
553       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   }]
561   # 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}
569   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   }
577   do_test 6.2 {
578     forcedelete test_unzip
579     file mkdir test_unzip
580     exec $::UNZIP -d test_unzip test2.zip
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   }]
593   do_execsql_test 6.3 {
594     SELECT name, mtime, sz, rawdata, data FROM zipfile('test2.zip')
595   } {
596     a.txt 946684800   3 abc abc
597     b.txt 1000000000  3 abc abc
598     c.txt 1111111000  3 abc abc
599   }
603 #-------------------------------------------------------------------------
604 # Force an IO error by truncating the zip archive to zero bytes in size
605 # while it is being read.
606 forcedelete test.zip
607 do_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   }
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()}}
624 forcedelete test.zip
625 do_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
636 do_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}
642 do_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 } {}
648 execsql COMMIT
650 catch { forcedelete test_unzip }
651 catch { file mkdir test_unzip }
652 do_execsql_test 8.1.1 {
653   CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip');
655 do_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}}
659 do_execsql_test 8.2.1 {
660   DROP TABLE nogood;
661   BEGIN;
662     CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip');
664 do_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}}
667 do_execsql_test 8.2.3 {
668   COMMIT;
671 forcedelete test.zip
672 do_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;
679 #-------------------------------------------------------------------------
680 # Test that the zipfile aggregate correctly adds and removes "/" from
681 # the ends of directory file names.
682 do_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/ /}
693 #-------------------------------------------------------------------------
694 # INSERT OR REPLACE and INSERT OR IGNORE
696 catch {db close}
697 forcedelete test.zip test.db
698 sqlite3 db :memory:
699 load_static_extension db zipfile
700 load_static_extension db fileio
702 do_execsql_test 10.0 {
703   CREATE VIRTUAL TABLE z USING zipfile('test.zip');
704 } {}
705 do_catchsql_test 10.1 {
706   INSERT INTO z(name,data) VALUES('a0','one'),('a0','two');
707 } {1 {duplicate name: "a0"}}
708 do_execsql_test 10.2 {
709   SELECT name, data FROM z;
710 } {a0 one}
711 do_execsql_test 10.3 {
712   REPLACE INTO z(name,data) VALUES('a0','three'),('a0','four');
713 } {}
714 do_execsql_test 10.4 {
715   SELECT name, data FROM z;
716 } {a0 four}
717 do_execsql_test 10.5 {
718   INSERT OR IGNORE INTO z(name,data) VALUES('a0','five'),('a0','six');
719 } {}
720 do_execsql_test 10.6 {
721   SELECT name, data FROM z;
722 } {a0 four}
724 do_execsql_test 11.1 {
725   DELETE FROM z;
726 } {}
727 do_execsql_test 11.2 {
728   SELECT name, data FROM z;
729 } {}
730 do_execsql_test 11.3 {
731   INSERT INTO z (name,data) VALUES ('b0','one');
732   SELECT name, data FROM z;
733 } {b0 one}
734 do_execsql_test 11.4 {
735   UPDATE z SET name = 'b1' WHERE name = 'b0';
736   SELECT name, data FROM z;
737 } {b1 one}
738 do_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}
742 do_catchsql_test 11.6 {
743   UPDATE z SET name = 'b1' WHERE name = 'b0';
744 } {1 {duplicate name: "b1"}}
745 do_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}
749 do_catchsql_test 11.8 {
750   UPDATE z SET name = 'b1';
751 } {1 {duplicate name: "b1"}}
752 do_catchsql_test 11.9 {
753   UPDATE z SET name = 'b2';
754 } {1 {duplicate name: "b2"}}
755 do_execsql_test 11.10 {
756   UPDATE z SET name = name;
757   SELECT name, data FROM z ORDER BY name;
758 } {b0 two b2 one}
759 do_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}
765 if {$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}
793   do_execsql_test 12.5 {
794     SELECT name FROM d JOIN x JOIN fsdir('.', d) ORDER BY 1;
795   } {. ./x1.txt ./x2.txt}
798 # 2019-12-18 Yongheng and Rui fuzzer
800 do_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}
811 # 2019-12-23 Yongheng and Rui fuzzer
812 # Run using valgrind to see the problem.
814 do_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}
824 # 2019-12-26 More problems in zipfile from the Yongheng and Rui fuzzer
826 do_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 } {}
831 do_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 } {}
837 # 2020-01-02 Yongheng fuzzer discovery
839 do_catchsql_test 16.10 {
840   DELETE FROM zipfile;
841 } {1 {zipfile: missing filename}}
842 do_catchsql_test 16.20 {
843   REPLACE INTO zipfile VALUES(null,null,null,null,null,123,null);
844 } {1 {zipfile: missing filename}}
846 # 2021-04-22 forum https://sqlite.org/forum/forumpost/d82289d69f
847 do_execsql_test 17.1 {
848   WITH vlist(x) AS (
849      VALUES(9223372036854775807),
850            (-9223372036854775808),
851            (9223372036854775806),
852            (-9223372036854775807)
853   )
854   SELECT DISTINCT typeof(zipfile(0,0,x,0)) FROM vlist;
855 } {blob}
857 # 2023-01-04
858 # https://sqlite.org/forum/forumpost/d1c96a9032e564f8
859 # Call to fopen() with a NULL filename.
861 do_catchsql_test 18.1 {
862   SELECT * FROM zipfile(NULL);
863 } {1 {cannot open file: }}
865 # 2023-05-03 https://sqlite.org/forum/info/f03f1e4c5a5c9959
867 do_test 19.1 {
868   sqlite3 db :memory:
869   load_static_extension db zipfile
870   forcedelete zipfile19.zip
871   db eval {
872     CREATE VIRTUAL TABLE t1 USING zipfile('zipfile19.zip');
873     INSERT INTO t1 DEFAULT VALUES;
874   }
875   db close
876   sqlite3 db :memory:
877   load_static_extension db zipfile
878   db eval {
879     CREATE VIRTUAL TABLE v0 USING zipfile('zipfile19.zip');
880     SAVEPOINT y;
881     DELETE FROM v0 WHERE 9;
882     INSERT INTO v0 DEFAULT VALUES;
883   }
884 } {}
885 forcedelete zipfile19.zip
887 finish_test