/ Check-in [a4730586]
Login

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

Overview
Comment:Add test logic and some test cases.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | quota-stdio
Files: files | file ages | folders
SHA1: a4730586cc1f686ead956ccd1cc218b5931942c9
User & Date: drh 2011-12-01 20:48:15
Context
2011-12-01
22:07
Progress toward getting things to work better on windows. check-in: 253dd707 user: drh tags: quota-stdio
20:48
Add test logic and some test cases. check-in: a4730586 user: drh tags: quota-stdio
18:44
Add stdio-like I/O interfaces to the test_quota VFS. This is a prototype change for discussion and is mostly untested. This is an alternative to adding stdio-like I/O interfaces in the core. There is no guarantee that this code will make it into the trunk. If it does get to trunk, there could be many changes to the interface first. check-in: bd3ce723 user: drh tags: quota-stdio
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/test_quota.c.

   233    233   **      '?'       Matches exactly one character.
   234    234   **
   235    235   **     [...]      Matches one character from the enclosed list of
   236    236   **                characters.
   237    237   **
   238    238   **     [^...]     Matches one character not in the enclosed list.
   239    239   **
          240  +**     /          Matches "/" or "\\"
          241  +**
   240    242   */
   241    243   static int quotaStrglob(const char *zGlob, const char *z){
   242    244     int c, c2;
   243    245     int invert;
   244    246     int seen;
   245    247   
   246    248     while( (c = (*(zGlob++)))!=0 ){
................................................................................
   291    293               seen = 1;
   292    294             }
   293    295             prior_c = c2;
   294    296           }
   295    297           c2 = *(zGlob++);
   296    298         }
   297    299         if( c2==0 || (seen ^ invert)==0 ) return 0;
          300  +    }else if( c=='/' ){
          301  +      if( z[0]!='/' && z[0]!='\\' ) return 0;
          302  +      z++;
   298    303       }else{
   299    304         if( c!=(*(z++)) ) return 0;
   300    305       }
   301    306     }
   302    307     return *z==0;
   303    308   }
   304    309   
