/ Check-in [48f1c556]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix a problem triggered when a zipfile virtual table is created and written to within the same transaction. And add other zipfile tests.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 48f1c556994d7f8f359c649a1da81eec02306106b68946a9a20b276742c4610d
User & Date: dan 2018-02-01 19:41:23
Original Comment: Fix a problem triggered when a zipfile virtual table is created and written to within the same transaction. And add other zipfile test.
Context
2018-02-01
20:42
Add a few more zipfile tests. No changes to code. check-in: 3f621545 user: dan tags: trunk
19:41
Fix a problem triggered when a zipfile virtual table is created and written to within the same transaction. And add other zipfile tests. check-in: 48f1c556 user: dan tags: trunk
15:57
New assert() statements to help ensure that no other errors similar to [343634942dd54ab57b7] ever appear in the code. check-in: 5a70af1e user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/misc/zipfile.c.

  1069   1069           }
  1070   1070         }
  1071   1071         break;
  1072   1072       }
  1073   1073       case 6:   /* method */
  1074   1074         sqlite3_result_int(ctx, pCDS->iCompression);
  1075   1075         break;
  1076         -    case 7:   /* z */
         1076  +    default:  /* z */
         1077  +      assert( i==7 );
  1077   1078         sqlite3_result_int64(ctx, pCsr->iId);
  1078   1079         break;
  1079   1080     }
  1080   1081   
  1081   1082     return rc;
  1082   1083   }
  1083   1084   
