diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bitvec.c | 208 | ||||
-rw-r--r-- | src/pager.c | 114 | ||||
-rw-r--r-- | src/sqliteInt.h | 9 | ||||
-rw-r--r-- | src/test2.c | 105 |
4 files changed, 368 insertions, 68 deletions
diff --git a/src/bitvec.c b/src/bitvec.c new file mode 100644 index 000000000..23a002c64 --- /dev/null +++ b/src/bitvec.c @@ -0,0 +1,208 @@ +/* +** 2008 February 16 +** +** 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. +** +************************************************************************* +** This file implements an object that represents a fixed-length +** bitmap. Bits are numbered starting with 1. +** +** A bitmap is used to record what pages a database file have been +** journalled during a transaction. Usually only a few pages are +** journalled. So the bitmap is usually sparse and has low cardinality. +** But sometimes (for example when during a DROP of a large table) most +** or all of the pages get journalled. In those cases, the bitmap becomes +** dense. The algorithm needs to handle both cases well. +** +** The size of the bitmap is fixed when the object is created. +** +** All bits are clear when the bitmap is created. Individual bits +** may be set or cleared one at a time. +** +** Test operations are about 100 times more common that set operations. +** Clear operations are exceedingly rare. There are usually between +** 5 and 500 set operations per Bitvec object, though the number of sets can +** sometimes grow into tens of thousands or larger. The size of the +** Bitvec object is the number of pages in the database file at the +** start of a transaction, and is thus usually less than a few thousand, +** but can be as large as 2 billion for a really big database. +** +** @(#) $Id: bitvec.c,v 1.1 2008/02/18 14:47:34 drh Exp $ +*/ +#include "sqliteInt.h" + +#define BITVEC_SZ 512 +#define BITVEC_NCHAR (BITVEC_SZ-12) +#define BITVEC_NBIT (BITVEC_NCHAR*8) +#define BITVEC_NINT ((BITVEC_SZ-12)/4) +#define BITVEC_MXHASH (BITVEC_NINT/2) +#define BITVEC_NPTR ((BITVEC_SZ-12)/8) + +#define BITVEC_HASH(X) (((X)*37)%BITVEC_NINT) + +/* +** A bitmap is an instance of the following structure. +** +** This bitmap records the existance of zero or more bits +** with values between 1 and iSize, inclusive. +** +** There are three possible representations of the bitmap. +** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight +** bitmap. The least significant bit is bit 1. +** +** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is +** a hash table that will hold up to BITVEC_MXHASH distinct values. +** +** Otherwise, the value i is redirected into one of BITVEC_NPTR +** sub-bitmaps pointed to by Bitvec.u.apSub[]. Each subbitmap +** handles up to iDivisor separate values of i. apSub[0] holds +** values between 1 and iDivisor. apSub[1] holds values between +** iDivisor+1 and 2*iDivisor. apSub[N] holds values between +** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized +** to hold deal with values between 1 and iDivisor. +*/ +struct Bitvec { + u32 iSize; /* Maximum bit index */ + u32 nSet; /* Number of bits that are set */ + u32 iDivisor; /* Number of bits handled by each apSub[] entry */ + union { + u8 aBitmap[BITVEC_NCHAR]; /* Bitmap representation */ + u32 aHash[BITVEC_NINT]; /* Hash table representation */ + Bitvec *apSub[BITVEC_NPTR]; /* Recursive representation */ + } u; +}; + +/* +** Create a new bitmap object able to handle bits between 0 and iSize, +** inclusive. Return a pointer to the new object. Return NULL if +** malloc fails. +*/ +Bitvec *sqlite3BitvecCreate(u32 iSize){ + Bitvec *p; + assert( sizeof(*p)==BITVEC_SZ ); + p = sqlite3MallocZero( sizeof(*p) ); + if( p ){ + p->iSize = iSize; + } + return p; +} + +/* +** Check to see if the i-th bit is set. Return true or false. +** If p is NULL (if the bitmap has not been created) or if +** i is out of range, then return false. +*/ +int sqlite3BitvecTest(Bitvec *p, u32 i){ + assert( i>0 ); + if( p==0 ) return 0; + if( i>p->iSize ) return 0; + if( p->iSize<=BITVEC_NBIT ){ + i--; + return (p->u.aBitmap[i/8] & (1<<(i&7)))!=0; + } + if( p->iDivisor>0 ){ + u32 bin = (i-1)/p->iDivisor; + i = (i-1)%p->iDivisor + 1; + return sqlite3BitvecTest(p->u.apSub[bin], i); + }else{ + u32 h = BITVEC_HASH(i); + while( p->u.aHash[h] ){ + if( p->u.aHash[h]==i ) return 1; + h++; + if( h>=BITVEC_NINT ) h = 0; + } + return 0; + } +} + +/* +** Set the i-th bit. Return 0 on success and an error code if +** anything goes wrong. +*/ +int sqlite3BitvecSet(Bitvec *p, u32 i){ + u32 h; + assert( p!=0 ); + if( p->iSize<=BITVEC_NBIT ){ + i--; + p->u.aBitmap[i/8] |= 1 << (i&7); + return SQLITE_OK; + } + if( p->iDivisor ){ + u32 bin = (i-1)/p->iDivisor; + i = (i-1)%p->iDivisor + 1; + if( p->u.apSub[bin]==0 ){ + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1); + p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor ); + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0); + if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM; + } + return sqlite3BitvecSet(p->u.apSub[bin], i); + } + h = BITVEC_HASH(i); + while( p->u.aHash[h] ){ + if( p->u.aHash[h]==i ) return SQLITE_OK; + h++; + if( h==BITVEC_NINT ) h = 0; + } + p->nSet++; + if( p->nSet>=BITVEC_MXHASH ){ + int j, rc; + u32 aiValues[BITVEC_NINT]; + memcpy(aiValues, p->u.aHash, sizeof(aiValues)); + memset(p->u.apSub, 0, sizeof(p->u.apSub[0])*BITVEC_NPTR); + p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR; + sqlite3BitvecSet(p, i); + for(rc=j=0; j<BITVEC_NINT; j++){ + if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]); + } + return rc; + } + p->u.aHash[h] = i; + return SQLITE_OK; +} + +/* +** Clear the i-th bit. Return 0 on success and an error code if +** anything goes wrong. +*/ +void sqlite3BitvecClear(Bitvec *p, u32 i){ + assert( p!=0 ); + if( p->iSize<=BITVEC_NBIT ){ + i--; + p->u.aBitmap[i/8] &= ~(1 << (i&7)); + }else if( p->iDivisor ){ + u32 bin = (i-1)/p->iDivisor; + i = (i-1)%p->iDivisor + 1; + if( p->u.apSub[bin] ){ + sqlite3BitvecClear(p->u.apSub[bin], i); + } + }else{ + int j; + u32 aiValues[BITVEC_NINT]; + memcpy(aiValues, p->u.aHash, sizeof(aiValues)); + memset(p->u.aHash, 0, sizeof(p->u.aHash[0])*BITVEC_NINT); + p->nSet = 0; + for(j=0; j<BITVEC_NINT; j++){ + if( aiValues[j] && aiValues[j]!=i ) sqlite3BitvecSet(p, aiValues[j]); + } + } +} + +/* +** Destroy a bitmap object. Reclaim all memory used. +*/ +void sqlite3BitvecDestroy(Bitvec *p){ + if( p==0 ) return; + if( p->iDivisor ){ + int i; + for(i=0; i<BITVEC_NPTR; i++){ + sqlite3BitvecDestroy(p->u.apSub[i]); + } + } + sqlite3_free(p); +} diff --git a/src/pager.c b/src/pager.c index 7780110ec..80469db9f 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.406 2008/02/14 23:26:56 drh Exp $ +** @(#) $Id: pager.c,v 1.407 2008/02/18 14:47:34 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -213,9 +213,9 @@ struct PagerLruLink { ** has been synced to disk. For pages that are in the original ** database file, the following expression should always be true: ** -** inJournal = (pPager->aInJournal[(pgno-1)/8] & (1<<((pgno-1)%8))!=0 +** inJournal = sqlite3BitvecTest(pPager->pInJournal, pgno) ** -** The pPager->aInJournal[] array is only valid for the original +** The pPager->pInJournal object is only valid for the original ** pages of the database, not new pages that are added to the end ** of the database, so obviously the above expression cannot be ** valid for new pages. For new pages inJournal is always 0. @@ -365,8 +365,8 @@ struct Pager { int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ int mxPage; /* Maximum number of pages to hold in cache */ Pgno mxPgno; /* Maximum allowed size of the database */ - u8 *aInJournal; /* One bit for each page in the database file */ - u8 *aInStmt; /* One bit for each page in the database */ + Bitvec *pInJournal; /* One bit for each page in the database file */ + Bitvec *pInStmt; /* One bit for each page in the database */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ char *zDirectory; /* Directory hold database and journal files */ @@ -666,9 +666,7 @@ static int pageInStatement(PgHdr *pPg){ if( MEMDB ){ return PGHDR_TO_HIST(pPg, pPager)->inStmt; }else{ - Pgno pgno = pPg->pgno; - u8 *a = pPager->aInStmt; - return (a && (int)pgno<=pPager->stmtSize && (a[pgno/8] & (1<<(pgno&7)))); + return sqlite3BitvecTest(pPager->pInStmt, pPg->pgno); } } @@ -1252,14 +1250,14 @@ static void pager_unlock(Pager *pPager){ pager_reset(pPager); if( pPager->stmtOpen ){ sqlite3OsClose(pPager->stfd); - sqlite3_free(pPager->aInStmt); - pPager->aInStmt = 0; + sqlite3BitvecDestroy(pPager->pInStmt); + pPager->pInStmt = 0; } if( pPager->journalOpen ){ sqlite3OsClose(pPager->jfd); pPager->journalOpen = 0; - sqlite3_free(pPager->aInJournal); - pPager->aInJournal = 0; + sqlite3BitvecDestroy(pPager->pInJournal); + pPager->pInJournal = 0; } pPager->stmtOpen = 0; pPager->stmtInUse = 0; @@ -1334,8 +1332,8 @@ static int pager_end_transaction(Pager *pPager){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); } } - sqlite3_free( pPager->aInJournal ); - pPager->aInJournal = 0; + sqlite3BitvecDestroy(pPager->pInJournal); + pPager->pInJournal = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; pPg->dirty = 0; @@ -1349,7 +1347,7 @@ static int pager_end_transaction(Pager *pPager){ pPager->dirtyCache = 0; pPager->nRec = 0; }else{ - assert( pPager->aInJournal==0 ); + assert( pPager->pInJournal==0 ); assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } @@ -2661,7 +2659,7 @@ int sqlite3PagerClose(Pager *pPager){ if( pPager->journalOpen ){ sqlite3OsClose(pPager->jfd); } - sqlite3_free(pPager->aInJournal); + sqlite3BitvecDestroy(pPager->pInJournal); if( pPager->stmtOpen ){ sqlite3OsClose(pPager->stfd); } @@ -3625,17 +3623,8 @@ static int pagerAcquire( pPg->pgno = pgno; assert( !MEMDB || pgno>pPager->stmtSize ); - if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ -#if 0 - sqlite3CheckMemory(pPager->aInJournal, pgno/8); -#endif - assert( pPager->journalOpen ); - pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; - pPg->needSync = 0; - }else{ - pPg->inJournal = 0; - pPg->needSync = 0; - } + pPg->inJournal = sqlite3BitvecTest(pPager->pInJournal, pgno); + pPg->needSync = 0; makeClean(pPg); pPg->nRef = 1; @@ -3801,12 +3790,12 @@ static int pager_open_journal(Pager *pPager){ assert( pPager->state>=PAGER_RESERVED ); assert( pPager->journalOpen==0 ); assert( pPager->useJournal ); - assert( pPager->aInJournal==0 ); + assert( pPager->pInJournal==0 ); sqlite3PagerPagecount(pPager); pagerLeave(pPager); - pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize); pagerEnter(pPager); - if( pPager->aInJournal==0 ){ + if( pPager->pInJournal==0 ){ rc = SQLITE_NOMEM; goto failed_to_open_journal; } @@ -3858,8 +3847,8 @@ static int pager_open_journal(Pager *pPager){ return rc; failed_to_open_journal: - sqlite3_free(pPager->aInJournal); - pPager->aInJournal = 0; + sqlite3BitvecDestroy(pPager->pInJournal); + pPager->pInJournal = 0; return rc; } @@ -3897,7 +3886,7 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ assert( pPg->nRef>0 ); assert( pPager->state!=PAGER_UNLOCK ); if( pPager->state==PAGER_SHARED ){ - assert( pPager->aInJournal==0 ); + assert( pPager->pInJournal==0 ); if( MEMDB ){ pPager->state = PAGER_EXCLUSIVE; pPager->origDbSize = pPager->dbSize; @@ -3927,12 +3916,12 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ */ assert( pPager->nRec==0 ); assert( pPager->origDbSize==0 ); - assert( pPager->aInJournal==0 ); + assert( pPager->pInJournal==0 ); sqlite3PagerPagecount(pPager); pagerLeave(pPager); - pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + pPager->pInJournal = sqlite3BitvecCreate( pPager->dbSize ); pagerEnter(pPager); - if( !pPager->aInJournal ){ + if( !pPager->pInJournal ){ rc = SQLITE_NOMEM; }else{ pPager->origDbSize = pPager->dbSize; @@ -4108,11 +4097,11 @@ static int pager_write(PgHdr *pPg){ } pPager->nRec++; - assert( pPager->aInJournal!=0 ); - pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); + assert( pPager->pInJournal!=0 ); + sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); pPg->needSync = !pPager->noSync; if( pPager->stmtInUse ){ - pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); + sqlite3BitvecSet(pPager->pInStmt, pPg->pgno); } } }else{ @@ -4157,8 +4146,8 @@ static int pager_write(PgHdr *pPg){ return rc; } pPager->stmtNRec++; - assert( pPager->aInStmt!=0 ); - pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); + assert( pPager->pInStmt!=0 ); + sqlite3BitvecSet(pPager->pInStmt, pPg->pgno); } } } @@ -4227,9 +4216,7 @@ int sqlite3PagerWrite(DbPage *pDbPage){ for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){ Pgno pg = pg1+ii; PgHdr *pPage; - if( !pPager->aInJournal || pg==pPg->pgno || - pg>pPager->origDbSize || !(pPager->aInJournal[pg/8]&(1<<(pg&7))) - ) { + if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ if( pg!=PAGER_MJ_PGNO(pPager) ){ rc = sqlite3PagerGet(pPager, pg, &pPage); if( rc==SQLITE_OK ){ @@ -4403,13 +4390,13 @@ void sqlite3PagerDontRollback(DbPage *pPg){ */ assert( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ); - assert( pPager->aInJournal!=0 ); - pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); + assert( pPager->pInJournal!=0 ); + sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); pPg->inJournal = 1; pPg->needRead = 0; if( pPager->stmtInUse ){ assert( pPager->stmtSize <= pPager->origDbSize ); - pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); + sqlite3BitvecSet(pPager->pInStmt, pPg->pgno); } PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager)); IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno)) @@ -4545,7 +4532,7 @@ int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){ Pgno i; int iSkip = PAGER_MJ_PGNO(pPager); for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){ - if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){ + if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){ rc = sqlite3PagerGet(pPager, i, &pPg); if( rc!=SQLITE_OK ) goto sync_exit; rc = sqlite3PagerWrite(pPg); @@ -4803,10 +4790,10 @@ static int pagerStmtBegin(Pager *pPager){ } assert( pPager->journalOpen ); pagerLeave(pPager); - assert( pPager->aInStmt==0 ); - pPager->aInStmt = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + assert( pPager->pInStmt==0 ); + pPager->pInStmt = sqlite3BitvecCreate(pPager->dbSize); pagerEnter(pPager); - if( pPager->aInStmt==0 ){ + if( pPager->pInStmt==0 ){ /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */ return SQLITE_NOMEM; } @@ -4832,9 +4819,9 @@ static int pagerStmtBegin(Pager *pPager){ return SQLITE_OK; stmt_begin_failed: - if( pPager->aInStmt ){ - sqlite3_free(pPager->aInStmt); - pPager->aInStmt = 0; + if( pPager->pInStmt ){ + sqlite3BitvecDestroy(pPager->pInStmt); + pPager->pInStmt = 0; } return rc; } @@ -4856,8 +4843,8 @@ int sqlite3PagerStmtCommit(Pager *pPager){ PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); if( !MEMDB ){ /* sqlite3OsTruncate(pPager->stfd, 0); */ - sqlite3_free( pPager->aInStmt ); - pPager->aInStmt = 0; + sqlite3BitvecDestroy(pPager->pInStmt); + pPager->pInStmt = 0; }else{ for(pPg=pPager->pStmt; pPg; pPg=pNext){ PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); @@ -5027,12 +5014,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){ }else{ pPg->needSync = 0; } - if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ - pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; - }else{ - pPg->inJournal = 0; - assert( pPg->needSync==0 || (int)pgno>pPager->origDbSize ); - } + pPg->inJournal = sqlite3BitvecTest(pPager->pInJournal, pgno); /* Change the page number for pPg and insert it into the new hash-chain. */ assert( pgno!=0 ); @@ -5053,11 +5035,11 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){ /* If needSyncPgno is non-zero, then the journal file needs to be ** sync()ed before any data is written to database file page needSyncPgno. ** Currently, no such page exists in the page-cache and the - ** Pager.aInJournal bit has been set. This needs to be remedied by loading + ** Pager.pInJournal bit has been set. This needs to be remedied by loading ** the page into the pager-cache and setting the PgHdr.needSync flag. ** ** If the attempt to load the page into the page-cache fails, (due - ** to a malloc() or IO failure), clear the bit in the aInJournal[] + ** to a malloc() or IO failure), clear the bit in the pInJournal[] ** array. Otherwise, if the page is loaded and written again in ** this transaction, it may be written to the database file before ** it is synced into the journal file. This way, it may end up in @@ -5071,8 +5053,8 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){ assert( pPager->needSync ); rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr); if( rc!=SQLITE_OK ){ - if( pPager->aInJournal && (int)needSyncPgno<=pPager->origDbSize ){ - pPager->aInJournal[needSyncPgno/8] &= ~(1<<(needSyncPgno&7)); + if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){ + sqlite3BitvecClear(pPager->pInJournal, needSyncPgno); } pagerLeave(pPager); return rc; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 60ac09e9e..e81802ef1 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.662 2008/02/14 23:26:56 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.663 2008/02/18 14:47:34 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -363,6 +363,7 @@ struct BusyHandler { */ typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; +typedef struct Bitvec Bitvec; typedef struct CollSeq CollSeq; typedef struct Column Column; typedef struct Db Db; @@ -1759,6 +1760,12 @@ void sqlite3AddDefaultValue(Parse*,Expr*); void sqlite3AddCollateType(Parse*, Token*); void sqlite3EndTable(Parse*,Token*,Token*,Select*); +Bitvec *sqlite3BitvecCreate(u32); +int sqlite3BitvecTest(Bitvec*, u32); +int sqlite3BitvecSet(Bitvec*, u32); +void sqlite3BitvecClear(Bitvec*, u32); +void sqlite3BitvecDestroy(Bitvec*); + void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) diff --git a/src/test2.c b/src/test2.c index 9b77ff382..4d7031dbc 100644 --- a/src/test2.c +++ b/src/test2.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test2.c,v 1.52 2007/09/03 15:19:35 drh Exp $ +** $Id: test2.c,v 1.53 2008/02/18 14:47:34 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -562,6 +562,104 @@ static int fake_big_file( #endif /* +** sqlite3BitvecCreate SIZE +** sqlite3BitvecTest POINTER N +** sqlite3BitvecSet POINTER N +** sqlite3BitvecClear POINTER N +** sqlite3BitvecDestroy POINTER +*/ +static int testBitvecCreate( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + const char **argv /* Text of each argument */ +){ + int size; + Bitvec *p; + char zBuf[100]; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", + (void*)0); + } + if( Tcl_GetInt(interp, argv[1], &size) ) return TCL_ERROR; + p = sqlite3BitvecCreate(size); + sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",p); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} +static int testBitvecTest( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + const char **argv /* Text of each argument */ +){ + int N; + Bitvec *p; + char zBuf[100]; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"", + (void*)0); + } + p = (Bitvec*)sqlite3TextToPtr(argv[1]); + if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR; + sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3BitvecTest(p,N)); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} +static int testBitvecSet( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + const char **argv /* Text of each argument */ +){ + int N; + Bitvec *p; + char zBuf[100]; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"", + (void*)0); + } + p = (Bitvec*)sqlite3TextToPtr(argv[1]); + if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR; + sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3BitvecSet(p,N)); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} +static int testBitvecClear( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + const char **argv /* Text of each argument */ +){ + int N; + Bitvec *p; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR N\"", + (void*)0); + } + p = (Bitvec*)sqlite3TextToPtr(argv[1]); + if( Tcl_GetInt(interp, argv[2], &N) ) return TCL_ERROR; + sqlite3BitvecClear(p,N); + return TCL_OK; +} +static int testBitvecDestroy( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + const char **argv /* Text of each argument */ +){ + Bitvec *p; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PTR\"", + (void*)0); + } + p = (Bitvec*)sqlite3TextToPtr(argv[1]); + sqlite3BitvecDestroy(p); + return TCL_OK; +} + + +/* ** Register commands with the TCL interpreter. */ int Sqlitetest2_Init(Tcl_Interp *interp){ @@ -594,6 +692,11 @@ int Sqlitetest2_Init(Tcl_Interp *interp){ #ifndef SQLITE_OMIT_DISKIO { "fake_big_file", (Tcl_CmdProc*)fake_big_file }, #endif + { "sqlite3BitvecCreate", (Tcl_CmdProc*)testBitvecCreate }, + { "sqlite3BitvecTest", (Tcl_CmdProc*)testBitvecTest }, + { "sqlite3BitvecSet", (Tcl_CmdProc*)testBitvecSet }, + { "sqlite3BitvecClear", (Tcl_CmdProc*)testBitvecClear }, + { "sqlite3BitvecDestroy", (Tcl_CmdProc*)testBitvecDestroy }, }; int i; for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ |