Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -16,11 +16,11 @@ ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.163 2004/09/08 20:13:05 drh Exp $ +** @(#) $Id: pager.c,v 1.164 2004/09/24 22:32:31 drh Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" #include "pager.h" #include @@ -226,16 +226,16 @@ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ PgHdr *pFirst, *pLast; /* List of free pages */ PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ PgHdr *pAll; /* List of all pages */ PgHdr *pStmt; /* List of pages in the statement subjournal */ - PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */ off_t journalOff; /* Current byte offset in the journal file */ off_t journalHdr; /* Byte offset to previous journal header */ off_t stmtHdrOff; /* First journal header written this statement */ off_t stmtCksum; /* cksumInit when statement was started */ int sectorSize; /* Assumed sector size during rollback */ + PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */ }; /* ** These are bits that can be set in Pager.errMask. */ Index: src/printf.c ================================================================== --- src/printf.c +++ src/printf.c @@ -88,12 +88,12 @@ typedef struct et_info { /* Information about each format field */ char fmttype; /* The format field code letter */ etByte base; /* The base for radix conversion */ etByte flags; /* One or more of FLAG_ constants below */ etByte type; /* Conversion paradigm */ - char *charset; /* The character set for conversion */ - char *prefix; /* Prefix on non-zero values in alt format */ + etByte charset; /* Offset into aDigits[] of the digits string */ + etByte prefix; /* Offset into aPrefix[] of the prefix string */ } et_info; /* ** Allowed values for et_info.flags */ @@ -103,32 +103,34 @@ /* ** The following table is searched linearly, so it is good to put the ** most frequently used conversion types first. */ +static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; +static const char aPrefix[] = "-x0\000X0"; static et_info fmtinfo[] = { - { 'd', 10, 1, etRADIX, "0123456789", 0 }, - { 's', 0, 0, etSTRING, 0, 0 }, - { 'z', 0, 2, etDYNSTRING, 0, 0 }, - { 'q', 0, 0, etSQLESCAPE, 0, 0 }, - { 'Q', 0, 0, etSQLESCAPE2, 0, 0 }, - { 'c', 0, 0, etCHARX, 0, 0 }, - { 'o', 8, 0, etRADIX, "01234567", "0" }, - { 'u', 10, 0, etRADIX, "0123456789", 0 }, - { 'x', 16, 0, etRADIX, "0123456789abcdef", "x0" }, - { 'X', 16, 0, etRADIX, "0123456789ABCDEF", "X0" }, - { 'f', 0, 1, etFLOAT, 0, 0 }, - { 'e', 0, 1, etEXP, "e", 0 }, - { 'E', 0, 1, etEXP, "E", 0 }, - { 'g', 0, 1, etGENERIC, "e", 0 }, - { 'G', 0, 1, etGENERIC, "E", 0 }, - { 'i', 10, 1, etRADIX, "0123456789", 0 }, - { 'n', 0, 0, etSIZE, 0, 0 }, - { '%', 0, 0, etPERCENT, 0, 0 }, - { 'p', 16, 0, etPOINTER, "0123456789abcdef", "x0" }, - { 'T', 0, 2, etTOKEN, 0, 0 }, - { 'S', 0, 2, etSRCLIST, 0, 0 }, + { 'd', 10, 1, etRADIX, 0, 0 }, + { 's', 0, 0, etSTRING, 0, 0 }, + { 'z', 0, 2, etDYNSTRING, 0, 0 }, + { 'q', 0, 0, etSQLESCAPE, 0, 0 }, + { 'Q', 0, 0, etSQLESCAPE2, 0, 0 }, + { 'c', 0, 0, etCHARX, 0, 0 }, + { 'o', 8, 0, etRADIX, 0, 2 }, + { 'u', 10, 0, etRADIX, 0, 0 }, + { 'x', 16, 0, etRADIX, 16, 1 }, + { 'X', 16, 0, etRADIX, 0, 4 }, + { 'f', 0, 1, etFLOAT, 0, 0 }, + { 'e', 0, 1, etEXP, 30, 0 }, + { 'E', 0, 1, etEXP, 14, 0 }, + { 'g', 0, 1, etGENERIC, 30, 0 }, + { 'G', 0, 1, etGENERIC, 14, 0 }, + { 'i', 10, 1, etRADIX, 0, 0 }, + { 'n', 0, 0, etSIZE, 0, 0 }, + { '%', 0, 0, etPERCENT, 0, 0 }, + { 'p', 16, 0, etPOINTER, 0, 1 }, + { 'T', 0, 2, etTOKEN, 0, 0 }, + { 'S', 0, 2, etSRCLIST, 0, 0 }, }; #define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0])) /* ** If NOFLOATINGPOINT is defined, then none of the floating point @@ -375,13 +377,13 @@ if( flag_zeropad && precisioncharset; + cset = &aDigits[infop->charset]; base = infop->base; do{ /* Convert to ascii */ *(--bufpt) = cset[longvalue%base]; longvalue = longvalue/base; }while( longvalue>0 ); @@ -390,14 +392,15 @@ for(idx=precision-length; idx>0; idx--){ *(--bufpt) = '0'; /* Zero pad */ } if( prefix ) *(--bufpt) = prefix; /* Add sign */ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ - char *pre, x; - pre = infop->prefix; + const char *pre; + char x; + pre = &aPrefix[infop->prefix]; if( *bufpt!=pre[0] ){ - for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x; + for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; } } length = &buf[etBUFSIZE-1]-bufpt; break; case etFLOAT: @@ -491,11 +494,11 @@ while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; } bufpt++; /* point to next free slot */ if( exp || flag_exp ){ - *(bufpt++) = infop->charset[0]; + *(bufpt++) = aDigits[infop->charset]; if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ else { *(bufpt++) = '+'; } if( exp>=100 ){ *(bufpt++) = (exp/100)+'0'; /* 100's digit */ exp %= 100; @@ -807,14 +810,15 @@ ** A version of printf() that understands %lld. Used for debugging. ** The printf() built into some versions of windows does not understand %lld ** and segfaults if you give it a long long int. */ void sqlite3DebugPrintf(const char *zFormat, ...){ + extern int getpid(void); va_list ap; char zBuf[500]; va_start(ap, zFormat); base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap); va_end(ap); fprintf(stdout,"%d: %s", getpid(), zBuf); fflush(stdout); } #endif Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -52,10 +52,25 @@ ** Turn tracing on or off */ void sqlite3VdbeTrace(Vdbe *p, FILE *trace){ p->trace = trace; } + +/* +** Resize the Vdbe.aOp array so that it contains at least N +** elements. +*/ +static void resizeOpArray(Vdbe *p, int N){ + if( p->nOpAllocnOpAlloc; + p->nOpAlloc = N+100; + p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); + if( p->aOp ){ + memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); + } + } +} /* ** Add a new instruction to the list of instructions current in the ** VDBE. Return the address of the new instruction. ** @@ -76,28 +91,17 @@ VdbeOp *pOp; i = p->nOp; p->nOp++; assert( p->magic==VDBE_MAGIC_INIT ); - if( i>=p->nOpAlloc ){ - int oldSize = p->nOpAlloc; - Op *aNew; - p->nOpAlloc = p->nOpAlloc*2 + 100; - aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); - if( aNew==0 ){ - p->nOpAlloc = oldSize; - return 0; - } - p->aOp = aNew; - memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); + resizeOpArray(p, i+1); + if( p->aOp==0 ){ + return 0; } pOp = &p->aOp[i]; pOp->opcode = op; pOp->p1 = p1; - if( p2<0 && (-1-p2)nLabel && p->aLabel[-1-p2]>=0 ){ - p2 = p->aLabel[-1-p2]; - } pOp->p2 = p2; pOp->p3 = 0; pOp->p3type = P3_NOTUSED; #ifndef NDEBUG if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]); @@ -131,44 +135,53 @@ int sqlite3VdbeMakeLabel(Vdbe *p){ int i; i = p->nLabel++; assert( p->magic==VDBE_MAGIC_INIT ); if( i>=p->nLabelAlloc ){ - int *aNew; p->nLabelAlloc = p->nLabelAlloc*2 + 10; - aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); - if( aNew==0 ){ - sqliteFree(p->aLabel); - } - p->aLabel = aNew; + p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); } - if( p->aLabel==0 ){ - p->nLabel = 0; - p->nLabelAlloc = 0; - return 0; + if( p->aLabel ){ + p->aLabel[i] = -1; } - p->aLabel[i] = -1; return -1-i; } /* ** Resolve label "x" to be the address of the next instruction to ** be inserted. The parameter "x" must have been obtained from ** a prior call to sqlite3VdbeMakeLabel(). */ void sqlite3VdbeResolveLabel(Vdbe *p, int x){ - int j; + int j = -1-x; assert( p->magic==VDBE_MAGIC_INIT ); - if( x<0 && (-x)<=p->nLabel && p->aOp ){ - if( p->aLabel[-1-x]==p->nOp ) return; - assert( p->aLabel[-1-x]<0 ); - p->aLabel[-1-x] = p->nOp; - for(j=0; jnOp; j++){ - if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp; - } + assert( j>=0 && jnLabel ); + if( p->aLabel ){ + p->aLabel[j] = p->nOp; } } + +/* +** Loop through the program looking for P2 values that are negative. +** Each such value is a label. Resolve the label by setting the P2 +** value to its correct non-zero value. +** +** This routine is called once after all opcodes have been inserted. +*/ +static void resolveP2Values(Vdbe *p){ + int i; + Op *pOp; + int *aLabel = p->aLabel; + if( aLabel==0 ) return; + for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ + if( pOp->p2>=0 ) continue; + assert( -1-pOp->p2nLabel ); + pOp->p2 = aLabel[-1-pOp->p2]; + } + sqliteFree(p->aLabel); + p->aLabel = 0; +} /* ** Return the address of the next instruction to be inserted. */ int sqlite3VdbeCurrentAddr(Vdbe *p){ @@ -181,21 +194,13 @@ ** address of the first operation added. */ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ int addr; assert( p->magic==VDBE_MAGIC_INIT ); - if( p->nOp + nOp >= p->nOpAlloc ){ - int oldSize = p->nOpAlloc; - Op *aNew; - p->nOpAlloc = p->nOpAlloc*2 + nOp + 10; - aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); - if( aNew==0 ){ - p->nOpAlloc = oldSize; - return 0; - } - p->aOp = aNew; - memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); + resizeOpArray(p, p->nOp + nOp); + if( p->aOp==0 ){ + return 0; } addr = p->nOp; if( nOp>0 ){ int i; VdbeOpList const *pIn = aOp; @@ -310,11 +315,11 @@ ** comment text. */ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_list ap; assert( p->nOp>0 ); - assert( p->aOp[p->nOp-1].p3==0 ); + assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 ); va_start(ap, zFormat); sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC); va_end(ap); } #endif @@ -453,10 +458,21 @@ fprintf(pOut, zFormat1, pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3); fflush(pOut); } #endif + +/* +** Release an array of N Mem elements +*/ +static void releaseMemArray(Mem *p, int N){ + if( p ){ + while( N-->0 ){ + sqlite3VdbeMemRelease(p++); + } + } +} /* ** Give a listing of the program in the virtual machine. ** ** The interface is the same as sqlite3VdbeExec(). But instead of @@ -475,14 +491,11 @@ /* Even though this opcode does not put dynamic strings onto the ** the stack, they may become dynamic if the user calls ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. */ if( p->pTos==&p->aStack[4] ){ - for(i=0; i<5; i++){ - sqlite3VdbeMemRelease(&p->aStack[i]); - p->aStack[i].flags = 0; - } + releaseMemArray(p->aStack, 5); } p->resOnStack = 0; i = p->pc++; if( i>=p->nOp ){ @@ -584,10 +597,11 @@ ** on the maximum stack depth required. ** ** Allocation all the stack space we will ever need. */ if( p->aStack==0 ){ + resolveP2Values(p); assert( nVar>=0 ); n = isExplain ? 10 : p->nOp; p->aStack = sqliteMalloc( n*(sizeof(p->aStack[0])+sizeof(Mem*)) /* aStack, apArg */ + nVar*sizeof(Mem) /* aVar */ @@ -844,31 +858,27 @@ ** variables in the aVar[] array. */ static void Cleanup(Vdbe *p){ int i; if( p->aStack ){ - Mem *pTos = p->pTos; - while( pTos>=p->aStack ){ - sqlite3VdbeMemRelease(pTos); - pTos--; - } - p->pTos = pTos; + releaseMemArray(p->aStack, 1 + (p->pTos - p->aStack)); + p->pTos = &p->aStack[-1]; } closeAllCursors(p); - for(i=0; inMem; i++){ - sqlite3VdbeMemRelease(&p->aMem[i]); - } + releaseMemArray(p->aMem, p->nMem); if( p->pList ){ sqlite3VdbeKeylistFree(p->pList); p->pList = 0; } - for(i=0; icontextStackTop; i++){ - sqlite3VdbeKeylistFree(p->contextStack[i].pList); + if( p->contextStack ){ + for(i=0; icontextStackTop; i++){ + sqlite3VdbeKeylistFree(p->contextStack[i].pList); + } + sqliteFree(p->contextStack); } sqlite3VdbeSorterReset(p); sqlite3VdbeAggReset(0, &p->agg, 0); - sqliteFree(p->contextStack); p->contextStack = 0; p->contextStackDepth = 0; p->contextStackTop = 0; sqliteFree(p->zErrMsg); p->zErrMsg = 0; @@ -879,12 +889,20 @@ ** statement. This is now set at compile time, rather than during ** execution of the vdbe program so that sqlite3_column_count() can ** be called on an SQL statement before sqlite3_step(). */ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ + Mem *pColName; + int n; assert( 0==p->nResColumn ); p->nResColumn = nResColumn; + n = nResColumn*2; + p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n ); + if( p->aColName==0 ) return; + while( n-- > 0 ){ + (pColName++)->flags = MEM_Null; + } } /* ** Set the name of the idx'th column to be returned by the SQL statement. ** zName must be a pointer to a nul terminated string. @@ -898,25 +916,12 @@ */ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){ int rc; Mem *pColName; assert( idx<(2*p->nResColumn) ); - - /* If the Vdbe.aColName array has not yet been allocated, allocate - ** it now. - */ - if( !p->aColName ){ - int i; - p->aColName = (Mem *)sqliteMalloc(sizeof(Mem)*p->nResColumn*2); - if( !p->aColName ){ - return SQLITE_NOMEM; - } - for(i=0; i<(2*p->nResColumn); i++){ - p->aColName[i].flags = MEM_Null; - } - } - + if( sqlite3_malloc_failed ) return SQLITE_NOMEM; + assert( p->aColName!=0 ); pColName = &(p->aColName[idx]); if( N==P3_DYNAMIC || N==P3_STATIC ){ rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC); }else{ rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8,SQLITE_TRANSIENT); @@ -1379,38 +1384,29 @@ p->db->pVdbe = p->pNext; } if( p->pNext ){ p->pNext->pPrev = p->pPrev; } - p->pPrev = p->pNext = 0; - if( p->nOpAlloc==0 ){ - p->aOp = 0; - p->nOp = 0; - } - for(i=0; inOp; i++){ - Op *pOp = &p->aOp[i]; - if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){ - sqliteFree(pOp->p3); + if( p->aOp ){ + for(i=0; inOp; i++){ + Op *pOp = &p->aOp[i]; + if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){ + sqliteFree(pOp->p3); + } + if( pOp->p3type==P3_VDBEFUNC ){ + VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3; + sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); + sqliteFree(pVdbeFunc); + } } - if( pOp->p3type==P3_VDBEFUNC ){ - VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3; - sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); - sqliteFree(pVdbeFunc); - } + sqliteFree(p->aOp); } - for(i=0; inVar; i++){ - sqlite3VdbeMemRelease(&p->aVar[i]); - } - sqliteFree(p->aOp); + releaseMemArray(p->aVar, p->nVar); sqliteFree(p->aLabel); sqliteFree(p->aStack); - if( p->aColName ){ - for(i=0; i<(p->nResColumn)*2; i++){ - sqlite3VdbeMemRelease(&(p->aColName[i])); - } - sqliteFree(p->aColName); - } + releaseMemArray(p->aColName, p->nResColumn*2); + sqliteFree(p->aColName); p->magic = VDBE_MAGIC_DEAD; sqliteFree(p); } /*