xref: /sqlite-3.40.0/test/zipfile.test (revision e99cb2da)
1# 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
13package require Tcl 8.6
14
15set testdir [file dirname $argv0]
16source $testdir/tester.tcl
17set testprefix zipfile
18
19ifcapable !vtab {
20  finish_test; return
21}
22if {[catch {load_static_extension db zipfile} error]} {
23  puts "Skipping zipfile tests, hit load error: $error"
24  finish_test; return
25}
26if {[catch {load_static_extension db fileio} error]} {
27  puts "Skipping zipfile tests, hit load error: $error"
28  finish_test; return
29}
30
31proc 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
37}
38
39unset -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  }
63  proc do_unzip {file} {
64    forcedelete test_unzip
65    file mkdir test_unzip
66    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
72      FROM fsdir('test_unzip')
73      WHERE name!='test_unzip'
74      ORDER BY name
75    }]
76    set res
77  }
78}
79
80
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
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:
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} {
103
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  )}
110
111
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
118
119  uplevel [list do_test $tn.1 [list set {} $r2] $r1]
120  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} {
140  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
161  if {[info exists ::UNZIP]} {
162    uplevel do_unzip_test $tn.2 $file
163  }
164}
165
166forcedelete test.zip
167do_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
178}
179
180do_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}}
184do_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}}
188do_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}}
192do_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}}
196
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);
204}
205
206do_execsql_test 1.2 {
207  SELECT name, mtime, data FROM zipfile('test.zip')
208} {
209  f.txt 1000000000 abcde
210  g.txt 1000000002 12345
211}
212do_zip_tests 1.2a test.zip
213
214do_execsql_test 1.3 {
215  INSERT INTO zz(name, mode, mtime, data) VALUES('h.txt',
216    '-rw-r--r--', 1000000004, 'aaaaaaaaaabbbbbbbbbb'
217  );
218}
219do_zip_tests 1.3a test.zip
220
221do_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
227}
228
229ifcapable 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  }
238}
239do_catchsql_test 1.4.2 {
240  SELECT zipfile_cds(mode) FROM zipfile('test.zip');
241} {0 {{} {} {}}}
242
243do_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}
250do_execsql_test 1.5.2 {
251  SELECT name FROM zz;
252} {f.txt g.txt h.txt i.txt}
253do_execsql_test 1.5.3 {
254  SELECT data FROM zz WHERE name='i.txt';
255} {zxcvb}
256
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
262do_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}
269do_zip_tests 1.6.1a test.zip
270
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
280if {$::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
286}
287
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}]
296do_zip_tests 1.6.3a test.zip
297
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');
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
305}]
306do_zip_tests 1.6.4a test.zip
307
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');
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
315}]
316
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');
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
324}]
325
326do_catchsql_test 1.6.7 {
327  UPDATE zz SET data=NULL WHERE name='i.txt'
328} {1 {zipfile: mode does not match data}}
329do_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
335}]
336
337do_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
344}]
345
346do_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 {}
354}
355
356do_execsql_test 1.6.11 {
357  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
368#-------------------------------------------------------------------------
369db close
370forcedelete test.zip
371reset_db
372load_static_extension db fileio
373load_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;
378} {dirname/ 16877 {}}
379do_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
387}
388
389do_catchsql_test 2.3 {
390  UPDATE zzz SET name = 'dirname3' WHERE name = 'dirname/';
391} {0 {}}
392do_execsql_test 2.4 {
393  SELECT name, mode, data FROM zzz;
394} {
395  dirname3/ 16877 {}
396  dirname2/ 16877 {}
397  dirname2/file1.txt 33188 abcdefghijklmnop
398}
399do_zip_tests 2.4a test.zip
400
401# Check that the [unzip] utility can unpack our archive.
402#
403if {[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}
424}
425
426#-------------------------------------------------------------------------
427reset_db
428forcedelete test.zip
429load_static_extension db zipfile
430load_static_extension db fileio
431
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);
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\""]
452}
453
454do_catchsql_test 3.2 {
455  SELECT rowid FROM x1
456} {1 {no such column: rowid}}
457
458#-------------------------------------------------------------------------
459# 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}}
467
468do_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
487do_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
500do_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}}
508
509do_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 /}}
517
518#--------------------------------------------------------------------------
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(
526    ( SELECT rt( zipfile(name,NULL,mtime,data,NULL) ) FROM c )
527  )
528} {
529  a.txt 946684800 abc
530}
531
532if {[info exists ::UNZIP]} {
533ifcapable 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
549
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  }]
560
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}
568
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  }
576
577  do_test 6.2 {
578    forcedelete test_unzip
579    file mkdir test_unzip
580    exec $::UNZIP -d test_unzip test2.zip
581
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  }]
592
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  }
600}
601}
602
603#-------------------------------------------------------------------------
604# Force an IO error by truncating the zip archive to zero bytes in size
605# while it is being read.
606forcedelete 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
624forcedelete 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
650catch { forcedelete test_unzip }
651catch { file mkdir test_unzip }
652do_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}
678
679#-------------------------------------------------------------------------
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/ /}
692
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
700load_static_extension db fileio
701
702do_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
724do_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}
763
764
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
798# 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
811
812finish_test
813