]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the sqlite3_quota_dump test command. Add a destructor argument on
authordrh <drh@noemail.net>
Wed, 1 Sep 2010 14:35:48 +0000 (14:35 +0000)
committerdrh <drh@noemail.net>
Wed, 1 Sep 2010 14:35:48 +0000 (14:35 +0000)
the sqlite3_quota_set() interface.

FossilOrigin-Name: 7a624b5ae2abff21bcbbb34af88d1c7656f3b729

manifest
manifest.uuid
src/test_quota.c
test/quota.test

index f7d1163f36c88e3d18b6a20d15d435a4ef226b5b..ebafdadb9d6b507819fc74d1edc50d27695c4118 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,8 +1,8 @@
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
-C Clean\sup\scomments\sin\sthe\stest_quota.c\ssource\sfile.
-D 2010-09-01T13:09:57
+C Add\sthe\ssqlite3_quota_dump\stest\scommand.\s\sAdd\sa\sdestructor\sargument\son\nthe\ssqlite3_quota_set()\sinterface.
+D 2010-09-01T14:35:49
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in c599a15d268b1db2aeadea19df2adc3bf2eb6bee
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -211,7 +211,7 @@ F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
 F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
 F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
 F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
-F src/test_quota.c e542d96d5e0ad7bbc064ab9912da3d8ed65cbe28
+F src/test_quota.c 92015bbb781f58a7073d03a4faf9981e46d679c4
 F src/test_rtree.c e957a603a98871dcf005c1e96ae791cfe74eb7f6
 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
@@ -565,7 +565,7 @@ F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
 F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
-F test/quota.test 0026c53f3ad78094f478c5e7048fb63602d59ee7
+F test/quota.test e6ea65a69ab79e77a9945d97004204fd6d8c3d97
 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
@@ -856,14 +856,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P f5d263803084107389c5541face8d536b62fffe3
-R 35c143fcc0c1d935b095e49fe0b10b28
+P c1eec7dba698e5bad0870cb80079203f0fb89514
+R 5ccdd6b5ff8c4a7fd8c3537f33664271
 U drh
-Z 22044fa4707460c35e1dd2a52d813a99
+Z 37a3d6817393597a2d599801ebf7d8b4
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.6 (GNU/Linux)
 
-iD8DBQFMflCroxKgR168RlERAupSAJ41VgmVbutErFMPzEt158JfEp4N/gCeLiry
-ne2YPJhXeQQSv7tL27HzCOk=
-=nNgv
+iD8DBQFMfmTIoxKgR168RlERAkXOAJ9rg479NHW8icHIeLtH5Tt3WleCsQCfVywb
+rV5uQ2LKNw+EzD5POJ3VPYQ=
+=vORW
 -----END PGP SIGNATURE-----
index 63e92c447c98d025a6cf802f68181b7fd646d5b9..e1c19f426f122e1c4f738a67fd0b766781365fa4 100644 (file)
@@ -1 +1 @@
-c1eec7dba698e5bad0870cb80079203f0fb89514
\ No newline at end of file
+7a624b5ae2abff21bcbbb34af88d1c7656f3b729
\ No newline at end of file
index 61a8f6e8be05f71ee62a4de92b3cd75628b5b6e8..1e372ca9cc2678f80c1f5b7a631664695c2f3f70 100644 (file)
@@ -35,7 +35,7 @@
 
 /* Forward declaration of all object types */
 typedef struct quotaGroup quotaGroup;
-typedef struct quotaOpen quotaOpen;
+typedef struct quotaConn quotaConn;
 typedef struct quotaFile quotaFile;
 
 /*
@@ -63,6 +63,7 @@ struct quotaGroup {
      void *pArg                     /* Client data */
   );
   void *pArg;                    /* Third argument to the xCallback() */
+  void (*xDestroy)(void*);       /* Optional destructor for pArg */
   quotaGroup *pNext, **ppPrev;   /* Doubly linked list of all quota objects */
   quotaFile *pFile;              /* Files within this group */
 };
