github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/zipfile.test (about)

     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  
    13  package require Tcl 8.6
    14  
    15  set testdir [file dirname $argv0]
    16  source $testdir/tester.tcl
    17  set testprefix zipfile
    18  
    19  ifcapable !vtab {
    20    finish_test; return
    21  }
    22  if {[catch {load_static_extension db zipfile} error]} {
    23    puts "Skipping zipfile tests, hit load error: $error"
    24    finish_test; return
    25  }
    26  if {[catch {load_static_extension db fileio} error]} {
    27    puts "Skipping zipfile tests, hit load error: $error"
    28    finish_test; return
    29  }
    30  
    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
    37  }
    38  
    39  unset -nocomplain ::UNZIP
    40  
    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
    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  #
    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
    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  #
   102  proc 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  #
   139  proc 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  }
   157  proc strip_slash {in} { regsub {/$} $in {} }
   158  
   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    }
   164  }
   165  
   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
   178  }
   179  
   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}}
   196  
   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);
   200  }
   201  do_execsql_test 1.1.2 {
   202    INSERT INTO zz(name, mode, mtime, data, method) 
   203    VALUES('g.txt', NULL, 1000000002, '12345', 0);
   204  }
   205  
   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
   211  }
   212  do_zip_tests 1.2a test.zip
   213  
   214  do_execsql_test 1.3 {
   215    INSERT INTO zz(name, mode, mtime, data) VALUES('h.txt', 
   216      '-rw-r--r--', 1000000004, 'aaaaaaaaaabbbbbbbbbb'
   217    );
   218  }
   219  do_zip_tests 1.3a test.zip
   220  
   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
   227  }
   228  
   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    }
   238  }
   239  do_catchsql_test 1.4.2 {
   240    SELECT zipfile_cds(mode) FROM zipfile('test.zip');
   241  } {0 {{} {} {}}}
   242  
   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}
   256  
   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}
   261  
   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
   268  }
   269  do_zip_tests 1.6.1a test.zip
   270  
   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
   278  }
   279  
   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
   286  }
   287  
   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
   295  }]
   296  do_zip_tests 1.6.3a test.zip
   297  
   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
   305  }]
   306  do_zip_tests 1.6.4a test.zip
   307  
   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
   315  }]
   316  
   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
   324  }]
   325  
   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
   335  }]
   336  
   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
   344  }]
   345  
   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 {}
   354  }
   355  
   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 {}
   361  }
   362  
   363  do_execsql_test 1.7 {
   364    DELETE FROM zz;
   365    SELECT * FROM zz;
   366  } {}
   367  
   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
   387  }
   388  
   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
   398  }
   399  do_zip_tests 2.4a test.zip
   400  
   401  # Check that the [unzip] utility can unpack our archive.
   402  #
   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}
   424  }
   425  
   426  #-------------------------------------------------------------------------
   427  reset_db
   428  forcedelete test.zip
   429  load_static_extension db zipfile
   430  load_static_extension db fileio
   431  
   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');
   437  }
   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\""]
   452  }
   453  
   454  do_catchsql_test 3.2 {
   455    SELECT rowid FROM x1
   456  } {1 {no such column: rowid}}
   457  
   458  #-------------------------------------------------------------------------
   459  # Test some error conditions.
   460  #
   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}}
   467  
   468  do_catchsql_test 4.3 {
   469    SELECT * FROM zipfile()
   470  } {1 {zipfile() function requires an argument}}
   471  
   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}}
   475  
   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"]
   485  }
   486  
   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()}}
   491  
   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}}
   499  
   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}}
   508  
   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 /}}
   517  
   518  #--------------------------------------------------------------------------
   519  
   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
   530  }
   531  
   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
   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.
   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    }
   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  
   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
   635  }
   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
   649  
   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');
   654  }
   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}}
   658  
   659  do_execsql_test 8.2.1 {
   660    DROP TABLE nogood;
   661    BEGIN;
   662      CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip');
   663  }
   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;
   669  }
   670  
   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;
   677  }
   678  
   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/ /}
   692  
   693  #-------------------------------------------------------------------------
   694  # INSERT OR REPLACE and INSERT OR IGNORE
   695  #
   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
   701  
   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}
   723  
   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}
   763  
   764  
   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}
   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  #
   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}
   810  
   811  # 2019-12-23 Yongheng and Rui fuzzer
   812  # Run using valgrind to see the problem.
   813  #
   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}
   823  
   824  # 2019-12-26 More problems in zipfile from the Yongheng and Rui fuzzer
   825  #
   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  } {}
   836  
   837  # 2020-01-02 Yongheng fuzzer discovery
   838  #
   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}}
   845  
   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}
   856    
   857  
   858  finish_test