Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add the sqlite3_quota_dump test command. Add a destructor argument on the sqlite3_quota_set() interface. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | experimental |
Files: | files | file ages | folders |
SHA1: |
7a624b5ae2abff21bcbbb34af88d1c76 |
User & Date: | drh 2010-09-01 14:35:49.000 |
Context
2010-09-01
| ||
14:45 | Make all private routines in test_quota.c begin with "quota". Fix a test_quota.c segfault when setting a zero-quota. (check-in: c0d0fc3a1c user: drh tags: experimental) | |
14:35 | Add the sqlite3_quota_dump test command. Add a destructor argument on the sqlite3_quota_set() interface. (check-in: 7a624b5ae2 user: drh tags: experimental) | |
13:09 | Clean up comments in the test_quota.c source file. (check-in: c1eec7dba6 user: drh tags: experimental) | |
Changes
Changes to src/test_quota.c.
︙ | ︙ | |||
31 32 33 34 35 36 37 | #include <string.h> #include <assert.h> /************************ Object Definitions ******************************/ /* Forward declaration of all object types */ typedef struct quotaGroup quotaGroup; | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include <string.h> #include <assert.h> /************************ Object Definitions ******************************/ /* Forward declaration of all object types */ typedef struct quotaGroup quotaGroup; typedef struct quotaConn quotaConn; typedef struct quotaFile quotaFile; /* ** A "quota group" is a collection of files whose collective size we want ** to limit. Each quota group is defined by a GLOB pattern. ** ** There is an instance of the following object for each defined quota |
︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 68 69 70 71 72 | void (*xCallback)( /* Callback invoked when going over quota */ const char *zFilename, /* Name of file whose size increases */ sqlite3_int64 *piLimit, /* IN/OUT: The current limit */ sqlite3_int64 iSize, /* Total size of all files in the group */ void *pArg /* Client data */ ); void *pArg; /* Third argument to the xCallback() */ quotaGroup *pNext, **ppPrev; /* Doubly linked list of all quota objects */ quotaFile *pFile; /* Files within this group */ }; /* ** An instance of this structure represents a single file that is part ** of a quota group. A single file can be opened multiple times. In | > | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | void (*xCallback)( /* Callback invoked when going over quota */ const char *zFilename, /* Name of file whose size increases */ sqlite3_int64 *piLimit, /* IN/OUT: The current limit */ sqlite3_int64 iSize, /* Total size of all files in the group */ 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 */ }; /* ** An instance of this structure represents a single file that is part ** of a quota group. A single file can be opened multiple times. In |
︙ | ︙ | |||
85 86 87 88 89 90 91 | /* ** An instance of the following object represents each open connection ** to a file that participates in quota tracking. This object is a ** subclass of sqlite3_file. The sqlite3_file object for the underlying ** VFS is appended to this structure. */ | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | /* ** An instance of the following object represents each open connection ** to a file that participates in quota tracking. This object is a ** subclass of sqlite3_file. The sqlite3_file object for the underlying ** VFS is appended to this structure. */ 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 */ }; /************************* Global Variables **********************************/ /* |
︙ | ︙ | |||
153 154 155 156 157 158 159 160 161 162 163 164 165 166 | /* If the reference count and threshold for a quotaGroup are both ** zero, then destroy the quotaGroup. */ 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; sqlite3_free(p); } } /* ** Return TRUE if string z matches glob pattern zGlob. ** | > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | /* If the reference count and threshold for a quotaGroup are both ** zero, then destroy the quotaGroup. */ 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); } } /* ** Return TRUE if string z matches glob pattern zGlob. ** |
︙ | ︙ | |||
239 240 241 242 243 244 245 | } return *z==0; } /* Find a quotaGroup given the filename. ** | | | | | | | | | | | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | } return *z==0; } /* Find a quotaGroup given the filename. ** ** Return a pointer to the quotaGroup object. Return NULL if not found. */ static quotaGroup *quotaGroupFind(const char *zFilename){ quotaGroup *p; for(p=gQuota.pGroup; p && strglob(p->zPattern, zFilename)==0; p=p->pNext){} return p; } /* Translate an sqlite3_file* that is really a quotaConn* into ** the sqlite3_file* for the underlying original VFS. */ static sqlite3_file *quotaSubOpen(sqlite3_file *pConn){ quotaConn *p = (quotaConn*)pConn; return (sqlite3_file*)&p[1]; } /************************* VFS Method Wrappers *****************************/ /* ** This is the xOpen method used for the "quota" VFS. ** ** Most of the work is done by the underlying original VFS. This method ** simply links the new file into the appropriate quota group if it is a ** file that needs to be tracked. */ static int quotaOpen( sqlite3_vfs *pVfs, /* The quota VFS */ const char *zName, /* Name of file to be opened */ 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 */ 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 */ sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs; /* Real VFS */ /* If the file is not a main database file or a WAL, then use the ** normal xOpen method. */ if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ return pOrigVfs->xOpen(pOrigVfs, zName, pConn, flags, pOutFlags); } /* If the name of the file does not match any quota group, then ** use the normal xOpen method. */ quotaEnter(); pGroup = quotaGroupFind(zName); if( pGroup==0 ){ 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 = (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); pFile=pFile->pNext){} if( pFile==0 ){ int nName = strlen(zName); pFile = sqlite3_malloc( sizeof(*pFile) + nName + 1 ); |
︙ | ︙ | |||
333 334 335 336 337 338 339 | quotaLeave(); return rc; } /************************ I/O Method Wrappers *******************************/ /* xClose requests get passed through to the original VFS. But we | | > | | | | | | | | | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | quotaLeave(); return rc; } /************************ I/O Method Wrappers *******************************/ /* xClose requests get passed through to the original VFS. But we ** 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 *pConn){ quotaConn *p = (quotaConn*)pConn; quotaFile *pFile = p->pFile; sqlite3_file *pSubOpen = quotaSubOpen(pConn); int rc; rc = pSubOpen->pMethods->xClose(pSubOpen); quotaEnter(); pFile->nRef--; if( pFile->nRef==0 ){ quotaGroup *pGroup = pFile->pGroup; pGroup->iSize -= pFile->iSize; if( pFile->pNext ) pFile->pNext->ppPrev = pFile->ppPrev; *pFile->ppPrev = pFile->pNext; quotaGroupDeref(pGroup); sqlite3_free(pFile); } quotaLeave(); return rc; } /* Pass xRead requests directory thru to the original VFS without ** further processing. */ static int quotaRead( sqlite3_file *pConn, void *pBuf, int iAmt, sqlite3_int64 iOfst ){ sqlite3_file *pSubOpen = quotaSubOpen(pConn); return pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst); } /* Check xWrite requests to see if they expand the file. If they do, ** the perform a quota check before passing them through to the ** original VFS. */ static int quotaWrite( sqlite3_file *pConn, const void *pBuf, int iAmt, sqlite3_int64 iOfst ){ quotaConn *p = (quotaConn*)pConn; sqlite3_file *pSubOpen = quotaSubOpen(pConn); sqlite3_int64 iEnd = iOfst+iAmt; quotaGroup *pGroup; quotaFile *pFile = p->pFile; sqlite3_int64 szNew; if( pFile->iSize<iEnd ){ pGroup = pFile->pGroup; |
︙ | ︙ | |||
409 410 411 412 413 414 415 | } return pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst); } /* Pass xTruncate requests thru to the original VFS. If the ** success, update the file size. */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | } return pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst); } /* Pass xTruncate requests thru to the original VFS. If the ** success, update the file size. */ 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; if( rc==SQLITE_OK ){ quotaEnter(); pGroup = pFile->pGroup; pGroup->iSize -= pFile->iSize; pFile->iSize = size; pGroup->iSize += size; quotaLeave(); } return rc; } /* Pass xSync requests through to the original VFS without change */ 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 *pConn, sqlite3_int64 *pSize){ quotaConn *p = (quotaConn*)pConn; sqlite3_file *pSubOpen = quotaSubOpen(pConn); quotaFile *pFile = p->pFile; quotaGroup *pGroup; sqlite3_int64 sz; int rc; rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz); if( rc==SQLITE_OK ){ quotaEnter(); pGroup = pFile->pGroup; pGroup->iSize -= pFile->iSize; pFile->iSize = sz; pGroup->iSize += sz; quotaLeave(); *pSize = sz; } return rc; } /* Pass xLock requests through to the original VFS unchanged. */ 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 *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 *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 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 *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 *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 *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(pConn); return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend, pp); } /* Pass xShmLock requests through to the original VFS unchanged. */ static int quotaShmLock( 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(pConn); return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags); } /* Pass xShmBarrier requests through to the original VFS unchanged. */ 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 *pConn, int deleteFlag){ sqlite3_file *pSubOpen = quotaSubOpen(pConn); return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag); } /************************** Public Interfaces *****************************/ /* ** Initialize the quota VFS shim. Use the VFS named zOrigVfsName ** as the VFS that does the actual work. Use the default if |
︙ | ︙ | |||
563 564 565 566 567 568 569 | gQuota.pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( !gQuota.pMutex ){ return SQLITE_NOMEM; } gQuota.isInitialized = 1; gQuota.pOrigVfs = pOrigVfs; gQuota.sThisVfs = *pOrigVfs; | | | | | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 | gQuota.pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( !gQuota.pMutex ){ return SQLITE_NOMEM; } gQuota.isInitialized = 1; gQuota.pOrigVfs = pOrigVfs; gQuota.sThisVfs = *pOrigVfs; gQuota.sThisVfs.xOpen = quotaOpen; gQuota.sThisVfs.szOsFile += sizeof(quotaConn); gQuota.sThisVfs.zName = "quota"; gQuota.sIoMethodsV1.iVersion = 1; gQuota.sIoMethodsV1.xClose = quotaClose; gQuota.sIoMethodsV1.xRead = quotaRead; gQuota.sIoMethodsV1.xWrite = quotaWrite; gQuota.sIoMethodsV1.xTruncate = quotaTruncate; gQuota.sIoMethodsV1.xSync = quotaSync; gQuota.sIoMethodsV1.xFileSize = quotaFileSize; gQuota.sIoMethodsV1.xLock = quotaLock; gQuota.sIoMethodsV1.xUnlock = quotaUnlock; gQuota.sIoMethodsV1.xCheckReservedLock = quotaCheckReservedLock; gQuota.sIoMethodsV1.xFileControl = quotaFileControl; gQuota.sIoMethodsV1.xSectorSize = quotaSectorSize; gQuota.sIoMethodsV1.xDeviceCharacteristics = quotaDeviceCharacteristics; gQuota.sIoMethodsV2 = gQuota.sIoMethodsV1; gQuota.sIoMethodsV2.iVersion = 2; gQuota.sIoMethodsV2.xShmMap = quotaShmMap; gQuota.sIoMethodsV2.xShmLock = quotaShmLock; gQuota.sIoMethodsV2.xShmBarrier = quotaShmBarrier; |
︙ | ︙ | |||
645 646 647 648 649 650 651 | sqlite3_int64 iLimit, /* New quota to set for this quota group */ void (*xCallback)( /* Callback invoked when going over quota */ const char *zFilename, /* Name of file whose size increases */ sqlite3_int64 *piLimit, /* IN/OUT: The current limit */ sqlite3_int64 iSize, /* Total size of all files in the group */ void *pArg /* Client data */ ), | | > | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | sqlite3_int64 iLimit, /* New quota to set for this quota group */ void (*xCallback)( /* Callback invoked when going over quota */ const char *zFilename, /* Name of file whose size increases */ sqlite3_int64 *piLimit, /* IN/OUT: The current limit */ sqlite3_int64 iSize, /* Total size of all files in the group */ void *pArg /* Client data */ ), void *pArg, /* client data passed thru to callback */ void (*xDestroy)(void*) /* Optional destructor for pArg */ ){ quotaGroup *pGroup; quotaEnter(); pGroup = gQuota.pGroup; while( pGroup && strcmp(pGroup->zPattern, zPattern)!=0 ){ pGroup = pGroup->pNext; } |
︙ | ︙ | |||
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | if( gQuota.pGroup ) gQuota.pGroup->ppPrev = &pGroup->pNext; pGroup->pNext = gQuota.pGroup; pGroup->ppPrev = &gQuota.pGroup; gQuota.pGroup = pGroup; } pGroup->iLimit = iLimit; pGroup->xCallback = xCallback; pGroup->pArg = pArg; quotaGroupDeref(pGroup); quotaLeave(); return SQLITE_OK; } /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST #include <tcl.h> typedef struct TclQuotaCallback TclQuotaCallback; struct TclQuotaCallback { | > > > > > > > | | < < > > > > | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | if( gQuota.pGroup ) gQuota.pGroup->ppPrev = &pGroup->pNext; pGroup->pNext = gQuota.pGroup; pGroup->ppPrev = &gQuota.pGroup; gQuota.pGroup = pGroup; } 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; } /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST #include <tcl.h> /* ** Argument passed to a TCL quota-over-limit callback. */ typedef struct TclQuotaCallback TclQuotaCallback; struct TclQuotaCallback { Tcl_Interp *interp; /* Interpreter in which to run the script */ Tcl_Obj *pScript; /* Script to be run */ }; 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 */ sqlite3_int64 iSize, /* Total size of all files in the group */ void *pArg /* Client data */ ){ TclQuotaCallback *p; /* Callback script object */ |
︙ | ︙ | |||
728 729 730 731 732 733 734 735 736 737 738 739 740 741 | Tcl_UnsetVar(p->interp, Tcl_GetString(pVarname), 0); } Tcl_DecrRefCount(pEval); Tcl_DecrRefCount(pVarname); if( rc!=TCL_OK ) Tcl_BackgroundError(p->interp); } /* ** tclcmd: sqlite3_quota_initialize NAME MAKEDEFAULT */ static int test_quota_initialize( void * clientData, Tcl_Interp *interp, | > > > > > > > > > > > | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 | Tcl_UnsetVar(p->interp, Tcl_GetString(pVarname), 0); } Tcl_DecrRefCount(pEval); Tcl_DecrRefCount(pVarname); 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 */ static int test_quota_initialize( void * clientData, Tcl_Interp *interp, |
︙ | ︙ | |||
778 779 780 781 782 783 784 | return TCL_ERROR; } /* Call sqlite3_quota_shutdown() */ rc = sqlite3_quota_shutdown(); Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); | < < < < < < < < < < < < < > > > | | | > > > > > | | > | | > > | > > > > > | | > > > > > > > | | | > > > > > > > > > > > > > > > > > | > | > | > | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | return TCL_ERROR; } /* Call sqlite3_quota_shutdown() */ rc = sqlite3_quota_shutdown(); Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_set PATTERN LIMIT SCRIPT */ static int test_quota_set( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zPattern; /* File pattern to configure */ sqlite3_int64 iLimit; /* Initial quota in bytes */ 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 ){ Tcl_WrongNumArgs(interp, 1, objv, "PATTERN LIMIT SCRIPT"); return TCL_ERROR; } zPattern = Tcl_GetString(objv[1]); if( Tcl_GetWideIntFromObj(interp, objv[2], &iLimit) ) return TCL_ERROR; pScript = objv[3]; Tcl_GetStringFromObj(pScript, &nScript); 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; }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 ** of this module. */ int Sqlitequota_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; } aCmd[] = { { "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; for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); } return TCL_OK; } #endif |
Changes to test/quota.test.
︙ | ︙ | |||
97 98 99 100 101 102 103 | } {SQLITE_MISUSE} set ::quota [list] do_test quota-2.4.2 { catchsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {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} | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | } {SQLITE_MISUSE} set ::quota [list] do_test quota-2.4.2 { catchsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {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.99 { db close sqlite3_quota_shutdown } {SQLITE_OK} #------------------------------------------------------------------------- # Try some tests with more than one connection to a database file. Still # in rollback mode. |
︙ | ︙ | |||
135 136 137 138 139 140 141 142 143 144 145 | } {3072} do_test quota-3.1.3 { sqlite3 db2 test.db set ::quota [list] execsql { CREATE TABLE t2(a, b) } db2 set ::quota } {} do_test quota-3.X { catch { db close } catch { db2 close } | > > > > > > > > > > > > > > > > > | > | > > > | > > | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | } {3072} do_test quota-3.1.3 { sqlite3 db2 test.db set ::quota [list] 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 } } {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 |