................................................................................
  1213   1214   static int zipfileFilter(
  1214   1215     sqlite3_vtab_cursor *cur, 
  1215   1216     int idxNum, const char *idxStr,
  1216   1217     int argc, sqlite3_value **argv
  1217   1218   ){
  1218   1219     ZipfileTab *pTab = (ZipfileTab*)cur->pVtab;
  1219   1220     ZipfileCsr *pCsr = (ZipfileCsr*)cur;
  1220         -  const char *zFile;              /* Zip file to scan */
         1221  +  const char *zFile = 0;          /* Zip file to scan */
  1221   1222     int rc = SQLITE_OK;             /* Return Code */
  1222   1223     int bInMemory = 0;              /* True for an in-memory zipfile */
  1223   1224   
  1224   1225     zipfileResetCursor(pCsr);
  1225   1226   
  1226   1227     if( pTab->zFile ){
  1227   1228       zFile = pTab->zFile;
  1228   1229     }else if( idxNum==0 ){
  1229         -    bInMemory = 1;
         1230  +    zipfileSetErrmsg(pCsr, "zipfile() function requires an argument");
         1231  +    return SQLITE_ERROR;
  1230   1232     }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
  1231   1233       const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
  1232   1234       int nBlob = sqlite3_value_bytes(argv[0]);
  1233   1235       assert( pTab->pFirstEntry==0 );
  1234   1236       rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
  1235   1237       pCsr->pFreeEntry = pTab->pFirstEntry;
  1236   1238       pTab->pFirstEntry = pTab->pLastEntry = 0;
................................................................................
  1291   1293       pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
  1292   1294       pIdxInfo->idxNum = 0;
  1293   1295     }
  1294   1296   
  1295   1297     return SQLITE_OK;
  1296   1298   }
  1297   1299   
  1298         -static ZipfileEntry *zipfileNewEntry(const char *zPath, int nData){
         1300  +static ZipfileEntry *zipfileNewEntry(const char *zPath){
  1299   1301     ZipfileEntry *pNew;
  1300         -  pNew = sqlite3_malloc(sizeof(ZipfileEntry) + nData);
         1302  +  pNew = sqlite3_malloc(sizeof(ZipfileEntry));
  1301   1303     if( pNew ){
  1302   1304       memset(pNew, 0, sizeof(ZipfileEntry));
  1303         -    if( nData ){
  1304         -      pNew->aData = (u8*)&pNew[1];
  1305         -    }
  1306   1305       pNew->cds.zFile = sqlite3_mprintf("%s", zPath);
  1307   1306       if( pNew->cds.zFile==0 ){
  1308   1307         sqlite3_free(pNew);
  1309   1308         pNew = 0;
  1310   1309       }
  1311   1310     }
  1312   1311     return pNew;
................................................................................
  1354   1353     u8 *aBuf = pTab->aBuffer;
  1355   1354     int nBuf;
  1356   1355     int rc;
  1357   1356   
  1358   1357     nBuf = zipfileSerializeLFH(pEntry, aBuf);
  1359   1358     rc = zipfileAppendData(pTab, aBuf, nBuf);
  1360   1359     if( rc==SQLITE_OK ){
         1360  +    pEntry->iDataOff = pTab->szCurrent;
  1361   1361       rc = zipfileAppendData(pTab, pData, nData);
  1362   1362     }
  1363   1363   
  1364   1364     return rc;
  1365   1365   }
  1366   1366   
  1367   1367   static int zipfileGetMode(
................................................................................
  1413   1413   static int zipfileComparePath(const char *zA, const char *zB, int nB){
  1414   1414     int nA = (int)strlen(zA);
  1415   1415     if( zA[nA-1]=='/' ) nA--;
  1416   1416     if( zB[nB-1]=='/' ) nB--;
  1417   1417     if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
  1418   1418     return 1;
  1419   1419   }
         1420  +
         1421  +static int zipfileBegin(sqlite3_vtab *pVtab){
         1422  +  ZipfileTab *pTab = (ZipfileTab*)pVtab;
         1423  +  int rc = SQLITE_OK;
         1424  +
         1425  +  assert( pTab->pWriteFd==0 );
         1426  +
         1427  +  /* Open a write fd on the file. Also load the entire central directory
         1428  +  ** structure into memory. During the transaction any new file data is 
         1429  +  ** appended to the archive file, but the central directory is accumulated
         1430  +  ** in main-memory until the transaction is committed.  */
         1431  +  pTab->pWriteFd = fopen(pTab->zFile, "ab+");
         1432  +  if( pTab->pWriteFd==0 ){
         1433  +    pTab->base.zErrMsg = sqlite3_mprintf(
         1434  +        "zipfile: failed to open file %s for writing", pTab->zFile
         1435  +        );
         1436  +    rc = SQLITE_ERROR;
         1437  +  }else{
         1438  +    fseek(pTab->pWriteFd, 0, SEEK_END);
         1439  +    pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd);
         1440  +    rc = zipfileLoadDirectory(pTab, 0, 0);
         1441  +  }
         1442  +
         1443  +  if( rc!=SQLITE_OK ){
         1444  +    zipfileCleanupTransaction(pTab);
         1445  +  }
         1446  +
         1447  +  return rc;
         1448  +}
  1420   1449   
  1421   1450   /*
  1422   1451   ** xUpdate method.
  1423   1452   */
  1424   1453   static int zipfileUpdate(
  1425   1454     sqlite3_vtab *pVtab, 
  1426   1455     int nVal, 
................................................................................
  1441   1470     int iMethod = 0;                /* Compression method for new entry */
  1442   1471     u8 *pFree = 0;                  /* Free this */
  1443   1472     char *zFree = 0;                /* Also free this */
  1444   1473     ZipfileEntry *pOld = 0;
  1445   1474     int bIsDir = 0;
  1446   1475     u32 iCrc32 = 0;
  1447   1476   
  1448         -  assert( (pTab->zFile==0)==(pTab->pWriteFd==0) );
         1477  +  if( pTab->pWriteFd==0 ){
         1478  +    rc = zipfileBegin(pVtab);
         1479  +    if( rc!=SQLITE_OK ) return rc;
         1480  +  }
  1449   1481   
  1450   1482     /* If this is a DELETE or UPDATE, find the archive entry to delete. */
  1451   1483     if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
  1452   1484       const char *zDelete = (const char*)sqlite3_value_text(apVal[0]);
  1453   1485       int nDelete = (int)strlen(zDelete);
  1454   1486       for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){
  1455   1487         if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){
................................................................................
  1537   1569             break;
  1538   1570           }
  1539   1571         }
  1540   1572       }
  1541   1573   
  1542   1574       if( rc==SQLITE_OK ){
  1543   1575         /* Create the new CDS record. */
  1544         -      pNew = zipfileNewEntry(zPath, pTab->zFile ? 0 : (nData+1));
         1576  +      pNew = zipfileNewEntry(zPath);
  1545   1577         if( pNew==0 ){
  1546   1578           rc = SQLITE_NOMEM;
  1547   1579         }else{
  1548   1580           pNew->cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
  1549   1581           pNew->cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED;
  1550   1582           pNew->cds.flags = ZIPFILE_NEWENTRY_FLAGS;
  1551   1583           pNew->cds.iCompression = (u16)iMethod;
................................................................................
  1553   1585           pNew->cds.crc32 = iCrc32;
  1554   1586           pNew->cds.szCompressed = nData;
  1555   1587           pNew->cds.szUncompressed = (u32)sz;
  1556   1588           pNew->cds.iExternalAttr = (mode<<16);
  1557   1589           pNew->cds.iOffset = (u32)pTab->szCurrent;
  1558   1590           pNew->cds.nFile = nPath;
  1559   1591           pNew->mUnixTime = (u32)mTime;
  1560         -        if( pTab->zFile ){
  1561         -          rc = zipfileAppendEntry(pTab, pNew, pData, nData);
  1562         -        }else{
  1563         -          memcpy(pNew->aData, pData, nData);
  1564         -        }
         1592  +        rc = zipfileAppendEntry(pTab, pNew, pData, nData);
  1565   1593           zipfileAddEntry(pTab, pOld, pNew);
  1566   1594         }
  1567   1595       }
  1568   1596     }
  1569   1597   
  1570   1598     if( rc==SQLITE_OK && pOld ){
  1571   1599       ZipfileEntry **pp;
................................................................................
  1602   1630   
  1603   1631   static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){
  1604   1632     int nBuf = zipfileSerializeEOCD(p, pTab->aBuffer);
  1605   1633     assert( nBuf==ZIPFILE_EOCD_FIXED_SZ );
  1606   1634     return zipfileAppendData(pTab, pTab->aBuffer, nBuf);
  1607   1635   }
  1608   1636   
  1609         -static int zipfileBegin(sqlite3_vtab *pVtab){
  1610         -  ZipfileTab *pTab = (ZipfileTab*)pVtab;
  1611         -  int rc = SQLITE_OK;
  1612         -
  1613         -  assert( pTab->pWriteFd==0 );
  1614         -  if( pTab->zFile ){
  1615         -    /* Open a write fd on the file. Also load the entire central directory
  1616         -    ** structure into memory. During the transaction any new file data is 
  1617         -    ** appended to the archive file, but the central directory is accumulated
  1618         -    ** in main-memory until the transaction is committed.  */
  1619         -    pTab->pWriteFd = fopen(pTab->zFile, "ab+");
  1620         -    if( pTab->pWriteFd==0 ){
  1621         -      pTab->base.zErrMsg = sqlite3_mprintf(
  1622         -          "zipfile: failed to open file %s for writing", pTab->zFile
  1623         -      );
  1624         -      rc = SQLITE_ERROR;
  1625         -    }else{
  1626         -      fseek(pTab->pWriteFd, 0, SEEK_END);
  1627         -      pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd);
  1628         -      rc = zipfileLoadDirectory(pTab, 0, 0);
  1629         -    }
  1630         -
  1631         -    if( rc!=SQLITE_OK ){
  1632         -      zipfileCleanupTransaction(pTab);
  1633         -    }
  1634         -  }
  1635         -
  1636         -  return rc;
  1637         -}
  1638         -
  1639   1637   /*
  1640   1638   ** Serialize the CDS structure into buffer aBuf[]. Return the number
  1641   1639   ** of bytes written.
  1642   1640   */
  1643   1641   static int zipfileSerializeCDS(ZipfileEntry *pEntry, u8 *aBuf){
  1644   1642     u8 *a = aBuf;
  1645   1643     ZipfileCDS *pCDS = &pEntry->cds;
................................................................................
  1781   1779   static int zipfileFindFunction(
  1782   1780     sqlite3_vtab *pVtab,            /* Virtual table handle */
  1783   1781     int nArg,                       /* Number of SQL function arguments */
  1784   1782     const char *zName,              /* Name of SQL function */
  1785   1783     void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
  1786   1784     void **ppArg                    /* OUT: User data for *pxFunc */
  1787   1785   ){
  1788         -  if( nArg>0 ){
  1789         -    if( sqlite3_stricmp("zipfile_cds", zName)==0 ){
  1790         -      *pxFunc = zipfileFunctionCds;
  1791         -      *ppArg = (void*)pVtab;
  1792         -      return 1;
  1793         -    }
         1786  +  if( sqlite3_stricmp("zipfile_cds", zName)==0 ){
         1787  +    *pxFunc = zipfileFunctionCds;
         1788  +    *ppArg = (void*)pVtab;
         1789  +    return 1;
  1794   1790     }
  1795         -
  1796   1791     return 0;
  1797   1792   }
  1798   1793   
  1799   1794   typedef struct ZipfileBuffer ZipfileBuffer;
  1800   1795   struct ZipfileBuffer {
  1801   1796     u8 *a;                          /* Pointer to buffer */
  1802   1797     int n;                          /* Size of buffer in bytes */

Changes to test/zipfile.test.

   147    147     6 method {} 0 {} 0
   148    148   }
   149    149   
   150    150   do_catchsql_test 1.1.0.1 {
   151    151     INSERT INTO zz(name, mode, mtime, sz, rawdata, method) 
   152    152     VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
   153    153   } {1 {constraint failed}}
   154         -do_catchsql_test 1.1.0.1 {
   155         -  INSERT INTO zz(name, mtime, sz, rawdata, method) 
          154  +do_catchsql_test 1.1.0.2 {
          155  +  INSERT INTO zz(name, mtime, sz, data, method) 
   156    156     VALUES('g.txt', 1000000002, 5, '12345', 0);
   157    157   } {1 {constraint failed}}
          158  +do_catchsql_test 1.1.0.3 {
          159  +  INSERT INTO zz(name, mtime, rawdata, method) 
          160  +  VALUES('g.txt', 1000000002, '12345', 0);
          161  +} {1 {constraint failed}}
          162  +do_catchsql_test 1.1.0.4 {
          163  +  INSERT INTO zz(name, data, method) 
          164  +  VALUES('g.txt', '12345', 7);
          165  +} {1 {constraint failed}}
   158    166   
   159    167   do_execsql_test 1.1.1 {
   160    168     INSERT INTO zz(name, mode, mtime, data, method) 
   161    169     VALUES('f.txt', '-rw-r--r--', 1000000000, 'abcde', 0);
   162    170   }
   163    171   do_execsql_test 1.1.2 {
   164    172     INSERT INTO zz(name, mode, mtime, data, method) 
................................................................................
   194    202       FROM zipfile('test.zip');
   195    203     } {
   196    204       f.txt 1
   197    205       g.txt 1
   198    206       h.txt 1
   199    207     }
   200    208   }
          209  +do_catchsql_test 1.4.2 {
          210  +  SELECT zipfile_cds(mode) FROM zipfile('test.zip');
          211  +} {0 {{} {} {}}}
   201    212   
   202    213   do_execsql_test 1.5.1 {
   203    214     BEGIN;
   204    215       INSERT INTO zz(name, mode, mtime, data, method)
   205    216       VALUES('i.txt', '-rw-r--r--', 1000000006, 'zxcvb', 0);
   206    217       SELECT name FROM zz;
   207    218     COMMIT;
................................................................................
   280    291   do_execsql_test 1.6.8 {
   281    292     SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
   282    293   } {
   283    294     blue.txt/ 16877 1000000000 {} 0
   284    295     h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
   285    296     i.txt 33188 4 zxcvb 0
   286    297   }
          298  +
          299  +do_execsql_test 1.6.8 {
          300  +  UPDATE zz SET data = '' WHERE name='i.txt';
          301  +  SELECT name,mode,mtime,data,method from zipfile('test.zip');
          302  +} {
          303  +  blue.txt/ 16877 1000000000 {} 0
          304  +  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
          305  +  i.txt 33188 4 {} 0
          306  +}
          307  +
          308  +do_execsql_test 1.6.9 {
          309  +  SELECT a.name, a.data 
          310  +  FROM zz AS a, zz AS b 
          311  +  WHERE a.name=+b.name AND +a.mode=b.mode
          312  +} {
          313  +  blue.txt/ {}
          314  +  h.txt aaaaaaaaaabbbbbbbbbb
          315  +  i.txt {}
          316  +}
          317  +
          318  +do_execsql_test 1.6.10 {
          319  +  SELECT name, data FROM zz WHERE name LIKE '%txt'
          320  +} {
          321  +  h.txt aaaaaaaaaabbbbbbbbbb
          322  +  i.txt {}
          323  +}
          324  +
          325  +do_execsql_test 1.7 {
          326  +  DELETE FROM zz;
          327  +  SELECT * FROM zz;
          328  +} {}
   287    329   
   288    330   #-------------------------------------------------------------------------
   289    331   db close
   290    332   forcedelete test.zip
   291    333   reset_db
   292    334   load_static_extension db fileio
   293    335   load_static_extension db zipfile
................................................................................
   374    416   #
   375    417   do_catchsql_test 4.1 {
   376    418     CREATE VIRTUAL TABLE yyy USING zipfile();
   377    419   } {1 {zipfile constructor requires one argument}}
   378    420   do_catchsql_test 4.2 {
   379    421     CREATE VIRTUAL TABLE yyy USING zipfile('test.zip', 'test.zip');
   380    422   } {1 {zipfile constructor requires one argument}}
          423  +
          424  +do_catchsql_test 4.3 {
          425  +  SELECT * FROM zipfile()
          426  +} {1 {zipfile() function requires an argument}}
          427  +
          428  +do_catchsql_test 4.4 {
          429  +  SELECT * FROM zipfile('/path/that/does/not/exist')
          430  +} {1 {cannot open file: /path/that/does/not/exist}}
          431  +
          432  +foreach {tn mode} {
          433  +  1 abcd
          434  +  2 brwxrwxrwx
          435  +  3 lrwxrrxrwx
          436  +} {
          437  +  do_catchsql_test 4.5.$tn {
          438  +    WITH m(m) AS ( SELECT $mode)
          439  +    SELECT zipfile('a.txt', m, 1000, 'xyz') FROM m
          440  +  } [list 1 "zipfile: parse error in mode: $mode"]
          441  +}
   381    442   
   382    443   #--------------------------------------------------------------------------
   383    444   
   384    445   db func rt remove_timestamps
   385    446   do_execsql_test 5.0 {
   386    447     WITH c(name,mtime,data) AS (
   387    448       SELECT 'a.txt', 946684800, 'abc'
................................................................................
   444    505     } [list {*}{
   445    506       test_unzip/a.txt 946684800
   446    507       test_unzip/b.txt 1000000000 
   447    508       test_unzip/c.txt 1111111000 
   448    509     }]
   449    510   
   450    511     do_execsql_test 6.3 {
   451         -    SELECT name, mtime, data FROM zipfile('test2.zip')
          512  +    SELECT name, mtime, sz, rawdata, data FROM zipfile('test2.zip')
   452    513     } {
   453         -    a.txt 946684800   abc
   454         -    b.txt 1000000000  abc
   455         -    c.txt 1111111000  abc
          514  +    a.txt 946684800   3 abc abc
          515  +    b.txt 1000000000  3 abc abc
          516  +    c.txt 1111111000  3 abc abc
   456    517     }
   457    518   }
   458    519   }
   459    520   
   460    521   #-------------------------------------------------------------------------
          522  +# Force an IO error by truncating the zip archive to zero bytes in size
          523  +# while it is being read.
   461    524   forcedelete test.zip
   462    525   do_test 7.0 {
   463    526     execsql {
   464    527       WITH c(name,data) AS (
   465    528           SELECT '1', randomblob(1000000) UNION ALL
   466    529           SELECT '2', randomblob(1000000) UNION ALL
   467    530           SELECT '3', randomblob(1000000) 
................................................................................
   472    535     list [catch {
   473    536       db eval { SELECT name, data FROM zipfile('test.zip') } {
   474    537         if {$name==2} { close [open test.zip w+] }
   475    538       }
   476    539     } msg] $msg
   477    540   } {1 {error in fread()}}
   478    541   
          542  +forcedelete test.zip
          543  +do_execsql_test 8.0.1 {
          544  +  CREATE VIRTUAL TABLE zz USING zipfile('test.zip');
          545  +  BEGIN;
          546  +    INSERT INTO zz(name, data) VALUES('a.txt', '1');
          547  +    INSERT INTO zz(name, data) VALUES('b.txt', '2');
          548  +    INSERT INTO zz(name, data) VALUES('c.txt', '1');
          549  +    INSERT INTO zz(name, data) VALUES('d.txt', '2');
          550  +    SELECT name, data FROM zz;
          551  +} {
          552  +  a.txt 1 b.txt 2 c.txt 1 d.txt 2
          553  +}
          554  +do_test 8.0.2 {
          555  +  db eval { SELECT name, data FROM zz } {
          556  +    if { $data=="2" } { db eval { DELETE FROM zz WHERE name=$name } }
          557  +  }
          558  +  execsql { SELECT name, data FROM zz } 
          559  +} {a.txt 1 c.txt 1}
          560  +do_test 8.0.3 {
          561  +  db eval { SELECT name, data FROM zz } {
          562  +    db eval { DELETE FROM zz WHERE name=$name }
          563  +  }
          564  +  execsql { SELECT name, data FROM zz } 
          565  +} {}
          566  +execsql COMMIT
          567  +
          568  +do_execsql_test 8.1.1 {
          569  +  CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip');
          570  +}
          571  +do_catchsql_test 8.1.2 {
          572  +  INSERT INTO nogood(name, data) VALUES('abc', 'def');
          573  +} {1 {zipfile: failed to open file test_unzip for writing}}
          574  +
          575  +do_execsql_test 8.2.1 {
          576  +  DROP TABLE nogood;
          577  +  BEGIN;
          578  +    CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip');
          579  +}
          580  +do_catchsql_test 8.2.2 {
          581  +    INSERT INTO nogood(name, data) VALUES('abc', 'def');
          582  +} {1 {zipfile: failed to open file test_unzip for writing}}
          583  +do_execsql_test 8.2.3 {
          584  +  COMMIT;
          585  +}
          586  +
          587  +forcedelete test.zip
          588  +do_execsql_test 8.3.1 {
          589  +  BEGIN;
          590  +    CREATE VIRTUAL TABLE ok USING zipfile('test.zip');
          591  +    INSERT INTO ok(name, data) VALUES ('sqlite3', 'elf');
          592  +  COMMIT;
          593  +}
   479    594   
   480    595   finish_test
   481    596   

Changes to test/zipfile2.test.

   160    160   set a $archive2
   161    161   foreach i $L { set a [string replace $a $i [expr $i+7] 16000000] }
   162    162   set blob [blob $a]
   163    163   do_catchsql_test 4.1 {
   164    164     SELECT name,mtime,data,method FROM zipfile($blob)
   165    165   } {1 {inflate() failed (0)}}
   166    166   
          167  +# Check the response to an unknown compression method (set data to NULL).
          168  +set blob [blob [string map {0800 0900} $archive2]]
          169  +do_execsql_test 4.2 {
          170  +  SELECT name,mtime,data IS NULL,method FROM zipfile($blob)
          171  +} {a.txt 1000000 1 9}
          172  +
          173  +# Corrupt the EOCDS signature bytes in various ways.
          174  +foreach {tn sub} {
          175  +  1 {504B0500}
          176  +  2 {504B0006}
          177  +  3 {50000506}
          178  +  4 {004B0506}
          179  +} {
          180  +  set blob [blob [string map [list 504B0506 $sub] $archive2]]
          181  +  do_catchsql_test 4.3.$tn {
          182  +    SELECT * FROM zipfile($blob)
          183  +  } {1 {cannot find end of central directory record}}
          184  +}
          185  +
          186  +#-------------------------------------------------------------------------
          187  +# Test that a zero-length file with a '/' at the end is treated as
          188  +# a directory (data IS NULL). Even if the mode doesn't indicate
          189  +# that it is a directory.
          190  +
          191  +do_test 5.0 {
          192  +  set blob [db one {
          193  +    WITH c(n, d) AS (
          194  +      SELECT 'notadir', ''
          195  +    )
          196  +    SELECT zipfile(n, d) FROM c
          197  + }]
          198  +
          199  +  set hex [binary encode hex $blob]
          200  +  set hex [string map {6e6f7461646972 6e6f746164692f} $hex] 
          201  +  set blob2 [binary decode hex $hex]
          202  +
          203  +  execsql { SELECT name, data IS NULL FROM zipfile($blob2) }
          204  +} {notadi/ 1}
   167    205   
   168    206   
   169    207   finish_test
   170    208   

Changes to test/zipfilefault.test.

    38     38   sqlite3 db test.db
    39     39   load_static_extension db zipfile
    40     40   do_execsql_test 2.0 {
    41     41     CREATE VIRTUAL TABLE setup USING zipfile('test.zip');
    42     42     INSERT INTO setup(name, data) VALUES('a.txt', '1234567890');
    43     43   }
    44     44   
    45         -do_faultsim_test 2 -faults oom* -body {
           45  +do_faultsim_test 2.1 -faults oom* -body {
    46     46     execsql { SELECT name,data FROM zipfile('test.zip') }
    47     47   } -test {
    48     48     faultsim_test_result {0 {a.txt 1234567890}} 
           49  +}
           50  +do_faultsim_test 2.2 -faults oom* -body {
           51  +  execsql { 
           52  +    SELECT json_extract( zipfile_cds(z), '$.version-made-by' ) 
           53  +    FROM zipfile('test.zip')
           54  +  }
           55  +} -test {
           56  +  faultsim_test_result {0 798}
    49     57   }
    50     58   
    51     59   forcedelete test.zip
    52     60   reset_db
    53     61   load_static_extension db zipfile
    54     62   do_execsql_test 3.0 {
    55     63     CREATE VIRTUAL TABLE setup USING zipfile('test.zip');
................................................................................
    70     78       SELECT name, data FROM zipfile(
    71     79         (SELECT zipfile(n, d) FROM c)
    72     80       );
    73     81     }
    74     82   } -test {
    75     83     faultsim_test_result {0 {1 aaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbb}}
    76     84   }
           85  +
           86  +reset_db
           87  +load_static_extension db zipfile
           88  +
           89  +do_execsql_test 5.0 {
           90  +  CREATE VIRTUAL TABLE setup USING zipfile('test.zip') 
           91  +}
           92  +
           93  +do_faultsim_test 5.1 -faults oom* -prep {
           94  +  forcedelete test.zip
           95  +} -body {
           96  +  execsql {
           97  +    INSERT INTO setup(name, data) 
           98  +    VALUES('a.txt', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa');
           99  +  }
          100  +} -test {
          101  +  faultsim_test_result {0 {}}
          102  +}
          103  +
          104  +do_faultsim_test 5.2 -faults oom* -prep {
          105  +  forcedelete test.zip
          106  +} -body {
          107  +  execsql {
          108  +    INSERT INTO setup(name, data) VALUES('dir', NULL)
          109  +  }
          110  +} -test {
          111  +  faultsim_test_result {0 {}}
          112  +}
          113  +
          114  +do_faultsim_test 5.3 -faults oom* -prep {
          115  +  forcedelete test.zip
          116  +  execsql { 
          117  +    DROP TABLE IF EXISTS setup;
          118  +    BEGIN;
          119  +      CREATE VIRTUAL TABLE setup USING zipfile('test.zip') 
          120  +  }
          121  +} -body {
          122  +  execsql {
          123  +    INSERT INTO setup(name, data) VALUES('dir', NULL)
          124  +  }
          125  +} -test {
          126  +  catchsql { COMMIT }
          127  +  faultsim_test_result {0 {}}
          128  +}
    77    129   
    78    130   
    79    131   finish_test
    80    132