................................................................................
   346    351         pFile->ppPrev = &pGroup->pFiles;
   347    352         pGroup->pFiles = pFile;
   348    353         pFile->pGroup = pGroup;
   349    354       }
   350    355     }
   351    356     return pFile;
   352    357   }
          358  +
          359  +/*
          360  +** Figure out if we are dealing with Unix, Windows, or some other
          361  +** operating system.  After the following block of preprocess macros,
          362  +** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, SQLITE_OS_OS2, and SQLITE_OS_OTHER 
          363  +** will defined to either 1 or 0.  One of the four will be 1.  The other 
          364  +** three will be 0.
          365  +*/
          366  +#if defined(SQLITE_OS_OTHER)
          367  +# if SQLITE_OS_OTHER==1
          368  +#   undef SQLITE_OS_UNIX
          369  +#   define SQLITE_OS_UNIX 0
          370  +#   undef SQLITE_OS_WIN
          371  +#   define SQLITE_OS_WIN 0
          372  +#   undef SQLITE_OS_OS2
          373  +#   define SQLITE_OS_OS2 0
          374  +# else
          375  +#   undef SQLITE_OS_OTHER
          376  +# endif
          377  +#endif
          378  +#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
          379  +# define SQLITE_OS_OTHER 0
          380  +# ifndef SQLITE_OS_WIN
          381  +#   if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) \
          382  +                       || defined(__MINGW32__) || defined(__BORLANDC__)
          383  +#     define SQLITE_OS_WIN 1
          384  +#     define SQLITE_OS_UNIX 0
          385  +#     define SQLITE_OS_OS2 0
          386  +#   elif defined(__EMX__) || defined(_OS2) || defined(OS2) \
          387  +                          || defined(_OS2_) || defined(__OS2__)
          388  +#     define SQLITE_OS_WIN 0
          389  +#     define SQLITE_OS_UNIX 0
          390  +#     define SQLITE_OS_OS2 1
          391  +#   else
          392  +#     define SQLITE_OS_WIN 0
          393  +#     define SQLITE_OS_UNIX 1
          394  +#     define SQLITE_OS_OS2 0
          395  +#  endif
          396  +# else
          397  +#  define SQLITE_OS_UNIX 0
          398  +#  define SQLITE_OS_OS2 0
          399  +# endif
          400  +#else
          401  +# ifndef SQLITE_OS_WIN
          402  +#  define SQLITE_OS_WIN 0
          403  +# endif
          404  +#endif
          405  +
          406  +
          407  +/*
          408  +** Translate UTF8 to MBCS for use in fopen() calls.  Return a pointer to the
          409  +** translated text..  Call quota_mbcs_free() to deallocate any memory
          410  +** used to store the returned pointer when done.
          411  +*/
          412  +static char *quota_utf8_to_mbcs(const char *zUtf8){
          413  +#if SQLITE_OS_WIN
          414  +  extern char *sqlite3_win32_utf8_to_mbcs(const char*);
          415  +  return sqlite3_win32_utf8_to_mbcs(zUtf8);
          416  +#else
          417  +  return (char*)zUtf8;  /* No-op on unix */
          418  +#endif  
          419  +}
          420  +
          421  +/*
          422  +** Deallocate any memory allocated by quota_utf8_to_mbcs().
          423  +*/
          424  +static void quota_mbcs_free(char *zOld){
          425  +#if SQLITE_OS_WIN
          426  +  free(zOld);
          427  +#else
          428  +  /* No-op on unix */
          429  +#endif  
          430  +}
   353    431   
   354    432   /************************* VFS Method Wrappers *****************************/
   355    433   /*
   356    434   ** This is the xOpen method used for the "quota" VFS.
   357    435   **
   358    436   ** Most of the work is done by the underlying original VFS.  This method
   359    437   ** simply links the new file into the appropriate quota group if it is a
................................................................................
   852    930   
   853    931   /*
   854    932   ** Open a potentially quotaed file for I/O.
   855    933   */
   856    934   quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
   857    935     quota_FILE *p = 0;
   858    936     char *zFull = 0;
          937  +  char *zFullTranslated;
   859    938     int rc;
   860    939     quotaGroup *pGroup;
   861    940     quotaFile *pFile;
   862    941   
   863         -  p = sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1);
   864         -  if( p==0 ) return 0;
   865         -  zFull = (char*)&p[1];
          942  +  zFull = sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1);
          943  +  if( zFull==0 ) return 0;
   866    944     rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename,
   867    945                                         gQuota.sThisVfs.mxPathname+1, zFull);
   868    946     if( rc ) goto quota_fopen_error;
   869    947     p = sqlite3_malloc(sizeof(*p));
   870    948     if( p==0 ) goto quota_fopen_error;
   871    949     memset(p, 0, sizeof(*p));
   872         -  p->f = fopen(zFull, zMode);
          950  +  zFullTranslated = quota_utf8_to_mbcs(zFull);
          951  +  if( zFullTranslated==0 ) goto quota_fopen_error;
          952  +  p->f = fopen(zFullTranslated, zMode);
          953  +  quota_mbcs_free(zFullTranslated);
   873    954     if( p->f==0 ) goto quota_fopen_error;
   874    955     quotaEnter();
   875    956     pGroup = quotaGroupFind(zFull);
   876    957     if( pGroup ){
   877    958       pFile = quotaFindFile(pGroup, zFull, 1);
   878    959       if( pFile==0 ){
   879    960         quotaLeave();
................................................................................
  1237   1318       }
  1238   1319       Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
  1239   1320     }
  1240   1321     quotaLeave();
  1241   1322     Tcl_SetObjResult(interp, pResult);
  1242   1323     return TCL_OK;
  1243   1324   }
         1325  +
         1326  +/*
         1327  +** tclcmd: sqlite3_quota_fopen FILENAME MODE
         1328  +*/
         1329  +static int test_quota_fopen(
         1330  +  void * clientData,
         1331  +  Tcl_Interp *interp,
         1332  +  int objc,
         1333  +  Tcl_Obj *CONST objv[]
         1334  +){
         1335  +  const char *zFilename;          /* File pattern to configure */
         1336  +  const char *zMode;              /* Mode string */
         1337  +  quota_FILE *p;                  /* Open string object */
         1338  +  char zReturn[50];               /* Name of pointer to return */
         1339  +
         1340  +  /* Process arguments */
         1341  +  if( objc!=3 ){
         1342  +    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME MODE");
         1343  +    return TCL_ERROR;
         1344  +  }
         1345  +  zFilename = Tcl_GetString(objv[1]);
         1346  +  zMode = Tcl_GetString(objv[2]);
         1347  +  p = sqlite3_quota_fopen(zFilename, zMode);
         1348  +  sqlite3_snprintf(sizeof(zReturn), zReturn, "%p", p);
         1349  +  Tcl_SetResult(interp, zReturn, TCL_VOLATILE);
         1350  +  return TCL_OK;
         1351  +}
         1352  +
         1353  +/* Defined in test1.c */
         1354  +extern void *sqlite3TestTextToPtr(const char*);
         1355  +
         1356  +/*
         1357  +** tclcmd: sqlite3_quota_fread HANDLE SIZE NELEM
         1358  +*/
         1359  +static int test_quota_fread(
         1360  +  void * clientData,
         1361  +  Tcl_Interp *interp,
         1362  +  int objc,
         1363  +  Tcl_Obj *CONST objv[]
         1364  +){
         1365  +  quota_FILE *p;
         1366  +  char *zBuf;
         1367  +  int sz;
         1368  +  int nElem;
         1369  +  int got;
         1370  +
         1371  +  if( objc!=4 ){
         1372  +    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE NELEM");
         1373  +    return TCL_ERROR;
         1374  +  }
         1375  +  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         1376  +  if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR;
         1377  +  if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR;
         1378  +  zBuf = sqlite3_malloc( sz*nElem + 1 );
         1379  +  if( zBuf==0 ){
         1380  +    Tcl_SetResult(interp, "out of memory", TCL_STATIC);
         1381  +    return TCL_ERROR;
         1382  +  }
         1383  +  got = sqlite3_quota_fread(zBuf, sz, nElem, p);
         1384  +  if( got<0 ) got = 0;
         1385  +  zBuf[got*sz] = 0;
         1386  +  Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
         1387  +  sqlite3_free(zBuf);
         1388  +  return TCL_OK;
         1389  +}
         1390  +
         1391  +/*
         1392  +** tclcmd: sqlite3_quota_fwrite HANDLE SIZE NELEM CONTENT
         1393  +*/
         1394  +static int test_quota_fwrite(
         1395  +  void * clientData,
         1396  +  Tcl_Interp *interp,
         1397  +  int objc,
         1398  +  Tcl_Obj *CONST objv[]
         1399  +){
         1400  +  quota_FILE *p;
         1401  +  char *zBuf;
         1402  +  int sz;
         1403  +  int nElem;
         1404  +  int got;
         1405  +
         1406  +  if( objc!=5 ){
         1407  +    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE NELEM CONTENT");
         1408  +    return TCL_ERROR;
         1409  +  }
         1410  +  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         1411  +  if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR;
         1412  +  if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR;
         1413  +  zBuf = Tcl_GetString(objv[4]);
         1414  +  got = sqlite3_quota_fwrite(zBuf, sz, nElem, p);
         1415  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(got));
         1416  +  return TCL_OK;
         1417  +}
         1418  +
         1419  +/*
         1420  +** tclcmd: sqlite3_quota_fclose HANDLE
         1421  +*/
         1422  +static int test_quota_fclose(
         1423  +  void * clientData,
         1424  +  Tcl_Interp *interp,
         1425  +  int objc,
         1426  +  Tcl_Obj *CONST objv[]
         1427  +){
         1428  +  quota_FILE *p;
         1429  +  int rc;
         1430  +
         1431  +  if( objc!=2 ){
         1432  +    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
         1433  +    return TCL_ERROR;
         1434  +  }
         1435  +  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         1436  +  rc = sqlite3_quota_fclose(p);
         1437  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
         1438  +  return TCL_OK;
         1439  +}
         1440  +
         1441  +/*
         1442  +** tclcmd: sqlite3_quota_fseek HANDLE OFFSET WHENCE
         1443  +*/
         1444  +static int test_quota_fseek(
         1445  +  void * clientData,
         1446  +  Tcl_Interp *interp,
         1447  +  int objc,
         1448  +  Tcl_Obj *CONST objv[]
         1449  +){
         1450  +  quota_FILE *p;
         1451  +  int ofst;
         1452  +  const char *zWhence;
         1453  +  int whence;
         1454  +  int rc;
         1455  +
         1456  +  if( objc!=4 ){
         1457  +    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET WHENCE");
         1458  +    return TCL_ERROR;
         1459  +  }
         1460  +  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         1461  +  if( Tcl_GetIntFromObj(interp, objv[2], &ofst) ) return TCL_ERROR;
         1462  +  zWhence = Tcl_GetString(objv[3]);
         1463  +  if( strcmp(zWhence, "SEEK_SET")==0 ){
         1464  +    whence = SEEK_SET;
         1465  +  }else if( strcmp(zWhence, "SEEK_CUR")==0 ){
         1466  +    whence = SEEK_CUR;
         1467  +  }else if( strcmp(zWhence, "SEEK_END")==0 ){
         1468  +    whence = SEEK_END;
         1469  +  }else{
         1470  +    Tcl_AppendResult(interp,
         1471  +           "WHENCE should be SEEK_SET, SEEK_CUR, or SEEK_END", (char*)0);
         1472  +    return TCL_ERROR;
         1473  +  }
         1474  +  rc = sqlite3_quota_fseek(p, ofst, whence);
         1475  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
         1476  +  return TCL_OK;
         1477  +}
         1478  +
         1479  +/*
         1480  +** tclcmd: sqlite3_quota_rewind HANDLE
         1481  +*/
         1482  +static int test_quota_rewind(
         1483  +  void * clientData,
         1484  +  Tcl_Interp *interp,
         1485  +  int objc,
         1486  +  Tcl_Obj *CONST objv[]
         1487  +){
         1488  +  quota_FILE *p;
         1489  +  if( objc!=2 ){
         1490  +    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
         1491  +    return TCL_ERROR;
         1492  +  }
         1493  +  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         1494  +  sqlite3_quota_rewind(p);
         1495  +  return TCL_OK;
         1496  +}
         1497  +
         1498  +/*
         1499  +** tclcmd: sqlite3_quota_ftell HANDLE
         1500  +*/
         1501  +static int test_quota_ftell(
         1502  +  void * clientData,
         1503  +  Tcl_Interp *interp,
         1504  +  int objc,
         1505  +  Tcl_Obj *CONST objv[]
         1506  +){
         1507  +  quota_FILE *p;
         1508  +  sqlite3_int64 x;
         1509  +  if( objc!=2 ){
         1510  +    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
         1511  +    return TCL_ERROR;
         1512  +  }
         1513  +  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         1514  +  x = sqlite3_quota_ftell(p);
         1515  +  Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x));
         1516  +  return TCL_OK;
         1517  +}
         1518  +
         1519  +/*
         1520  +** tclcmd: sqlite3_quota_remove FILENAME
         1521  +*/
         1522  +static int test_quota_remove(
         1523  +  void * clientData,
         1524  +  Tcl_Interp *interp,
         1525  +  int objc,
         1526  +  Tcl_Obj *CONST objv[]
         1527  +){
         1528  +  const char *zFilename;          /* File pattern to configure */
         1529  +  int rc;
         1530  +  if( objc!=2 ){
         1531  +    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
         1532  +    return TCL_ERROR;
         1533  +  }
         1534  +  zFilename = Tcl_GetString(objv[1]);
         1535  +  rc = sqlite3_quota_remove(zFilename);
         1536  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
         1537  +  return TCL_OK;
         1538  +}
  1244   1539   
  1245   1540   /*
  1246   1541   ** This routine registers the custom TCL commands defined in this
  1247   1542   ** module.  This should be the only procedure visible from outside
  1248   1543   ** of this module.
  1249   1544   */
  1250   1545   int Sqlitequota_Init(Tcl_Interp *interp){
  1251   1546     static struct {
  1252   1547        char *zName;
  1253   1548        Tcl_ObjCmdProc *xProc;
  1254   1549     } aCmd[] = {
  1255   1550       { "sqlite3_quota_initialize", test_quota_initialize },
  1256         -    { "sqlite3_quota_shutdown", test_quota_shutdown },
  1257         -    { "sqlite3_quota_set", test_quota_set },
  1258         -    { "sqlite3_quota_file", test_quota_file },
  1259         -    { "sqlite3_quota_dump", test_quota_dump },
         1551  +    { "sqlite3_quota_shutdown",   test_quota_shutdown },
         1552  +    { "sqlite3_quota_set",        test_quota_set },
         1553  +    { "sqlite3_quota_file",       test_quota_file },
         1554  +    { "sqlite3_quota_dump",       test_quota_dump },
         1555  +    { "sqlite3_quota_fopen",      test_quota_fopen },
         1556  +    { "sqlite3_quota_fread",      test_quota_fread },
         1557  +    { "sqlite3_quota_fwrite",     test_quota_fwrite },
         1558  +    { "sqlite3_quota_fclose",     test_quota_fclose },
         1559  +    { "sqlite3_quota_fseek",      test_quota_fseek },
         1560  +    { "sqlite3_quota_rewind",     test_quota_rewind },
         1561  +    { "sqlite3_quota_ftell",      test_quota_ftell },
         1562  +    { "sqlite3_quota_remove",     test_quota_remove },
  1260   1563     };
  1261   1564     int i;
  1262   1565   
  1263   1566     for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
  1264   1567       Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  1265   1568     }
  1266   1569   
  1267   1570     return TCL_OK;
  1268   1571   }
  1269   1572   #endif

