Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Put in PRAGMA SANITY_CHECK in place of VACUUM. (CVS 365) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
7c65029e5bf26eb640aef529a7421cd0 |
User & Date: | drh 2002-02-03 17:37:36.000 |
Context
2002-02-03
| ||
19:06 | Fix a serious bug in INSERT when the source is a SELECT. (CVS 366) (check-in: 20ea737536 user: drh tags: trunk) | |
17:37 | Put in PRAGMA SANITY_CHECK in place of VACUUM. (CVS 365) (check-in: 7c65029e5b user: drh tags: trunk) | |
03:34 | The VACUUM command now does a database sanity check. (CVS 364) (check-in: 95d1f8389d user: drh tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.50 2002/02/03 17:37:36 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
2454 2455 2456 2457 2458 2459 2460 | return SQLITE_OK; } /****************************************************************************** ** The complete implementation of the BTree subsystem is above this line. ** All the code the follows is for testing and troubleshooting the BTree ** subsystem. None of the code that follows is used during normal operation. | | | | | 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 | return SQLITE_OK; } /****************************************************************************** ** The complete implementation of the BTree subsystem is above this line. ** All the code the follows is for testing and troubleshooting the BTree ** subsystem. None of the code that follows is used during normal operation. ** All of the following code is omitted if the library is compiled with ** the -DNDEBUG=1 compiler option. ******************************************************************************/ #ifndef NDEEBUG /* ** Print a disassembly of the given page on standard output. This routine ** is used for debugging and testing only. */ int sqliteBtreePageDump(Btree *pBt, int pgno, int recursive){ int rc; |
︙ | ︙ | |||
2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 | checkAppendMsg(pCheck, zContext, zMsg); break; } iPage = (int)pOvfl->iNext; sqlitepager_unref(pOvfl); } } /* ** Do various sanity checks on a single page of a tree. Return ** the tree depth. Root pages return 0. Parents of root pages ** return 1, and so forth. ** ** These checks are done: | > > > > > > > > > > > > > > > > > | 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 | checkAppendMsg(pCheck, zContext, zMsg); break; } iPage = (int)pOvfl->iNext; sqlitepager_unref(pOvfl); } } /* ** Return negative if zKey1<zKey2. ** Return zero if zKey1==zKey2. ** Return positive if zKey1>zKey2. */ static int keyCompare( const char *zKey1, int nKey1, const char *zKey2, int nKey2 ){ int min = nKey1>nKey2 ? nKey2 : nKey1; int c = memcmp(zKey1, zKey2, min); if( c==0 ){ c = nKey1 - nKey2; } return c; } /* ** Do various sanity checks on a single page of a tree. Return ** the tree depth. Root pages return 0. Parents of root pages ** return 1, and so forth. ** ** These checks are done: |
︙ | ︙ | |||
2682 2683 2684 2685 2686 2687 2688 | */ static int checkTreePage( SanityCheck *pCheck, /* Context for the sanity check */ int iPage, /* Page number of the page to check */ MemPage *pParent, /* Parent page */ char *zParentContext, /* Parent context */ char *zLowerBound, /* All keys should be greater than this, if not NULL */ | > | > > | 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 | */ static int checkTreePage( SanityCheck *pCheck, /* Context for the sanity check */ int iPage, /* Page number of the page to check */ MemPage *pParent, /* Parent page */ char *zParentContext, /* Parent context */ char *zLowerBound, /* All keys should be greater than this, if not NULL */ int nLower, /* Number of characters in zLowerBound */ char *zUpperBound, /* All keys should be less than this, if not NULL */ int nUpper /* Number of characters in zUpperBound */ ){ MemPage *pPage; int i, rc, depth, d2, pgno; char *zKey1, *zKey2; int nKey1, nKey2; BtCursor cur; char zMsg[100]; char zContext[100]; char hit[SQLITE_PAGE_SIZE]; /* Check that the page exists */ |
︙ | ︙ | |||
2712 2713 2714 2715 2716 2717 2718 | sqlitepager_unref(pPage); return 0; } /* Check out all the cells. */ depth = 0; | > > > > > | > > | > | | | | > | | 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 | sqlitepager_unref(pPage); return 0; } /* Check out all the cells. */ depth = 0; if( zLowerBound ){ zKey1 = sqliteMalloc( nLower+1 ); memcpy(zKey1, zLowerBound, nLower); zKey1[nLower] = 0; }else{ zKey1 = 0; } nKey1 = nLower; cur.pPage = pPage; cur.pBt = pCheck->pBt; for(i=0; i<pPage->nCell; i++){ Cell *pCell = pPage->apCell[i]; int sz; /* Check payload overflow pages */ nKey2 = NKEY(pCell->h); sz = nKey2 + NDATA(pCell->h); sprintf(zContext, "On page %d cell %d: ", iPage, i); if( sz>MX_LOCAL_PAYLOAD ){ int nPage = (sz - MX_LOCAL_PAYLOAD + OVERFLOW_SIZE - 1)/OVERFLOW_SIZE; checkList(pCheck, pCell->ovfl, nPage, zContext); } /* Check that keys are in the right order */ cur.idx = i; zKey2 = sqliteMalloc( nKey2+1 ); getPayload(&cur, 0, nKey2, zKey2); if( zKey1 && keyCompare(zKey1, nKey1, zKey2, nKey2)>=0 ){ checkAppendMsg(pCheck, zContext, "Key is out of order"); } /* Check sanity of left child page. */ pgno = (int)pCell->h.leftChild; d2 = checkTreePage(pCheck, pgno, pPage, zContext, zKey1,nKey1,zKey2,nKey2); if( i>0 && d2!=depth ){ checkAppendMsg(pCheck, zContext, "Child page depth differs"); } depth = d2; sqliteFree(zKey1); zKey1 = zKey2; nKey1 = nKey2; } pgno = pPage->u.hdr.rightChild; sprintf(zContext, "On page %d at right child: ", iPage); checkTreePage(pCheck, pgno, pPage, zContext, zKey1,nKey1,zUpperBound,nUpper); sqliteFree(zKey1); /* Check for complete coverage of the page */ memset(hit, 0, sizeof(hit)); memset(hit, 1, sizeof(PageHdr)); for(i=pPage->u.hdr.firstCell; i>0 && i<SQLITE_PAGE_SIZE; ){ |
︙ | ︙ | |||
2834 2835 2836 2837 2838 2839 2840 | /* Check the integrity of the freelist */ checkList(&sCheck, pBt->page1->freeList, pBt->page1->nFree,"Main freelist: "); /* Check all the tables. */ for(i=0; i<nRoot; i++){ | | | 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 | /* Check the integrity of the freelist */ checkList(&sCheck, pBt->page1->freeList, pBt->page1->nFree,"Main freelist: "); /* Check all the tables. */ for(i=0; i<nRoot; i++){ checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ", 0,0,0,0); } /* Make sure every page in the file is referenced */ for(i=1; i<=sCheck.nPage; i++){ if( sCheck.anRef[i]==0 ){ char zBuf[100]; |
︙ | ︙ | |||
2865 2866 2867 2868 2869 2870 2871 | /* Clean up and report errors. */ sqliteFree(sCheck.anRef); return sCheck.zErrMsg; } | | | 2894 2895 2896 2897 2898 2899 2900 2901 | /* Clean up and report errors. */ sqliteFree(sCheck.anRef); return sCheck.zErrMsg; } #endif /* !defined(NDEBUG) */ |
Changes to src/btree.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** ** @(#) $Id: btree.h,v 1.21 2002/02/03 17:37:36 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ typedef struct Btree Btree; typedef struct BtCursor BtCursor; |
︙ | ︙ | |||
53 54 55 56 57 58 59 | int sqliteBtreeCloseCursor(BtCursor*); #define SQLITE_N_BTREE_META 4 int sqliteBtreeGetMeta(Btree*, int*); int sqliteBtreeUpdateMeta(Btree*, int*); | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | int sqliteBtreeCloseCursor(BtCursor*); #define SQLITE_N_BTREE_META 4 int sqliteBtreeGetMeta(Btree*, int*); int sqliteBtreeUpdateMeta(Btree*, int*); #ifndef NDEBUG int sqliteBtreePageDump(Btree*, int, int); int sqliteBtreeCursorDump(BtCursor*, int*); struct Pager *sqliteBtreePager(Btree*); char *sqliteBtreeSanityCheck(Btree*, int*, int); #endif #endif /* _BTREE_H_ */ |
Changes to src/build.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** ** $Id: build.c,v 1.74 2002/02/03 17:37:36 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called after a single SQL statement has been ** parsed and we want to execute the VDBE code to implement |
︙ | ︙ | |||
1394 1395 1396 1397 1398 1399 1400 | } /* ** The non-standard VACUUM command is used to clean up the database, ** collapse free space, etc. It is modelled after the VACUUM command ** in PostgreSQL. ** | | | | > < < < < < < < < < < < < < < < | < < < < < < | 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 | } /* ** The non-standard VACUUM command is used to clean up the database, ** collapse free space, etc. It is modelled after the VACUUM command ** in PostgreSQL. ** ** In version 1.0.x of SQLite, the VACUUM command would call ** gdbm_reorganize() on all the database tables. But beginning ** with 2.0.0, SQLite no longer uses GDBM so this command has ** become a no-op. */ void sqliteVacuum(Parse *pParse, Token *pTableName){ /* Do nothing */ } /* ** Begin a transaction */ void sqliteBeginTransaction(Parse *pParse, int onError){ sqlite *db; |
︙ | ︙ | |||
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 | if( getBoolean(zRight) ){ sqliteParserTrace(stdout, "parser: "); }else{ sqliteParserTrace(0, 0); } }else #endif {} sqliteFree(zLeft); sqliteFree(zRight); } | > > > > > > > > > > > > > > > > > > > > | 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 | if( getBoolean(zRight) ){ sqliteParserTrace(stdout, "parser: "); }else{ sqliteParserTrace(0, 0); } }else #endif #ifndef NDEBUG if( sqliteStrICmp(zLeft, "sanity_check")==0 ){ static VdbeOp checkDb[] = { { OP_SetInsert, 0, 0, "2"}, { OP_Open, 0, 2, 0}, { OP_Rewind, 0, 6, 0}, { OP_Column, 0, 3, 0}, { OP_SetInsert, 0, 0, 0}, { OP_Next, 0, 3, 0}, { OP_SanityCheck, 0, 0, 0}, { OP_ColumnCount, 1, 0, 0}, { OP_ColumnName, 0, 0, "sanity_check"}, { OP_Callback, 1, 0, 0}, }; Vdbe *v = sqliteGetVdbe(pParse); if( v==0 ) return; sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb); }else #endif {} sqliteFree(zLeft); sqliteFree(zRight); } |
Changes to src/parse.y.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** ** @(#) $Id: parse.y,v 1.48 2002/02/03 17:37:36 drh Exp $ */ %token_prefix TK_ %token_type {Token} %default_type {Token} %extra_argument {Parse *pParse} %syntax_error { sqliteSetString(&pParse->zErrMsg,"syntax error",0); |
︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 | ///////////////////////////// The PRAGMA command ///////////////////////////// // cmd ::= PRAGMA ids(X) EQ ids(Y). {sqlitePragma(pParse,&X,&Y,0);} cmd ::= PRAGMA ids(X) EQ ON(Y). {sqlitePragma(pParse,&X,&Y,0);} cmd ::= PRAGMA ids(X) EQ plus_num(Y). {sqlitePragma(pParse,&X,&Y,0);} cmd ::= PRAGMA ids(X) EQ minus_num(Y). {sqlitePragma(pParse,&X,&Y,1);} cmd ::= PRAGMA ids(X) LP ids(Y) RP. {sqlitePragma(pParse,&X,&Y,0);} plus_num(A) ::= plus_opt number(X). {A = X;} minus_num(A) ::= MINUS number(X). {A = X;} number(A) ::= INTEGER(X). {A = X;} number(A) ::= FLOAT(X). {A = X;} plus_opt ::= PLUS. plus_opt ::= . | > | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | ///////////////////////////// The PRAGMA command ///////////////////////////// // cmd ::= PRAGMA ids(X) EQ ids(Y). {sqlitePragma(pParse,&X,&Y,0);} cmd ::= PRAGMA ids(X) EQ ON(Y). {sqlitePragma(pParse,&X,&Y,0);} cmd ::= PRAGMA ids(X) EQ plus_num(Y). {sqlitePragma(pParse,&X,&Y,0);} cmd ::= PRAGMA ids(X) EQ minus_num(Y). {sqlitePragma(pParse,&X,&Y,1);} cmd ::= PRAGMA ids(X) LP ids(Y) RP. {sqlitePragma(pParse,&X,&Y,0);} cmd ::= PRAGMA(Y) ids(X). {sqlitePragma(pParse,&X,&Y,0);} plus_num(A) ::= plus_opt number(X). {A = X;} minus_num(A) ::= MINUS number(X). {A = X;} number(A) ::= INTEGER(X). {A = X;} number(A) ::= FLOAT(X). {A = X;} plus_opt ::= PLUS. plus_opt ::= . |