@@ -89,7 +90,7 @@ struct quotaFile {
 ** subclass of sqlite3_file.  The sqlite3_file object for the underlying
 ** VFS is appended to this structure.
 */
-struct quotaOpen {
+struct quotaConn {
   sqlite3_file base;              /* Base class - must be first */
   quotaFile *pFile;               /* The underlying file */
   /* The underlying VFS sqlite3_file is appended to this object */
@@ -157,6 +158,7 @@ static void quotaGroupDeref(quotaGroup *p){
   if( p->pFile==0 && p->iLimit==0 ){
     if( p->pNext ) p->pNext->ppPrev = p->ppPrev;
     if( p->ppPrev ) *p->ppPrev = p->pNext;
+    if( p->xDestroy ) p->xDestroy(p->pArg);
     sqlite3_free(p);
   }
 }
@@ -243,7 +245,7 @@ static int strglob(const char *zGlob, const char *z){
 
 /* Find a quotaGroup given the filename.
 **
-** Return a pointer to the quotaOpen object. Return NULL if not found.
+** Return a pointer to the quotaGroup object. Return NULL if not found.
 */
 static quotaGroup *quotaGroupFind(const char *zFilename){
   quotaGroup *p;
@@ -251,11 +253,11 @@ static quotaGroup *quotaGroupFind(const char *zFilename){
   return p;
 }
 
-/* Translate an sqlite3_file* that is really a quotaOpen* into
+/* Translate an sqlite3_file* that is really a quotaConn* into
 ** the sqlite3_file* for the underlying original VFS.
 */
-static sqlite3_file *quotaSubOpen(sqlite3_file *pOpen){
-  quotaOpen *p = (quotaOpen*)pOpen;
+static sqlite3_file *quotaSubOpen(sqlite3_file *pConn){
+  quotaConn *p = (quotaConn*)pConn;
   return (sqlite3_file*)&p[1];
 }
 
@@ -267,15 +269,15 @@ static sqlite3_file *quotaSubOpen(sqlite3_file *pOpen){
 ** simply links the new file into the appropriate quota group if it is a
 ** file that needs to be tracked.
 */
-static int quotaxOpen(
+static int quotaOpen(
   sqlite3_vfs *pVfs,          /* The quota VFS */
   const char *zName,          /* Name of file to be opened */
-  sqlite3_file *pOpen,        /* Fill in this file descriptor */
+  sqlite3_file *pConn,        /* Fill in this file descriptor */
   int flags,                  /* Flags to control the opening */
   int *pOutFlags              /* Flags showing results of opening */
 ){
   int rc;                                    /* Result code */         
-  quotaOpen *pQuotaOpen;                     /* The new quota file descriptor */
+  quotaConn *pQuotaOpen;                     /* The new quota file descriptor */
   quotaFile *pFile;                          /* Corresponding quotaFile obj */
   quotaGroup *pGroup;                        /* The group file belongs to */
   sqlite3_file *pSubOpen;                    /* Real file descriptor */
@@ -285,7 +287,7 @@ static int quotaxOpen(
   ** normal xOpen method.
   */
   if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){
-    return pOrigVfs->xOpen(pOrigVfs, zName, pOpen, flags, pOutFlags);
+    return pOrigVfs->xOpen(pOrigVfs, zName, pConn, flags, pOutFlags);
   }
 
   /* If the name of the file does not match any quota group, then
@@ -294,12 +296,12 @@ static int quotaxOpen(
   quotaEnter();
   pGroup = quotaGroupFind(zName);
   if( pGroup==0 ){
-    rc = pOrigVfs->xOpen(pOrigVfs, zName, pOpen, flags, pOutFlags);
+    rc = pOrigVfs->xOpen(pOrigVfs, zName, pConn, flags, pOutFlags);
   }else{
     /* If we get to this point, it means the file needs to be quota tracked.
     */
-    pQuotaOpen = (quotaOpen*)pOpen;
-    pSubOpen = quotaSubOpen(pOpen);
+    pQuotaOpen = (quotaConn*)pConn;
+    pSubOpen = quotaSubOpen(pConn);
     rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubOpen, flags, pOutFlags);
     if( rc==SQLITE_OK ){
       for(pFile=pGroup->pFile; pFile && strcmp(pFile->zFilename, zName);
@@ -337,12 +339,13 @@ static int quotaxOpen(
 /************************ I/O Method Wrappers *******************************/
 
 /* xClose requests get passed through to the original VFS.  But we
-** also have to unlink the quotaOpen from the quotaGroup.
+** also have to unlink the quotaConn from the quotaFile and quotaGroup.
+** The quotaFile and/or quotaGroup are freed if they are no longer in use.
 */
-static int quotaClose(sqlite3_file *pOpen){
-  quotaOpen *p = (quotaOpen*)pOpen;
+static int quotaClose(sqlite3_file *pConn){
+  quotaConn *p = (quotaConn*)pConn;
   quotaFile *pFile = p->pFile;
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   int rc;
   rc = pSubOpen->pMethods->xClose(pSubOpen);
   quotaEnter();
@@ -363,12 +366,12 @@ static int quotaClose(sqlite3_file *pOpen){
 ** further processing.
 */
 static int quotaRead(
-  sqlite3_file *pOpen,
+  sqlite3_file *pConn,
   void *pBuf,
   int iAmt,
   sqlite3_int64 iOfst
 ){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
 }
 
@@ -377,13 +380,13 @@ static int quotaRead(
 ** original VFS.
 */
 static int quotaWrite(
-  sqlite3_file *pOpen,
+  sqlite3_file *pConn,
   const void *pBuf,
   int iAmt,
   sqlite3_int64 iOfst
 ){
-  quotaOpen *p = (quotaOpen*)pOpen;
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  quotaConn *p = (quotaConn*)pConn;
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   sqlite3_int64 iEnd = iOfst+iAmt;
   quotaGroup *pGroup;
   quotaFile *pFile = p->pFile;
@@ -413,9 +416,9 @@ static int quotaWrite(
 /* Pass xTruncate requests thru to the original VFS.  If the
 ** success, update the file size.
 */
-static int quotaTruncate(sqlite3_file *pOpen, sqlite3_int64 size){
-  quotaOpen *p = (quotaOpen*)pOpen;
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaTruncate(sqlite3_file *pConn, sqlite3_int64 size){
+  quotaConn *p = (quotaConn*)pConn;
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   int rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
   quotaFile *pFile = p->pFile;
   quotaGroup *pGroup;
@@ -432,17 +435,17 @@ static int quotaTruncate(sqlite3_file *pOpen, sqlite3_int64 size){
 
 /* Pass xSync requests through to the original VFS without change
 */
-static int quotaSync(sqlite3_file *pOpen, int flags){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaSync(sqlite3_file *pConn, int flags){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xSync(pSubOpen, flags);
 }
 
 /* Pass xFileSize requests through to the original VFS but then
 ** update the quotaGroup with the new size before returning.
 */
-static int quotaFileSize(sqlite3_file *pOpen, sqlite3_int64 *pSize){
-  quotaOpen *p = (quotaOpen*)pOpen;
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
+  quotaConn *p = (quotaConn*)pConn;
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   quotaFile *pFile = p->pFile;
   quotaGroup *pGroup;
   sqlite3_int64 sz;
@@ -463,82 +466,82 @@ static int quotaFileSize(sqlite3_file *pOpen, sqlite3_int64 *pSize){
 
 /* Pass xLock requests through to the original VFS unchanged.
 */
-static int quotaLock(sqlite3_file *pOpen, int lock){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaLock(sqlite3_file *pConn, int lock){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xLock(pSubOpen, lock);
 }
 
 /* Pass xUnlock requests through to the original VFS unchanged.
 */
-static int quotaUnlock(sqlite3_file *pOpen, int lock){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaUnlock(sqlite3_file *pConn, int lock){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
 }
 
 /* Pass xCheckReservedLock requests through to the original VFS unchanged.
 */
-static int quotaCheckReservedLock(sqlite3_file *pOpen, int *pResOut){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaCheckReservedLock(sqlite3_file *pConn, int *pResOut){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
 }
 
 /* Pass xFileControl requests through to the original VFS unchanged.
 */
-static int quotaOpenControl(sqlite3_file *pOpen, int op, void *pArg){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaFileControl(sqlite3_file *pConn, int op, void *pArg){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
 }
 
 /* Pass xSectorSize requests through to the original VFS unchanged.
 */
-static int quotaSectorSize(sqlite3_file *pOpen){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaSectorSize(sqlite3_file *pConn){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xSectorSize(pSubOpen);
 }
 
 /* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
 */
-static int quotaDeviceCharacteristics(sqlite3_file *pOpen){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaDeviceCharacteristics(sqlite3_file *pConn){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
 }
 
 /* Pass xShmMap requests through to the original VFS unchanged.
 */
 static int quotaShmMap(
-  sqlite3_file *pOpen,            /* Handle open on database file */
+  sqlite3_file *pConn,            /* Handle open on database file */
   int iRegion,                    /* Region to retrieve */
   int szRegion,                   /* Size of regions */
   int bExtend,                    /* True to extend file if necessary */
   void volatile **pp              /* OUT: Mapped memory */
 ){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend, pp);
 }
 
 /* Pass xShmLock requests through to the original VFS unchanged.
 */
 static int quotaShmLock(
-  sqlite3_file *pOpen,       /* Database file holding the shared memory */
+  sqlite3_file *pConn,       /* Database file holding the shared memory */
   int ofst,                  /* First lock to acquire or release */
   int n,                     /* Number of locks to acquire or release */
   int flags                  /* What to do with the lock */
 ){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
 }
 
 /* Pass xShmBarrier requests through to the original VFS unchanged.
 */
-static void quotaShmBarrier(sqlite3_file *pOpen){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static void quotaShmBarrier(sqlite3_file *pConn){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   pSubOpen->pMethods->xShmBarrier(pSubOpen);
 }
 
 /* Pass xShmUnmap requests through to the original VFS unchanged.
 */
-static int quotaShmUnmap(sqlite3_file *pOpen, int deleteFlag){
-  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+static int quotaShmUnmap(sqlite3_file *pConn, int deleteFlag){
+  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
 }
 
@@ -567,8 +570,8 @@ int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){
   gQuota.isInitialized = 1;
   gQuota.pOrigVfs = pOrigVfs;
   gQuota.sThisVfs = *pOrigVfs;
-  gQuota.sThisVfs.xOpen = quotaxOpen;
-  gQuota.sThisVfs.szOsFile += sizeof(quotaOpen);
+  gQuota.sThisVfs.xOpen = quotaOpen;
+  gQuota.sThisVfs.szOsFile += sizeof(quotaConn);
   gQuota.sThisVfs.zName = "quota";
   gQuota.sIoMethodsV1.iVersion = 1;
   gQuota.sIoMethodsV1.xClose = quotaClose;
@@ -580,7 +583,7 @@ int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){
   gQuota.sIoMethodsV1.xLock = quotaLock;
   gQuota.sIoMethodsV1.xUnlock = quotaUnlock;
   gQuota.sIoMethodsV1.xCheckReservedLock = quotaCheckReservedLock;
-  gQuota.sIoMethodsV1.xFileControl = quotaOpenControl;
+  gQuota.sIoMethodsV1.xFileControl = quotaFileControl;
   gQuota.sIoMethodsV1.xSectorSize = quotaSectorSize;
   gQuota.sIoMethodsV1.xDeviceCharacteristics = quotaDeviceCharacteristics;
   gQuota.sIoMethodsV2 = gQuota.sIoMethodsV1;
@@ -649,7 +652,8 @@ int sqlite3_quota_set(
      sqlite3_int64 iSize,           /* Total size of all files in the group */
      void *pArg                     /* Client data */
   ),
-  void *pArg                      /* client data passed thru to callback */
+  void *pArg,                     /* client data passed thru to callback */
+  void (*xDestroy)(void*)         /* Optional destructor for pArg */
 ){
   quotaGroup *pGroup;
   quotaEnter();
@@ -674,7 +678,11 @@ int sqlite3_quota_set(
   }
   pGroup->iLimit = iLimit;
   pGroup->xCallback = xCallback;
+  if( pGroup->xDestroy && pGroup->pArg!=pArg ){
+    pGroup->xDestroy(pGroup->pArg);
+  }
   pGroup->pArg = pArg;
+  pGroup->xDestroy = xDestroy;
   quotaGroupDeref(pGroup);
   quotaLeave();
   return SQLITE_OK;
@@ -685,16 +693,21 @@ int sqlite3_quota_set(
 #ifdef SQLITE_TEST
 #include <tcl.h>
 
+/*
+** Argument passed to a TCL quota-over-limit callback.
+*/
 typedef struct TclQuotaCallback TclQuotaCallback;
 struct TclQuotaCallback {
-  Tcl_Interp *interp;
-  Tcl_Obj *pScript;
-  TclQuotaCallback *pNext;
+  Tcl_Interp *interp;    /* Interpreter in which to run the script */
+  Tcl_Obj *pScript;      /* Script to be run */
 };
-static TclQuotaCallback *pQuotaCallbackList = 0;
 
 extern const char *sqlite3TestErrorName(int);
 
+
+/*
+** This is the callback from a quota-over-limit.
+*/
 static void tclQuotaCallback(
   const char *zFilename,          /* Name of file whose size increases */
   sqlite3_int64 *piLimit,         /* IN/OUT: The current limit */
@@ -733,6 +746,17 @@ static void tclQuotaCallback(
   if( rc!=TCL_OK ) Tcl_BackgroundError(p->interp);
 }
 
+/*
+** Destructor for a TCL quota-over-limit callback.
+*/
+static void tclCallbackDestructor(void *pObj){
+  TclQuotaCallback *p = (TclQuotaCallback*)pObj;
+  if( p ){
+    Tcl_DecrRefCount(p->pScript);
+    ckfree((char *)p);
+  }
+}
+
 /*
 ** tclcmd: sqlite3_quota_initialize NAME MAKEDEFAULT
 */
@@ -782,19 +806,6 @@ static int test_quota_shutdown(
   rc = sqlite3_quota_shutdown();
   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
 
-  /* If the quota system was successfully shut down, delete all the quota
-  ** callback script objects in the global linked list.
-  */
-  if( rc==SQLITE_OK ){
-    TclQuotaCallback *p, *pNext;
-    for(p=pQuotaCallbackList; p; p=pNext){
-      pNext = p->pNext;
-      Tcl_DecrRefCount(p->pScript);
-      ckfree((char *)p);
-    }
-    pQuotaCallbackList = 0;
-  }
-
   return TCL_OK;
 }
 
@@ -812,6 +823,7 @@ static int test_quota_set(
   Tcl_Obj *pScript;               /* Tcl script to invoke to increase quota */
   int rc;                         /* Value returned by quota_set() */
   TclQuotaCallback *p;            /* Callback object */
+  int nScript;                    /* Length of callback script */
 
   /* Process arguments */
   if( objc!=4 ){
@@ -821,27 +833,68 @@ static int test_quota_set(
   zPattern = Tcl_GetString(objv[1]);
   if( Tcl_GetWideIntFromObj(interp, objv[2], &iLimit) ) return TCL_ERROR;
   pScript = objv[3];
+  Tcl_GetStringFromObj(pScript, &nScript);
 
-  /* Allocate a TclQuotaCallback object */
-  p = (TclQuotaCallback *)ckalloc(sizeof(TclQuotaCallback));
-  memset(p, 0, sizeof(TclQuotaCallback));
-
-  /* Invoke sqlite3_quota_set() */
-  rc = sqlite3_quota_set(zPattern, iLimit, tclQuotaCallback, (void *)p);
-  if( rc!=SQLITE_OK ){
-    ckfree((char *)p);
-  }else{
-    Tcl_IncrRefCount(pScript);
+  if( nScript>0 ){
+    /* Allocate a TclQuotaCallback object */
+    p = (TclQuotaCallback *)ckalloc(sizeof(TclQuotaCallback));
+    memset(p, 0, sizeof(TclQuotaCallback));
     p->interp = interp;
+    Tcl_IncrRefCount(pScript);
     p->pScript = pScript;
-    p->pNext = pQuotaCallbackList;
-    pQuotaCallbackList = p;
+  }else{
+    p = 0;
   }
+  /* Invoke sqlite3_quota_set() */
+  rc = sqlite3_quota_set(zPattern, iLimit, tclQuotaCallback,
+                         (void*)p, tclCallbackDestructor);
 
   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
   return TCL_OK;
 }
 
+/*
+** tclcmd:  sqlite3_quota_dump
+*/
+static int test_quota_dump(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  Tcl_Obj *pResult;
+  Tcl_Obj *pGroupTerm;
+  Tcl_Obj *pFileTerm;
+  quotaGroup *pGroup;
+  quotaFile *pFile;
+
+  pResult = Tcl_NewObj();
+  quotaEnter();
+  for(pGroup=gQuota.pGroup; pGroup; pGroup=pGroup->pNext){
+    pGroupTerm = Tcl_NewObj();
+    Tcl_ListObjAppendElement(interp, pGroupTerm,
+          Tcl_NewStringObj(pGroup->zPattern, -1));
+    Tcl_ListObjAppendElement(interp, pGroupTerm,
+          Tcl_NewWideIntObj(pGroup->iLimit));
+    Tcl_ListObjAppendElement(interp, pGroupTerm,
+          Tcl_NewWideIntObj(pGroup->iSize));
+    for(pFile=pGroup->pFile; pFile; pFile=pFile->pNext){
+      pFileTerm = Tcl_NewObj();
+      Tcl_ListObjAppendElement(interp, pFileTerm,
+            Tcl_NewStringObj(pFile->zFilename, -1));
+      Tcl_ListObjAppendElement(interp, pFileTerm,
+            Tcl_NewWideIntObj(pFile->iSize));
+      Tcl_ListObjAppendElement(interp, pFileTerm,
+            Tcl_NewWideIntObj(pFile->nRef));
+      Tcl_ListObjAppendElement(interp, pGroupTerm, pFileTerm);
+    }
+    Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
+  }
+  quotaLeave();
+  Tcl_SetObjResult(interp, pResult);
+  return TCL_OK;
+}
+
 /*
 ** This routine registers the custom TCL commands defined in this
 ** module.  This should be the only procedure visible from outside
@@ -855,6 +908,7 @@ int Sqlitequota_Init(Tcl_Interp *interp){
     { "sqlite3_quota_initialize", test_quota_initialize },
     { "sqlite3_quota_shutdown", test_quota_shutdown },
     { "sqlite3_quota_set", test_quota_set },
+    { "sqlite3_quota_dump", test_quota_dump },
   };
   int i;
 
index 9288b5f8b8015388367a463b5efa999c42e5db77..2890fe0624a3114f12f2a605757ebfaaac79de20 100644 (file)
@@ -101,7 +101,7 @@ do_test quota-2.4.2 {
 } {1 {database or disk is full}}
 do_test quota-2.4.3 { set ::quota } {5120 6144}
 do_test quota-2.4.4 { file size test.db } {5120}
-do_test quota-2.4.5 {
+do_test quota-2.4.99 {
   db close
   sqlite3_quota_shutdown
 } {SQLITE_OK}
@@ -139,12 +139,35 @@ do_test quota-3.1.3 {
   execsql { CREATE TABLE t2(a, b) } db2
   set ::quota
 } {}
+puts "quotas: [sqlite3_quota_dump]"
 
 do_test quota-3.X {
   catch { db close }
   catch { db2 close }
-  sqlite3_quota_shutdown 
-} {SQLITE_OK}
-finish_test
+} {0}
+
+#-------------------------------------------------------------------------
+# Quotas are deleted when unused and when there limit is set to zero
+#
 
+# Return a list of all currently defined quotas.  Each quota is identified
+# by its pattern.
+proc quota_list {} {
+  set allq {}
+  foreach q [sqlite3_quota_dump] {
+    lappend allq [lindex $q 0]
+  }
+  return [lsort $allq]
+}
+do_test quota-4.1 {
+  sqlite3_quota_set *test.db 0 {}
+  quota_list
+} {}
+do_test quota-4.2 {
+  sqlite3_quota_set *test.db 4096 {}
+  quota_list
+} {*test.db}
 
+
+sqlite3_quota_shutdown 
+finish_test