Changes to test/quota.test.

    44     44   #   quota-2.4.*: Try to shutdown the quota system before closing the db
    45     45   #                file. Check that this fails and the quota system still works
    46     46   #                afterwards. Then close the database and successfully shut
    47     47   #                down the quota system.
    48     48   #   
    49     49   sqlite3_quota_initialize "" 1
    50     50   
           51  +unset -nocomplain quota_request_ok
    51     52   proc quota_check {filename limitvar size} {
    52     53     upvar $limitvar limit
    53     54   
    54     55     lappend ::quota [set limit] $size
    55     56     if {[info exists ::quota_request_ok]} { set limit $size }
    56     57   }
    57     58   

Added test/quota2.test.

            1  +# 2011 December 1
            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  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +source $testdir/malloc_common.tcl
           16  +
           17  +db close
           18  +sqlite3_quota_initialize "" 1
           19  +
           20  +file delete -force quota2a
           21  +file delete -force quota2b
           22  +file mkdir quota2a
           23  +file mkdir quota2b
           24  +
           25  +# The quota_check procedure is a callback from the quota handler.
           26  +# It has three arguments which are (1) the full pathname of the file
           27  +# that has gone over quota, (2) the quota limit, (3) the requested
           28  +# new quota size to cover the last write.  These three values are
           29  +# appended to the global variable $::quota.  The filename is processed
           30  +# to convert every \ character into / and to change the name of the
           31  +# working directory to PWD.  
           32  +#
           33  +# The quota is increased to the request if the ::quota_request_ok 
           34  +# global variable is true.
           35  +#
           36  +set ::quota {}
           37  +set ::quota_request_ok 0
           38  +proc quota_check {filename limitvar size} {
           39  +  upvar $limitvar limit
           40  +  set filename [string map [list [pwd] PWD \\ /] $filename]
           41  +  lappend ::quota $filename [set limit] $size
           42  +  if {$::quota_request_ok} {set limit $size}
           43  +}
           44  +
           45  +sqlite3_quota_set */quota2a/* 4000 quota_check
           46  +sqlite3_quota_set */quota2b/* 5000 quota_check
           47  +
           48  +unset -nocomplain bigtext
           49  +for {set i 1} {$i<=1000} {incr i} {
           50  +  if {$i%10==0} {
           51  +    append bigtext [format "%06d\n" $i]
           52  +  } else {
           53  +    append bigtext [format "%06d " $i]
           54  +  }
           55  +}
           56  +
           57  +catch { unset h1 }
           58  +catch { unset x }
           59  +do_test quota2-1.1 {
           60  +  set ::h1 [sqlite3_quota_fopen quota2a/xyz.txt w+]
           61  +  sqlite3_quota_fwrite $::h1 1 7000 $bigtext
           62  +} {4000}
           63  +do_test quota2-1.2 {
           64  +  set ::quota
           65  +} {PWD/quota2a/xyz.txt 4000 7000}
           66  +do_test quota2-1.3 {
           67  +  sqlite3_quota_rewind $::h1
           68  +  set ::x [sqlite3_quota_fread $::h1 1001 7]
           69  +  string length $::x
           70  +} {3003}
           71  +do_test quota2-1.4 {
           72  +  string match $::x [string range $::bigtext 0 3002]
           73  +} {1}
           74  +do_test quota2-1.5 {
           75  +  sqlite3_quota_fseek $::h1 0 SEEK_END
           76  +  sqlite3_quota_ftell $::h1
           77  +} {4000}
           78  +do_test quota2-1.6 {
           79  +  sqlite3_quota_fseek $::h1 -100 SEEK_END
           80  +  sqlite3_quota_ftell $::h1
           81  +} {3900}
           82  +do_test quota2-1.7 {
           83  +  sqlite3_quota_fseek $::h1 -100 SEEK_CUR
           84  +  sqlite3_quota_ftell $::h1
           85  +} {3800}
           86  +do_test quota2-1.8 {
           87  +  sqlite3_quota_fseek $::h1 50 SEEK_CUR
           88  +  sqlite3_quota_ftell $::h1
           89  +} {3850}
           90  +do_test quota2-1.9 {
           91  +  sqlite3_quota_fseek $::h1 50 SEEK_SET
           92  +  sqlite3_quota_ftell $::h1
           93  +} {50}
           94  +do_test quota2-1.10 {
           95  +  sqlite3_quota_rewind $::h1
           96  +  sqlite3_quota_ftell $::h1
           97  +} {0}
           98  +do_test quota2-1.11 {
           99  +  string map [list [pwd] PWD \\ /] [sqlite3_quota_dump]
          100  +} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}}
          101  +do_test quota1-1.12 {
          102  +  sqlite3_quota_fclose $::h1
          103  +  string map [list [pwd] PWD \\ /] [sqlite3_quota_dump]
          104  +} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}}
          105  +do_test quota1-1.13 {
          106  +  sqlite3_quota_remove quota2a/xyz.txt
          107  +  string map [list [pwd] PWD \\ /] [sqlite3_quota_dump]
          108  +} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}}
          109  +
          110  +
          111  +
          112  +catch { sqlite3_quota_shutdown }
          113  +catch { unset quota_request_ok }
          114  +finish_test