Update bundled libsqlite3 to version 3.2.7

This commit is contained in:
Ilia Alshanetsky 2005-09-26 19:31:41 +00:00
parent 74c7eb7723
commit 94d1e56360
40 changed files with 4884 additions and 4207 deletions

View file

@ -1 +1 @@
3.2.5 3.2.7

View file

@ -88,8 +88,8 @@ static void analyzeOneTable(
int addr; /* The address of an instruction */ int addr; /* The address of an instruction */
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
if( pTab==0 || pTab->pIndex==0 || pTab->pIndex->pNext==0 ){ if( pTab==0 || pTab->pIndex==0 ){
/* Do no analysis for tables with fewer than 2 indices */ /* Do no analysis for tables that have no indices */
return; return;
} }
@ -127,13 +127,11 @@ static void analyzeOneTable(
** Cells iMem through iMem+nCol are initialized to 0. The others ** Cells iMem through iMem+nCol are initialized to 0. The others
** are initialized to NULL. ** are initialized to NULL.
*/ */
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
for(i=0; i<=nCol; i++){ for(i=0; i<=nCol; i++){
sqlite3VdbeAddOp(v, OP_MemStore, iMem+i, i==nCol); sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i);
} }
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, i==nCol-1); sqlite3VdbeAddOp(v, OP_MemNull, iMem+nCol+i+1, 0);
} }
/* Do the analysis. /* Do the analysis.
@ -198,7 +196,7 @@ static void analyzeOneTable(
} }
sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "ttt", 0); sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "ttt", 0);
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0); sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, addr);
} }
} }
@ -333,7 +331,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){
const char *z; const char *z;
assert( argc==2 ); assert( argc==2 );
if( argv[0]==0 || argv[1]==0 ){ if( argv==0 || argv[0]==0 || argv[1]==0 ){
return 0; return 0;
} }
pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase); pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase);

View file

@ -494,7 +494,7 @@ static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){
assert( pBt->autoVacuum ); assert( pBt->autoVacuum );
if( key==0 ){ if( key==0 ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key); iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap); rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
@ -540,7 +540,7 @@ static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
sqlite3pager_unref(pPtrmap); sqlite3pager_unref(pPtrmap);
if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT; if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
return SQLITE_OK; return SQLITE_OK;
} }
@ -1030,7 +1030,7 @@ static int initPage(
assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] ); assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){ if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
/* The parent page should never change unless the file is corrupt */ /* The parent page should never change unless the file is corrupt */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
if( pPage->isInit ) return SQLITE_OK; if( pPage->isInit ) return SQLITE_OK;
if( pPage->pParent==0 && pParent!=0 ){ if( pPage->pParent==0 && pParent!=0 ){
@ -1048,11 +1048,11 @@ static int initPage(
pPage->nCell = get2byte(&data[hdr+3]); pPage->nCell = get2byte(&data[hdr+3]);
if( pPage->nCell>MX_CELL(pBt) ){ if( pPage->nCell>MX_CELL(pBt) ){
/* To many cells for a single page. The page must be corrupt */ /* To many cells for a single page. The page must be corrupt */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){ if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){
/* All pages must have at least one cell, except for root pages */ /* All pages must have at least one cell, except for root pages */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
/* Compute the total free space on the page */ /* Compute the total free space on the page */
@ -1062,13 +1062,13 @@ static int initPage(
int next, size; int next, size;
if( pc>usableSize-4 ){ if( pc>usableSize-4 ){
/* Free block is off the page */ /* Free block is off the page */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
next = get2byte(&data[pc]); next = get2byte(&data[pc]);
size = get2byte(&data[pc+2]); size = get2byte(&data[pc+2]);
if( next>0 && next<=pc+size+3 ){ if( next>0 && next<=pc+size+3 ){
/* Free blocks must be in accending order */ /* Free blocks must be in accending order */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
nFree += size; nFree += size;
pc = next; pc = next;
@ -1076,7 +1076,7 @@ static int initPage(
pPage->nFree = nFree; pPage->nFree = nFree;
if( nFree>=usableSize ){ if( nFree>=usableSize ){
/* Free space cannot exceed total page size */ /* Free space cannot exceed total page size */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
pPage->isInit = 1; pPage->isInit = 1;
@ -1146,7 +1146,7 @@ static int getAndInitPage(
){ ){
int rc; int rc;
if( pgno==0 ){ if( pgno==0 ){
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
rc = getPage(pBt, pgno, ppPage); rc = getPage(pBt, pgno, ppPage);
if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){ if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
@ -1714,7 +1714,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
if( eType==PTRMAP_OVERFLOW2 ){ if( eType==PTRMAP_OVERFLOW2 ){
/* The pointer is always the first 4 bytes of the page in this case. */ /* The pointer is always the first 4 bytes of the page in this case. */
if( get4byte(pPage->aData)!=iFrom ){ if( get4byte(pPage->aData)!=iFrom ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
put4byte(pPage->aData, iTo); put4byte(pPage->aData, iTo);
}else{ }else{
@ -1747,7 +1747,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
if( i==nCell ){ if( i==nCell ){
if( eType!=PTRMAP_BTREE || if( eType!=PTRMAP_BTREE ||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
} }
@ -1860,7 +1860,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
assert( pBt->autoVacuum ); assert( pBt->autoVacuum );
if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){ if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
/* Figure out how many free-pages are in the database. If there are no /* Figure out how many free-pages are in the database. If there are no
@ -1875,7 +1875,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
origSize = sqlite3pager_pagecount(pPager); origSize = sqlite3pager_pagecount(pPager);
nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5); nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
finSize = origSize - nFreeList - nPtrMap; finSize = origSize - nFreeList - nPtrMap;
if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){ if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
finSize--; finSize--;
if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){ if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
finSize--; finSize--;
@ -1898,7 +1898,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage); rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage);
if( rc!=SQLITE_OK ) goto autovacuum_out; if( rc!=SQLITE_OK ) goto autovacuum_out;
if( eType==PTRMAP_ROOTPAGE ){ if( eType==PTRMAP_ROOTPAGE ){
rc = SQLITE_CORRUPT; rc = SQLITE_CORRUPT_BKPT;
goto autovacuum_out; goto autovacuum_out;
} }
@ -2414,7 +2414,7 @@ static int getPayload(
} }
if( amt>0 ){ if( amt>0 ){
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
return SQLITE_OK; return SQLITE_OK;
} }
@ -2432,7 +2432,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( pCur->isValid ); assert( pCur->isValid );
assert( pCur->pPage!=0 ); assert( pCur->pPage!=0 );
if( pCur->pPage->intKey ){ if( pCur->pPage->intKey ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
assert( pCur->pPage->intKey==0 ); assert( pCur->pPage->intKey==0 );
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
@ -2481,13 +2481,11 @@ static const unsigned char *fetchPayload(
){ ){
unsigned char *aPayload; unsigned char *aPayload;
MemPage *pPage; MemPage *pPage;
Btree *pBt;
u32 nKey; u32 nKey;
int nLocal; int nLocal;
assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur!=0 && pCur->pPage!=0 );
assert( pCur->isValid ); assert( pCur->isValid );
pBt = pCur->pBt;
pPage = pCur->pPage; pPage = pCur->pPage;
pageIntegrity(pPage); pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
@ -2554,7 +2552,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
pCur->idx = 0; pCur->idx = 0;
pCur->info.nSize = 0; pCur->info.nSize = 0;
if( pNewPage->nCell<1 ){ if( pNewPage->nCell<1 ){
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
return SQLITE_OK; return SQLITE_OK;
} }
@ -2585,7 +2583,6 @@ static int isRootPage(MemPage *pPage){
** the largest cell index. ** the largest cell index.
*/ */
static void moveToParent(BtCursor *pCur){ static void moveToParent(BtCursor *pCur){
Pgno oldPgno;
MemPage *pParent; MemPage *pParent;
MemPage *pPage; MemPage *pPage;
int idxParent; int idxParent;
@ -2600,7 +2597,6 @@ static void moveToParent(BtCursor *pCur){
pageIntegrity(pParent); pageIntegrity(pParent);
idxParent = pPage->idxParent; idxParent = pPage->idxParent;
sqlite3pager_ref(pParent->aData); sqlite3pager_ref(pParent->aData);
oldPgno = pPage->pgno;
releasePage(pPage); releasePage(pPage);
pCur->pPage = pParent; pCur->pPage = pParent;
pCur->info.nSize = 0; pCur->info.nSize = 0;
@ -2765,7 +2761,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
lwr = 0; lwr = 0;
upr = pPage->nCell-1; upr = pPage->nCell-1;
if( !pPage->intKey && pKey==0 ){ if( !pPage->intKey && pKey==0 ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
pageIntegrity(pPage); pageIntegrity(pPage);
while( lwr<=upr ){ while( lwr<=upr ){
@ -3050,7 +3046,7 @@ static int allocatePage(
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>pBt->usableSize/4 - 8 ){ }else if( k>pBt->usableSize/4 - 8 ){
/* Value of k is out of range. Database corruption */ /* Value of k is out of range. Database corruption */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
}else if( searchList && nearby==iTrunk ){ }else if( searchList && nearby==iTrunk ){
/* The list is being searched and this trunk page is the page /* The list is being searched and this trunk page is the page
@ -3125,7 +3121,7 @@ static int allocatePage(
*pPgno = iPage; *pPgno = iPage;
if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){ if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){
/* Free page off the end of the file */ /* Free page off the end of the file */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */ return SQLITE_CORRUPT_BKPT;
} }
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
": %d more free pages\n", ": %d more free pages\n",
@ -3266,7 +3262,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
while( ovflPgno!=0 ){ while( ovflPgno!=0 ){
MemPage *pOvfl; MemPage *pOvfl;
if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){ if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
rc = getPage(pBt, ovflPgno, &pOvfl); rc = getPage(pBt, ovflPgno, &pOvfl);
if( rc ) return rc; if( rc ) return rc;
@ -4672,7 +4668,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
rc = sqlite3BtreeNext(&leafCur, &notUsed); rc = sqlite3BtreeNext(&leafCur, &notUsed);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
if( rc!=SQLITE_NOMEM ){ if( rc!=SQLITE_NOMEM ){
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */ rc = SQLITE_CORRUPT_BKPT;
} }
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@ -4858,7 +4854,7 @@ static int clearDatabasePage(
int i; int i;
if( pgno>sqlite3pager_pagecount(pBt->pPager) ){ if( pgno>sqlite3pager_pagecount(pBt->pPager) ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
rc = getAndInitPage(pBt, pgno, &pPage, pParent); rc = getAndInitPage(pBt, pgno, &pPage, pParent);
@ -5480,7 +5476,7 @@ static int checkTreePage(
u8 *data; u8 *data;
BtCursor cur; BtCursor cur;
Btree *pBt; Btree *pBt;
int maxLocal, usableSize; int usableSize;
char zContext[100]; char zContext[100];
char *hit; char *hit;
@ -5497,7 +5493,6 @@ static int checkTreePage(
"unable to get the page. error code=%d", rc); "unable to get the page. error code=%d", rc);
return 0; return 0;
} }
maxLocal = pPage->leafData ? pBt->maxLeaf : pBt->maxLocal;
if( (rc = initPage(pPage, pParent))!=0 ){ if( (rc = initPage(pPage, pParent))!=0 ){
checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc); checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc);
releasePage(pPage); releasePage(pPage);
@ -5744,7 +5739,7 @@ const char *sqlite3BtreeGetJournalname(Btree *pBt){
*/ */
int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
int rc = SQLITE_OK; int rc = SQLITE_OK;
Pgno i, nPage, nToPage; Pgno i, nPage, nToPage, iSkip;
if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){ if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){
return SQLITE_ERROR; return SQLITE_ERROR;
@ -5752,8 +5747,10 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
if( pBtTo->pCursor ) return SQLITE_BUSY; if( pBtTo->pCursor ) return SQLITE_BUSY;
nToPage = sqlite3pager_pagecount(pBtTo->pPager); nToPage = sqlite3pager_pagecount(pBtTo->pPager);
nPage = sqlite3pager_pagecount(pBtFrom->pPager); nPage = sqlite3pager_pagecount(pBtFrom->pPager);
iSkip = PENDING_BYTE_PAGE(pBtTo);
for(i=1; rc==SQLITE_OK && i<=nPage; i++){ for(i=1; rc==SQLITE_OK && i<=nPage; i++){
void *pPage; void *pPage;
if( i==iSkip ) continue;
rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage); rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
if( rc ) break; if( rc ) break;
rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage); rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
@ -5762,6 +5759,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
} }
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
void *pPage; void *pPage;
if( i==iSkip ) continue;
rc = sqlite3pager_get(pBtTo->pPager, i, &pPage); rc = sqlite3pager_get(pBtTo->pPager, i, &pPage);
if( rc ) break; if( rc ) break;
rc = sqlite3pager_write(pPage); rc = sqlite3pager_write(pPage);

View file

@ -76,7 +76,7 @@ void sqlite3FinishCoding(Parse *pParse){
if( pParse->cookieGoto>0 ){ if( pParse->cookieGoto>0 ){
u32 mask; u32 mask;
int iDb; int iDb;
sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){ for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
if( (mask & pParse->cookieMask)==0 ) continue; if( (mask & pParse->cookieMask)==0 ) continue;
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
@ -85,6 +85,7 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto); sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
} }
#ifndef SQLITE_OMIT_TRACE
/* Add a No-op that contains the complete text of the compiled SQL /* Add a No-op that contains the complete text of the compiled SQL
** statement as its P3 argument. This does not change the functionality ** statement as its P3 argument. This does not change the functionality
** of the program. ** of the program.
@ -92,6 +93,7 @@ void sqlite3FinishCoding(Parse *pParse){
** This is used to implement sqlite3_trace(). ** This is used to implement sqlite3_trace().
*/ */
sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql); sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql);
#endif /* SQLITE_OMIT_TRACE */
} }
@ -101,7 +103,7 @@ void sqlite3FinishCoding(Parse *pParse){
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqlite3VdbeTrace(v, trace); sqlite3VdbeTrace(v, trace);
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3, sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
pParse->nTab+3, pParse->nMaxDepth+1, pParse->explain); pParse->nTab+3, pParse->explain);
pParse->rc = SQLITE_DONE; pParse->rc = SQLITE_DONE;
pParse->colNamesSet = 0; pParse->colNamesSet = 0;
}else if( pParse->rc==SQLITE_OK ){ }else if( pParse->rc==SQLITE_OK ){
@ -130,7 +132,6 @@ void sqlite3FinishCoding(Parse *pParse){
void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
va_list ap; va_list ap;
char *zSql; char *zSql;
int rc;
# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar)) # define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar))
char saveBuf[SAVE_SZ]; char saveBuf[SAVE_SZ];
@ -145,7 +146,7 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
pParse->nested++; pParse->nested++;
memcpy(saveBuf, &pParse->nVar, SAVE_SZ); memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
memset(&pParse->nVar, 0, SAVE_SZ); memset(&pParse->nVar, 0, SAVE_SZ);
rc = sqlite3RunParser(pParse, zSql, 0); sqlite3RunParser(pParse, zSql, 0);
sqliteFree(zSql); sqliteFree(zSql);
memcpy(&pParse->nVar, saveBuf, SAVE_SZ); memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
pParse->nested--; pParse->nested--;
@ -634,7 +635,6 @@ void sqlite3StartTable(
int isView /* True if this is a VIEW */ int isView /* True if this is a VIEW */
){ ){
Table *pTable; Table *pTable;
Index *pIdx;
char *zName = 0; /* The name of the new table */ char *zName = 0; /* The name of the new table */
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
Vdbe *v; Vdbe *v;
@ -713,8 +713,7 @@ void sqlite3StartTable(
sqlite3ErrorMsg(pParse, "table %T already exists", pName); sqlite3ErrorMsg(pParse, "table %T already exists", pName);
goto begin_table_error; goto begin_table_error;
} }
if( (pIdx = sqlite3FindIndex(db, zName, 0))!=0 && if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
( iDb==0 || !db->init.busy) ){
sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
goto begin_table_error; goto begin_table_error;
} }
@ -941,7 +940,7 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){
i = p->nCol-1; i = p->nCol-1;
if( i<0 ) return; if( i<0 ) return;
pCol = &p->aCol[i]; pCol = &p->aCol[i];
assert( pCol->zType==0 ); sqliteFree(pCol->zType);
pCol->zType = sqlite3NameFromToken(pType); pCol->zType = sqlite3NameFromToken(pType);
pCol->affinity = sqlite3AffinityType(pType); pCol->affinity = sqlite3AffinityType(pType);
} }
@ -1016,7 +1015,9 @@ void sqlite3AddPrimaryKey(
break; break;
} }
} }
if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1; if( iCol<pTab->nCol ){
pTab->aCol[iCol].isPrimKey = 1;
}
} }
if( pList->nExpr>1 ) iCol = -1; if( pList->nExpr>1 ) iCol = -1;
} }
@ -2001,7 +2002,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
} }
sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0); sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0);
sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1); sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
sqlite3VdbeChangeP2(v, addr1, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp(v, OP_Close, iTab, 0); sqlite3VdbeAddOp(v, OP_Close, iTab, 0);
sqlite3VdbeAddOp(v, OP_Close, iIdx, 0); sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);
} }
@ -2114,14 +2115,12 @@ void sqlite3CreateIndex(
goto exit_create_index; goto exit_create_index;
} }
if( !db->init.busy ){ if( !db->init.busy ){
Index *pISameName; /* Another index with the same name */
Table *pTSameName; /* A table with same name as the index */
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){ if( sqlite3FindIndex(db, zName, db->aDb[iDb].zName)!=0 ){
sqlite3ErrorMsg(pParse, "index %s already exists", zName); sqlite3ErrorMsg(pParse, "index %s already exists", zName);
goto exit_create_index; goto exit_create_index;
} }
if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){ if( sqlite3FindTable(db, zName, 0)!=0 ){
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
goto exit_create_index; goto exit_create_index;
} }
@ -2171,7 +2170,7 @@ void sqlite3CreateIndex(
(sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr ); (sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr );
if( sqlite3_malloc_failed ) goto exit_create_index; if( sqlite3_malloc_failed ) goto exit_create_index;
pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr]; pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
pIndex->aiRowEst = &pIndex->aiColumn[pList->nExpr]; pIndex->aiRowEst = (unsigned*)&pIndex->aiColumn[pList->nExpr];
pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1]; pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1];
strcpy(pIndex->zName, zName); strcpy(pIndex->zName, zName);
pIndex->pTable = pTab; pIndex->pTable = pTab;
@ -2394,7 +2393,7 @@ exit_create_index:
** are based on typical values found in actual indices. ** are based on typical values found in actual indices.
*/ */
void sqlite3DefaultRowEst(Index *pIdx){ void sqlite3DefaultRowEst(Index *pIdx){
int *a = pIdx->aiRowEst; unsigned *a = pIdx->aiRowEst;
int i; int i;
assert( a!=0 ); assert( a!=0 );
a[0] = 1000000; a[0] = 1000000;
@ -2467,6 +2466,47 @@ exit_drop_index:
sqlite3SrcListDelete(pName); sqlite3SrcListDelete(pName);
} }
/*
** ppArray points into a structure where there is an array pointer
** followed by two integers. The first integer is the
** number of elements in the structure array. The second integer
** is the number of allocated slots in the array.
**
** In other words, the structure looks something like this:
**
** struct Example1 {
** struct subElem *aEntry;
** int nEntry;
** int nAlloc;
** }
**
** The pnEntry parameter points to the equivalent of Example1.nEntry.
**
** This routine allocates a new slot in the array, zeros it out,
** and returns its index. If malloc fails a negative number is returned.
**
** szEntry is the sizeof of a single array entry. initSize is the
** number of array entries allocated on the initial allocation.
*/
int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){
char *p;
int *an = (int*)&ppArray[1];
if( an[0]>=an[1] ){
void *pNew;
int newSize;
newSize = an[1]*2 + initSize;
pNew = sqliteRealloc(*ppArray, newSize*szEntry);
if( pNew==0 ){
return -1;
}
an[1] = newSize;
*ppArray = pNew;
}
p = *ppArray;
memset(&p[an[0]*szEntry], 0, szEntry);
return an[0]++;
}
/* /*
** Append a new element to the given IdList. Create a new IdList if ** Append a new element to the given IdList. Create a new IdList if
** need be. ** need be.
@ -2474,24 +2514,18 @@ exit_drop_index:
** A new IdList is returned, or NULL if malloc() fails. ** A new IdList is returned, or NULL if malloc() fails.
*/ */
IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){ IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
int i;
if( pList==0 ){ if( pList==0 ){
pList = sqliteMalloc( sizeof(IdList) ); pList = sqliteMalloc( sizeof(IdList) );
if( pList==0 ) return 0; if( pList==0 ) return 0;
pList->nAlloc = 0; pList->nAlloc = 0;
} }
if( pList->nId>=pList->nAlloc ){ i = sqlite3ArrayAllocate((void**)&pList->a, sizeof(pList->a[0]), 5);
struct IdList_item *a; if( i<0 ){
pList->nAlloc = pList->nAlloc*2 + 5;
a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]) );
if( a==0 ){
sqlite3IdListDelete(pList); sqlite3IdListDelete(pList);
return 0; return 0;
} }
pList->a = a; pList->a[i].zName = sqlite3NameFromToken(pToken);
}
memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
pList->a[pList->nId].zName = sqlite3NameFromToken(pToken);
pList->nId++;
return pList; return pList;
} }

View file

@ -178,12 +178,12 @@ void sqlite3DeleteFrom(
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb); sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
/* If we are trying to delete from a view, construct that view into /* If we are trying to delete from a view, realize that view into
** a temporary table. ** a ephemeral table.
*/ */
if( isView ){ if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect); Select *pView = sqlite3SelectDup(pTab->pSelect);
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0); sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView); sqlite3SelectDelete(pView);
} }
@ -380,7 +380,7 @@ void sqlite3GenerateRowDelete(
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0); addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0); sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, addr);
} }
/* /*

View file

@ -355,7 +355,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
pExpr->iTable = ++pParse->nVar; pExpr->iTable = ++pParse->nVar;
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){ if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10; pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
pParse->apVarExpr = sqliteRealloc(pParse->apVarExpr, sqlite3ReallocOrFree((void**)&pParse->apVarExpr,
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) ); pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
} }
if( !sqlite3_malloc_failed ){ if( !sqlite3_malloc_failed ){
@ -546,9 +546,14 @@ Select *sqlite3SelectDup(Select *p){
pNew->pOffset = sqlite3ExprDup(p->pOffset); pNew->pOffset = sqlite3ExprDup(p->pOffset);
pNew->iLimit = -1; pNew->iLimit = -1;
pNew->iOffset = -1; pNew->iOffset = -1;
pNew->ppOpenVirtual = 0;
pNew->isResolved = p->isResolved; pNew->isResolved = p->isResolved;
pNew->isAgg = p->isAgg; pNew->isAgg = p->isAgg;
pNew->usesVirt = 0;
pNew->disallowOrderBy = 0;
pNew->pRightmost = 0;
pNew->addrOpenVirt[0] = -1;
pNew->addrOpenVirt[1] = -1;
pNew->addrOpenVirt[2] = -1;
return pNew; return pNew;
} }
#else #else
@ -692,6 +697,7 @@ static int exprNodeIsConstant(void *pArg, Expr *pExpr){
case TK_COLUMN: case TK_COLUMN:
case TK_DOT: case TK_DOT:
case TK_AGG_FUNCTION: case TK_AGG_FUNCTION:
case TK_AGG_COLUMN:
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
case TK_SELECT: case TK_SELECT:
case TK_EXISTS: case TK_EXISTS:
@ -1227,11 +1233,19 @@ int sqlite3ExprResolveNames(
NameContext *pNC, /* Namespace to resolve expressions in. */ NameContext *pNC, /* Namespace to resolve expressions in. */
Expr *pExpr /* The expression to be analyzed. */ Expr *pExpr /* The expression to be analyzed. */
){ ){
int savedHasAgg;
if( pExpr==0 ) return 0; if( pExpr==0 ) return 0;
savedHasAgg = pNC->hasAgg;
pNC->hasAgg = 0;
walkExprTree(pExpr, nameResolverStep, pNC); walkExprTree(pExpr, nameResolverStep, pNC);
if( pNC->nErr>0 ){ if( pNC->nErr>0 ){
ExprSetProperty(pExpr, EP_Error); ExprSetProperty(pExpr, EP_Error);
} }
if( pNC->hasAgg ){
ExprSetProperty(pExpr, EP_Agg);
}else if( savedHasAgg ){
pNC->hasAgg = 1;
}
return ExprHasProperty(pExpr, EP_Error); return ExprHasProperty(pExpr, EP_Error);
} }
@ -1279,13 +1293,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
int mem = pParse->nMem++; int mem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
assert( testAddr>0 ); assert( testAddr>0 || sqlite3_malloc_failed );
sqlite3VdbeAddOp(v, OP_Integer, 1, 0); sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
sqlite3VdbeAddOp(v, OP_MemStore, mem, 1);
}
if( pExpr->pSelect ){
sqlite3VdbeAddOp(v, OP_AggContextPush, 0, 0);
} }
switch( pExpr->op ){ switch( pExpr->op ){
@ -1359,7 +1368,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){ if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1); VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
int i; int i;
for(i=0; i<4; i++){ for(i=0; i<3; i++){
aOp[i].opcode = OP_Noop; aOp[i].opcode = OP_Noop;
} }
testAddr = 0; testAddr = 0;
@ -1400,11 +1409,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
} }
} }
if( pExpr->pSelect ){
sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0);
}
if( testAddr ){ if( testAddr ){
sqlite3VdbeChangeP2(v, testAddr, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, testAddr);
} }
return; return;
} }
@ -1445,10 +1451,21 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
} }
op = pExpr->op; op = pExpr->op;
switch( op ){ switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
sqlite3VdbeAddOp(v, OP_MemLoad, pCol->iMem, 0);
break;
}else if( pAggInfo->useSortingIdx ){
sqlite3VdbeAddOp(v, OP_Column, pAggInfo->sortingIdx,
pCol->iSorterColumn);
break;
}
/* Otherwise, fall thru into the TK_COLUMN case */
}
case TK_COLUMN: { case TK_COLUMN: {
if( !pParse->fillAgg && pExpr->iAgg>=0 ){ if( pExpr->iColumn>=0 ){
sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg);
}else if( pExpr->iColumn>=0 ){
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn); sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn); sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
}else{ }else{
@ -1597,7 +1614,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
break; break;
} }
case TK_AGG_FUNCTION: { case TK_AGG_FUNCTION: {
sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); AggInfo *pInfo = pExpr->pAggInfo;
sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
break; break;
} }
case TK_CONST_FUNC: case TK_CONST_FUNC:
@ -1607,7 +1625,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
FuncDef *pDef; FuncDef *pDef;
int nId; int nId;
const char *zId; const char *zId;
int p2 = 0; int constMask = 0;
int i; int i;
u8 enc = pParse->db->enc; u8 enc = pParse->db->enc;
CollSeq *pColl = 0; CollSeq *pColl = 0;
@ -1618,7 +1636,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
nExpr = sqlite3ExprCodeExprList(pParse, pList); nExpr = sqlite3ExprCodeExprList(pParse, pList);
for(i=0; i<nExpr && i<32; i++){ for(i=0; i<nExpr && i<32; i++){
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){ if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
p2 |= (1<<i); constMask |= (1<<i);
} }
if( pDef->needCollSeq && !pColl ){ if( pDef->needCollSeq && !pColl ){
pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
@ -1628,7 +1646,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
if( !pColl ) pColl = pParse->db->pDfltColl; if( !pColl ) pColl = pParse->db->pDfltColl;
sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
} }
sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF); sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF);
break; break;
} }
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
@ -1692,7 +1710,6 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_CASE: { case TK_CASE: {
int expr_end_label; int expr_end_label;
int jumpInst; int jumpInst;
int addr;
int nExpr; int nExpr;
int i; int i;
ExprList *pEList; ExprList *pEList;
@ -1720,8 +1737,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
} }
sqlite3ExprCode(pParse, aListelem[i+1].pExpr); sqlite3ExprCode(pParse, aListelem[i+1].pExpr);
sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label); sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label);
addr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeJumpHere(v, jumpInst);
sqlite3VdbeChangeP2(v, jumpInst, addr);
} }
if( pExpr->pLeft ){ if( pExpr->pLeft ){
sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
@ -1888,7 +1904,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull); codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull);
sqlite3VdbeAddOp(v, OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
break; break;
} }
@ -2021,6 +2037,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
return 0; return 0;
} }
if( pA->op!=pB->op ) return 0; if( pA->op!=pB->op ) return 0;
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0; if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0; if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
if( pA->pList ){ if( pA->pList ){
@ -2044,22 +2061,31 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
return 1; return 1;
} }
/* /*
** Add a new element to the pParse->aAgg[] array and return its index. ** Add a new element to the pAggInfo->aCol[] array. Return the index of
** The new element is initialized to zero. The calling function is ** the new element. Return a negative number if malloc fails.
** expected to fill it in.
*/ */
static int appendAggInfo(Parse *pParse){ static int addAggInfoColumn(AggInfo *pInfo){
if( (pParse->nAgg & 0x7)==0 ){ int i;
int amt = pParse->nAgg + 8; i = sqlite3ArrayAllocate((void**)&pInfo->aCol, sizeof(pInfo->aCol[0]), 3);
AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0])); if( i<0 ){
if( aAgg==0 ){
return -1; return -1;
} }
pParse->aAgg = aAgg; return i;
} }
memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0]));
return pParse->nAgg++; /*
** Add a new element to the pAggInfo->aFunc[] array. Return the index of
** the new element. Return a negative number if malloc fails.
*/
static int addAggInfoFunc(AggInfo *pInfo){
int i;
i = sqlite3ArrayAllocate((void**)&pInfo->aFunc, sizeof(pInfo->aFunc[0]), 2);
if( i<0 ){
return -1;
}
return i;
} }
/* /*
@ -2071,60 +2097,118 @@ static int appendAggInfo(Parse *pParse){
*/ */
static int analyzeAggregate(void *pArg, Expr *pExpr){ static int analyzeAggregate(void *pArg, Expr *pExpr){
int i; int i;
AggExpr *aAgg;
NameContext *pNC = (NameContext *)pArg; NameContext *pNC = (NameContext *)pArg;
Parse *pParse = pNC->pParse; Parse *pParse = pNC->pParse;
SrcList *pSrcList = pNC->pSrcList; SrcList *pSrcList = pNC->pSrcList;
AggInfo *pAggInfo = pNC->pAggInfo;
switch( pExpr->op ){ switch( pExpr->op ){
case TK_COLUMN: { case TK_COLUMN: {
for(i=0; pSrcList && i<pSrcList->nSrc; i++){ /* Check to see if the column is in one of the tables in the FROM
if( pExpr->iTable==pSrcList->a[i].iCursor ){ ** clause of the aggregate query */
aAgg = pParse->aAgg; if( pSrcList ){
for(i=0; i<pParse->nAgg; i++){ struct SrcList_item *pItem = pSrcList->a;
if( aAgg[i].isAgg ) continue; for(i=0; i<pSrcList->nSrc; i++, pItem++){
if( aAgg[i].pExpr->iTable==pExpr->iTable struct AggInfo_col *pCol;
&& aAgg[i].pExpr->iColumn==pExpr->iColumn ){ if( pExpr->iTable==pItem->iCursor ){
/* If we reach this point, it means that pExpr refers to a table
** that is in the FROM clause of the aggregate query.
**
** Make an entry for the column in pAggInfo->aCol[] if there
** is not an entry there already.
*/
pCol = pAggInfo->aCol;
for(i=0; i<pAggInfo->nColumn; i++, pCol++){
if( pCol->iTable==pExpr->iTable &&
pCol->iColumn==pExpr->iColumn ){
break; break;
} }
} }
if( i>=pParse->nAgg ){ if( i>=pAggInfo->nColumn && (i = addAggInfoColumn(pAggInfo))>=0 ){
i = appendAggInfo(pParse); pCol = &pAggInfo->aCol[i];
if( i<0 ) return 1; pCol->iTable = pExpr->iTable;
pParse->aAgg[i].isAgg = 0; pCol->iColumn = pExpr->iColumn;
pParse->aAgg[i].pExpr = pExpr; pCol->iMem = pParse->nMem++;
pCol->iSorterColumn = -1;
pCol->pExpr = pExpr;
if( pAggInfo->pGroupBy ){
int j, n;
ExprList *pGB = pAggInfo->pGroupBy;
struct ExprList_item *pTerm = pGB->a;
n = pGB->nExpr;
for(j=0; j<n; j++, pTerm++){
Expr *pE = pTerm->pExpr;
if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable &&
pE->iColumn==pExpr->iColumn ){
pCol->iSorterColumn = j;
break;
} }
}
}
if( pCol->iSorterColumn<0 ){
pCol->iSorterColumn = pAggInfo->nSortingColumn++;
}
}
/* There is now an entry for pExpr in pAggInfo->aCol[] (either
** because it was there before or because we just created it).
** Convert the pExpr to be a TK_AGG_COLUMN referring to that
** pAggInfo->aCol[] entry.
*/
pExpr->pAggInfo = pAggInfo;
pExpr->op = TK_AGG_COLUMN;
pExpr->iAgg = i; pExpr->iAgg = i;
pExpr->iAggCtx = pNC->nDepth; break;
return 1; } /* endif pExpr->iTable==pItem->iCursor */
} } /* end loop over pSrcList */
} }
return 1; return 1;
} }
case TK_AGG_FUNCTION: { case TK_AGG_FUNCTION: {
/* The pNC->nDepth==0 test causes aggregate functions in subqueries
** to be ignored */
if( pNC->nDepth==0 ){ if( pNC->nDepth==0 ){
aAgg = pParse->aAgg; /* Check to see if pExpr is a duplicate of another aggregate
for(i=0; i<pParse->nAgg; i++){ ** function that is already in the pAggInfo structure
if( !aAgg[i].isAgg ) continue; */
if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){ struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){
break; break;
} }
} }
if( i>=pParse->nAgg ){ if( i>=pAggInfo->nFunc ){
/* pExpr is original. Make a new entry in pAggInfo->aFunc[]
*/
u8 enc = pParse->db->enc; u8 enc = pParse->db->enc;
i = appendAggInfo(pParse); i = addAggInfoFunc(pAggInfo);
if( i<0 ) return 1; if( i>=0 ){
pParse->aAgg[i].isAgg = 1; pItem = &pAggInfo->aFunc[i];
pParse->aAgg[i].pExpr = pExpr; pItem->pExpr = pExpr;
pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db, pItem->iMem = pParse->nMem++;
pItem->pFunc = sqlite3FindFunction(pParse->db,
pExpr->token.z, pExpr->token.n, pExpr->token.z, pExpr->token.n,
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
}else{
pItem->iDistinct = -1;
} }
}
}
/* Make pExpr point to the appropriate pAggInfo->aFunc[] entry
*/
pExpr->iAgg = i; pExpr->iAgg = i;
pExpr->pAggInfo = pAggInfo;
return 1; return 1;
} }
} }
} }
/* Recursively walk subqueries looking for TK_COLUMN nodes that need
** to be changed to TK_AGG_COLUMN. But increment nDepth so that
** TK_AGG_FUNCTION nodes in subqueries will be unchanged.
*/
if( pExpr->pSelect ){ if( pExpr->pSelect ){
pNC->nDepth++; pNC->nDepth++;
walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC); walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC);
@ -2149,3 +2233,21 @@ int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
walkExprTree(pExpr, analyzeAggregate, pNC); walkExprTree(pExpr, analyzeAggregate, pNC);
return pNC->pParse->nErr - nErr; return pNC->pParse->nErr - nErr;
} }
/*
** Call sqlite3ExprAnalyzeAggregates() for every expression in an
** expression list. Return the number of errors.
**
** If an error is found, the analysis is cut short.
*/
int sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
struct ExprList_item *pItem;
int i;
int nErr = 0;
if( pList ){
for(pItem=pList->a, i=0; nErr==0 && i<pList->nExpr; i++, pItem++){
nErr += sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
}
}
return nErr;
}

View file

@ -819,6 +819,7 @@ typedef struct SumCtx SumCtx;
struct SumCtx { struct SumCtx {
double sum; /* Sum of terms */ double sum; /* Sum of terms */
int cnt; /* Number of elements summed */ int cnt; /* Number of elements summed */
u8 seenFloat; /* True if there has been any floating point value */
}; };
/* /*
@ -826,21 +827,32 @@ struct SumCtx {
*/ */
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
SumCtx *p; SumCtx *p;
if( argc<1 ) return; int type;
assert( argc==1 );
p = sqlite3_aggregate_context(context, sizeof(*p)); p = sqlite3_aggregate_context(context, sizeof(*p));
if( p && SQLITE_NULL!=sqlite3_value_type(argv[0]) ){ type = sqlite3_value_type(argv[0]);
if( p && type!=SQLITE_NULL ){
p->sum += sqlite3_value_double(argv[0]); p->sum += sqlite3_value_double(argv[0]);
p->cnt++; p->cnt++;
if( type==SQLITE_FLOAT ){
p->seenFloat = 1;
}
} }
} }
static void sumFinalize(sqlite3_context *context){ static void sumFinalize(sqlite3_context *context){
SumCtx *p; SumCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p)); p = sqlite3_aggregate_context(context, 0);
sqlite3_result_double(context, p ? p->sum : 0.0); if( p && p->cnt>0 ){
if( p->seenFloat ){
sqlite3_result_double(context, p->sum);
}else{
sqlite3_result_int64(context, (i64)p->sum);
}
}
} }
static void avgFinalize(sqlite3_context *context){ static void avgFinalize(sqlite3_context *context){
SumCtx *p; SumCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p)); p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){ if( p && p->cnt>0 ){
sqlite3_result_double(context, p->sum/(double)p->cnt); sqlite3_result_double(context, p->sum/(double)p->cnt);
} }
@ -878,7 +890,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
} }
static void countFinalize(sqlite3_context *context){ static void countFinalize(sqlite3_context *context){
CountCtx *p; CountCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p)); p = sqlite3_aggregate_context(context, 0);
sqlite3_result_int(context, p ? p->n : 0); sqlite3_result_int(context, p ? p->n : 0);
} }
@ -916,12 +928,14 @@ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv)
} }
static void minMaxFinalize(sqlite3_context *context){ static void minMaxFinalize(sqlite3_context *context){
sqlite3_value *pRes; sqlite3_value *pRes;
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, sizeof(Mem)); pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
if( pRes ){
if( pRes->flags ){ if( pRes->flags ){
sqlite3_result_value(context, pRes); sqlite3_result_value(context, pRes);
} }
sqlite3VdbeMemRelease(pRes); sqlite3VdbeMemRelease(pRes);
} }
}
/* /*
@ -1041,11 +1055,11 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
/* /*
** Set the LIKEOPT flag on the 2-argument function with the given name. ** Set the LIKEOPT flag on the 2-argument function with the given name.
*/ */
static void setLikeOptFlag(sqlite3 *db, const char *zName){ static void setLikeOptFlag(sqlite3 *db, const char *zName, int flagVal){
FuncDef *pDef; FuncDef *pDef;
pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0); pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0);
if( pDef ){ if( pDef ){
pDef->flags = SQLITE_FUNC_LIKEOPT; pDef->flags = flagVal;
} }
} }
@ -1065,10 +1079,9 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0); sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
sqlite3_create_function(db, "glob", 2, SQLITE_UTF8, sqlite3_create_function(db, "glob", 2, SQLITE_UTF8,
(struct compareInfo*)&globInfo, likeFunc, 0,0); (struct compareInfo*)&globInfo, likeFunc, 0,0);
setLikeOptFlag(db, "glob"); setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
if( caseSensitive ){ setLikeOptFlag(db, "like",
setLikeOptFlag(db, "like"); caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
}
} }
/* /*
@ -1078,7 +1091,7 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
** return TRUE. If the function is not a LIKE-style function then ** return TRUE. If the function is not a LIKE-style function then
** return FALSE. ** return FALSE.
*/ */
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef; FuncDef *pDef;
if( pExpr->op!=TK_FUNCTION ){ if( pExpr->op!=TK_FUNCTION ){
return 0; return 0;
@ -1088,7 +1101,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){
} }
pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2, pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
SQLITE_UTF8, 0); SQLITE_UTF8, 0);
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKEOPT)==0 ){ if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
return 0; return 0;
} }
@ -1100,6 +1113,6 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll ); assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne ); assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet ); assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
*pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0;
return 1; return 1;
} }

View file

@ -372,13 +372,13 @@ void sqlite3Insert(
** of the program jumps to it. Create the temporary table, then jump ** of the program jumps to it. Create the temporary table, then jump
** back up and execute the SELECT code above. ** back up and execute the SELECT code above.
*/ */
sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, iInitCode);
sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0); sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn); sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop); sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
sqlite3VdbeResolveLabel(v, iCleanup); sqlite3VdbeResolveLabel(v, iCleanup);
}else{ }else{
sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, iInitCode);
} }
}else{ }else{
/* This is the case if the data for the INSERT is coming from a VALUES /* This is the case if the data for the INSERT is coming from a VALUES
@ -470,8 +470,7 @@ void sqlite3Insert(
*/ */
if( db->flags & SQLITE_CountRows ){ if( db->flags & SQLITE_CountRows ){
iCntMem = pParse->nMem++; iCntMem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem);
sqlite3VdbeAddOp(v, OP_MemStore, iCntMem, 1);
} }
/* Open tables and indices if there are no row triggers */ /* Open tables and indices if there are no row triggers */
@ -817,7 +816,6 @@ void sqlite3GenerateConstraintChecks(
Index *pIdx; Index *pIdx;
int seenReplace = 0; int seenReplace = 0;
int jumpInst1=0, jumpInst2; int jumpInst1=0, jumpInst2;
int contAddr;
int hasTwoRowids = (isUpdate && rowidChng); int hasTwoRowids = (isUpdate && rowidChng);
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
@ -867,7 +865,7 @@ void sqlite3GenerateConstraintChecks(
break; break;
} }
} }
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, addr);
} }
/* Test all CHECK constraints /* Test all CHECK constraints
@ -921,10 +919,9 @@ void sqlite3GenerateConstraintChecks(
break; break;
} }
} }
contAddr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeJumpHere(v, jumpInst2);
sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
if( isUpdate ){ if( isUpdate ){
sqlite3VdbeChangeP2(v, jumpInst1, contAddr); sqlite3VdbeJumpHere(v, jumpInst1);
sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1); sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
} }
@ -1018,11 +1015,10 @@ void sqlite3GenerateConstraintChecks(
break; break;
} }
} }
contAddr = sqlite3VdbeCurrentAddr(v);
#if NULL_DISTINCT_FOR_UNIQUE #if NULL_DISTINCT_FOR_UNIQUE
sqlite3VdbeChangeP2(v, jumpInst1, contAddr); sqlite3VdbeJumpHere(v, jumpInst1);
#endif #endif
sqlite3VdbeChangeP2(v, jumpInst2, contAddr); sqlite3VdbeJumpHere(v, jumpInst2);
} }
} }

View file

@ -509,13 +509,14 @@ int sqlite3_create_function16(
} }
#endif #endif
#ifndef SQLITE_OMIT_TRACE
/* /*
** Register a trace function. The pArg from the previously registered trace ** Register a trace function. The pArg from the previously registered trace
** is returned. ** is returned.
** **
** A NULL trace function means that no tracing is executes. A non-NULL ** A NULL trace function means that no tracing is executes. A non-NULL
** trace is a pointer to a function that is invoked at the start of each ** trace is a pointer to a function that is invoked at the start of each
** sqlite3_exec(). ** SQL statement.
*/ */
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
void *pOld = db->pTraceArg; void *pOld = db->pTraceArg;
@ -523,6 +524,25 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
db->pTraceArg = pArg; db->pTraceArg = pArg;
return pOld; return pOld;
} }
/*
** Register a profile function. The pArg from the previously registered
** profile function is returned.
**
** A NULL profile function means that no profiling is executes. A non-NULL
** profile is a pointer to a function that is invoked at the conclusion of
** each SQL statement that is run.
*/
void *sqlite3_profile(
sqlite3 *db,
void (*xProfile)(void*,const char*,sqlite_uint64),
void *pArg
){
void *pOld = db->pProfileArg;
db->xProfile = xProfile;
db->pProfileArg = pArg;
return pOld;
}
#endif /* SQLITE_OMIT_TRACE */
/*** EXPERIMENTAL *** /*** EXPERIMENTAL ***
** **
@ -694,6 +714,7 @@ static int openDatabase(
){ ){
sqlite3 *db; sqlite3 *db;
int rc, i; int rc, i;
CollSeq *pColl;
/* Allocate the sqlite data structure */ /* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite3) ); db = sqliteMalloc( sizeof(sqlite3) );
@ -730,6 +751,13 @@ static int openDatabase(
/* Also add a UTF-8 case-insensitive collation sequence. */ /* Also add a UTF-8 case-insensitive collation sequence. */
sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc); sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
/* Set flags on the built-in collating sequences */
db->pDfltColl->type = SQLITE_COLL_BINARY;
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 6, 0);
if( pColl ){
pColl->type = SQLITE_COLL_NOCASE;
}
/* Open the backend database driver */ /* Open the backend database driver */
rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt); rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -847,7 +875,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
rc = SQLITE_OK; rc = SQLITE_OK;
}else{ }else{
rc = sqlite3VdbeReset((Vdbe*)pStmt); rc = sqlite3VdbeReset((Vdbe*)pStmt);
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0, 0); sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
} }
return rc; return rc;
} }
@ -1019,3 +1047,14 @@ recover_out:
int sqlite3_get_autocommit(sqlite3 *db){ int sqlite3_get_autocommit(sqlite3 *db){
return db->autoCommit; return db->autoCommit;
} }
#ifdef SQLITE_DEBUG
/*
** The following routine is subtituted for constant SQLITE_CORRUPT in
** debugging builds. This provides a way to set a breakpoint for when
** corruption is first detected.
*/
int sqlite3Corrupt(void){
return SQLITE_CORRUPT;
}
#endif

View file

@ -1,144 +1,149 @@
/* Automatically generated. Do not edit */ /* Automatically generated. Do not edit */
/* See the mkopcodeh.awk script for details */ /* See the mkopcodeh.awk script for details */
#define OP_MemLoad 1 #define OP_MemLoad 1
#define OP_HexBlob 131 /* same as TK_BLOB */ #define OP_HexBlob 134 /* same as TK_BLOB */
#define OP_Column 2 #define OP_Column 2
#define OP_SetCookie 3 #define OP_SetCookie 3
#define OP_IfMemPos 4 #define OP_IfMemPos 4
#define OP_Real 130 /* same as TK_FLOAT */ #define OP_Real 133 /* same as TK_FLOAT */
#define OP_MoveGt 5 #define OP_Sequence 5
#define OP_Ge 77 /* same as TK_GE */ #define OP_MoveGt 6
#define OP_AggFocus 6 #define OP_Ge 80 /* same as TK_GE */
#define OP_RowKey 7 #define OP_RowKey 7
#define OP_AggNext 8 #define OP_Eq 76 /* same as TK_EQ */
#define OP_Eq 73 /* same as TK_EQ */ #define OP_OpenWrite 8
#define OP_OpenWrite 9 #define OP_NotNull 74 /* same as TK_NOTNULL */
#define OP_NotNull 71 /* same as TK_NOTNULL */ #define OP_If 9
#define OP_If 10 #define OP_ToInt 10
#define OP_ToInt 11 #define OP_String8 95 /* same as TK_STRING */
#define OP_String8 92 /* same as TK_STRING */ #define OP_Pop 11
#define OP_Pop 12 #define OP_CollSeq 12
#define OP_AggContextPush 13 #define OP_OpenRead 13
#define OP_CollSeq 14 #define OP_Expire 14
#define OP_OpenRead 15 #define OP_AutoCommit 15
#define OP_Expire 16 #define OP_Gt 77 /* same as TK_GT */
#define OP_SortReset 17 #define OP_IntegrityCk 16
#define OP_AutoCommit 18 #define OP_Sort 17
#define OP_Gt 74 /* same as TK_GT */ #define OP_Function 18
#define OP_Sort 19 #define OP_And 68 /* same as TK_AND */
#define OP_IntegrityCk 20 #define OP_Subtract 87 /* same as TK_MINUS */
#define OP_SortInsert 21 #define OP_Noop 19
#define OP_Function 22 #define OP_Return 20
#define OP_And 65 /* same as TK_AND */ #define OP_Remainder 90 /* same as TK_REM */
#define OP_Subtract 84 /* same as TK_MINUS */ #define OP_NewRowid 21
#define OP_Noop 23 #define OP_Multiply 88 /* same as TK_STAR */
#define OP_Return 24 #define OP_Variable 22
#define OP_Remainder 87 /* same as TK_REM */ #define OP_String 23
#define OP_NewRowid 25 #define OP_ParseSchema 24
#define OP_Multiply 85 /* same as TK_STAR */ #define OP_Close 25
#define OP_Variable 26 #define OP_CreateIndex 26
#define OP_String 27 #define OP_IsUnique 27
#define OP_ParseSchema 28 #define OP_IdxIsNull 28
#define OP_AggFunc 29 #define OP_NotFound 29
#define OP_Close 30 #define OP_Int64 30
#define OP_CreateIndex 31 #define OP_MustBeInt 31
#define OP_IsUnique 32 #define OP_Halt 32
#define OP_IdxIsNull 33 #define OP_Rowid 33
#define OP_NotFound 34 #define OP_IdxLT 34
#define OP_Int64 35 #define OP_AddImm 35
#define OP_MustBeInt 36 #define OP_Statement 36
#define OP_Halt 37 #define OP_RowData 37
#define OP_Rowid 38 #define OP_MemMax 38
#define OP_IdxLT 39 #define OP_Push 39
#define OP_AddImm 40 #define OP_Or 67 /* same as TK_OR */
#define OP_Statement 41 #define OP_NotExists 40
#define OP_RowData 42 #define OP_MemIncr 41
#define OP_MemMax 43 #define OP_Gosub 42
#define OP_Push 44 #define OP_Divide 89 /* same as TK_SLASH */
#define OP_Or 64 /* same as TK_OR */ #define OP_Integer 43
#define OP_NotExists 45 #define OP_ToNumeric 44
#define OP_MemIncr 46 #define OP_MemInt 45
#define OP_Gosub 47 #define OP_Prev 46
#define OP_Divide 86 /* same as TK_SLASH */ #define OP_Concat 91 /* same as TK_CONCAT */
#define OP_AggSet 48 #define OP_BitAnd 82 /* same as TK_BITAND */
#define OP_Integer 49 #define OP_CreateTable 47
#define OP_ToNumeric 50 #define OP_Last 48
#define OP_SortNext 51 #define OP_IsNull 73 /* same as TK_ISNULL */
#define OP_Prev 52 #define OP_IdxRowid 49
#define OP_Concat 88 /* same as TK_CONCAT */ #define OP_MakeIdxRec 50
#define OP_BitAnd 79 /* same as TK_BITAND */ #define OP_ShiftRight 85 /* same as TK_RSHIFT */
#define OP_CreateTable 53 #define OP_ResetCount 51
#define OP_Last 54 #define OP_FifoWrite 52
#define OP_IsNull 70 /* same as TK_ISNULL */ #define OP_Callback 53
#define OP_IdxRowid 55 #define OP_ContextPush 54
#define OP_MakeIdxRec 56 #define OP_DropTrigger 55
#define OP_ShiftRight 82 /* same as TK_RSHIFT */ #define OP_DropIndex 56
#define OP_ResetCount 57 #define OP_IdxGE 57
#define OP_FifoWrite 58 #define OP_IdxDelete 58
#define OP_Callback 59 #define OP_Vacuum 59
#define OP_ContextPush 60 #define OP_MoveLe 60
#define OP_DropTrigger 61 #define OP_IfNot 61
#define OP_DropIndex 62 #define OP_DropTable 62
#define OP_IdxGE 63 #define OP_MakeRecord 63
#define OP_IdxDelete 67 #define OP_ToBlob 64
#define OP_Vacuum 68 #define OP_Delete 65
#define OP_MoveLe 69 #define OP_AggFinal 66
#define OP_IfNot 78 #define OP_ShiftLeft 84 /* same as TK_LSHIFT */
#define OP_DropTable 90 #define OP_Dup 70
#define OP_MakeRecord 93 #define OP_Goto 71
#define OP_ToBlob 94 #define OP_FifoRead 72
#define OP_Delete 95 #define OP_Clear 81
#define OP_AggContextPop 96 #define OP_IdxGT 93
#define OP_ShiftLeft 81 /* same as TK_LSHIFT */ #define OP_MoveLt 96
#define OP_Dup 97 #define OP_Le 78 /* same as TK_LE */
#define OP_Goto 98 #define OP_VerifyCookie 97
#define OP_FifoRead 99 #define OP_AggStep 98
#define OP_Clear 100 #define OP_Pull 99
#define OP_IdxGT 101 #define OP_ToText 100
#define OP_MoveLt 102 #define OP_Not 69 /* same as TK_NOT */
#define OP_Le 75 /* same as TK_LE */ #define OP_SetNumColumns 101
#define OP_VerifyCookie 103 #define OP_AbsValue 102
#define OP_Pull 104 #define OP_Transaction 103
#define OP_ToText 105 #define OP_Negative 92 /* same as TK_UMINUS */
#define OP_Not 66 /* same as TK_NOT */ #define OP_Ne 75 /* same as TK_NE */
#define OP_SetNumColumns 106 #define OP_ContextPop 104
#define OP_AbsValue 107 #define OP_BitOr 83 /* same as TK_BITOR */
#define OP_Transaction 108 #define OP_Next 105
#define OP_Negative 89 /* same as TK_UMINUS */ #define OP_IdxInsert 106
#define OP_Ne 72 /* same as TK_NE */ #define OP_Distinct 107
#define OP_AggGet 109 #define OP_Lt 79 /* same as TK_LT */
#define OP_ContextPop 110 #define OP_Insert 108
#define OP_BitOr 80 /* same as TK_BITOR */ #define OP_Destroy 109
#define OP_Next 111 #define OP_ReadCookie 110
#define OP_AggInit 112 #define OP_ForceInt 111
#define OP_IdxInsert 113 #define OP_LoadAnalysis 112
#define OP_Distinct 114 #define OP_OpenVirtual 113
#define OP_Lt 76 /* same as TK_LT */ #define OP_Explain 114
#define OP_AggReset 115 #define OP_OpenPseudo 115
#define OP_Insert 116 #define OP_Null 116
#define OP_Destroy 117 #define OP_Blob 117
#define OP_ReadCookie 118 #define OP_Add 86 /* same as TK_PLUS */
#define OP_ForceInt 119 #define OP_MemStore 118
#define OP_LoadAnalysis 120 #define OP_Rewind 119
#define OP_OpenVirtual 121 #define OP_MoveGe 120
#define OP_OpenPseudo 122 #define OP_BitNot 94 /* same as TK_BITNOT */
#define OP_Null 123 #define OP_MemMove 121
#define OP_Blob 124 #define OP_MemNull 122
#define OP_Add 83 /* same as TK_PLUS */ #define OP_Found 123
#define OP_MemStore 125 #define OP_NullRow 124
#define OP_Rewind 126
#define OP_MoveGe 127
#define OP_BitNot 91 /* same as TK_BITNOT */
#define OP_Found 128
#define OP_NullRow 129
#define NOPUSH_MASK_0 65400 /* The following opcode values are never used */
#define NOPUSH_MASK_1 29103 #define OP_NotUsed_125 125
#define NOPUSH_MASK_2 64439 #define OP_NotUsed_126 126
#define NOPUSH_MASK_3 65109 #define OP_NotUsed_127 127
#define NOPUSH_MASK_4 65535 #define OP_NotUsed_128 128
#define NOPUSH_MASK_5 52991 #define OP_NotUsed_129 129
#define NOPUSH_MASK_6 55285 #define OP_NotUsed_130 130
#define NOPUSH_MASK_7 59295 #define OP_NotUsed_131 131
#define NOPUSH_MASK_8 3 #define OP_NotUsed_132 132
#define NOPUSH_MASK_0 65368
#define NOPUSH_MASK_1 47898
#define NOPUSH_MASK_2 22493
#define NOPUSH_MASK_3 32761
#define NOPUSH_MASK_4 65215
#define NOPUSH_MASK_5 30719
#define NOPUSH_MASK_6 40895
#define NOPUSH_MASK_7 6603
#define NOPUSH_MASK_8 0
#define NOPUSH_MASK_9 0 #define NOPUSH_MASK_9 0

View file

@ -161,8 +161,13 @@
** 1GB boundary. ** 1GB boundary.
** **
*/ */
#ifndef SQLITE_TEST
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */ #define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
/* #define PENDING_BYTE 0x5400 // Page 22 - for testing */ #else
extern unsigned int sqlite3_pending_byte;
#define PENDING_BYTE sqlite3_pending_byte
#endif
#define RESERVED_BYTE (PENDING_BYTE+1) #define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510 #define SHARED_SIZE 510
@ -181,7 +186,7 @@ int sqlite3OsClose(OsFile*);
int sqlite3OsRead(OsFile*, void*, int amt); int sqlite3OsRead(OsFile*, void*, int amt);
int sqlite3OsWrite(OsFile*, const void*, int amt); int sqlite3OsWrite(OsFile*, const void*, int amt);
int sqlite3OsSeek(OsFile*, i64 offset); int sqlite3OsSeek(OsFile*, i64 offset);
int sqlite3OsSync(OsFile*); int sqlite3OsSync(OsFile*, int);
int sqlite3OsTruncate(OsFile*, i64 size); int sqlite3OsTruncate(OsFile*, i64 size);
int sqlite3OsFileSize(OsFile*, i64 *pSize); int sqlite3OsFileSize(OsFile*, i64 *pSize);
char *sqlite3OsFullPathname(const char*); char *sqlite3OsFullPathname(const char*);

View file

@ -28,6 +28,14 @@
#endif #endif
/*
* When testing, this global variable stores the location of the
* pending-byte in the database file.
*/
#ifdef SQLITE_TEST
unsigned int sqlite3_pending_byte = 0x40000000;
#endif
int sqlite3_os_trace = 0; int sqlite3_os_trace = 0;
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
static int last_page = 0; static int last_page = 0;
@ -82,6 +90,7 @@ static unsigned int elapse;
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
int sqlite3_io_error_pending = 0; int sqlite3_io_error_pending = 0;
int sqlite3_diskfull_pending = 0; int sqlite3_diskfull_pending = 0;
int sqlite3_diskfull = 0;
#define SimulateIOError(A) \ #define SimulateIOError(A) \
if( sqlite3_io_error_pending ) \ if( sqlite3_io_error_pending ) \
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; } if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
@ -89,8 +98,15 @@ static void local_ioerr(){
sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */ sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
} }
#define SimulateDiskfullError \ #define SimulateDiskfullError \
if( sqlite3_diskfull_pending ) \ if( sqlite3_diskfull_pending ){ \
if( sqlite3_diskfull_pending-- == 1 ){ local_ioerr(); return SQLITE_FULL; } if( sqlite3_diskfull_pending == 1 ){ \
local_ioerr(); \
sqlite3_diskfull = 1; \
return SQLITE_FULL; \
}else{ \
sqlite3_diskfull_pending--; \
} \
}
#else #else
#define SimulateIOError(A) #define SimulateIOError(A)
#define SimulateDiskfullError #define SimulateDiskfullError

View file

@ -391,12 +391,12 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
** Sync the file. First flush the write-cache to disk, then call the ** Sync the file. First flush the write-cache to disk, then call the
** real sync() function. ** real sync() function.
*/ */
int sqlite3OsSync(OsFile *id){ int sqlite3OsSync(OsFile *id, int dataOnly){
int rc; int rc;
/* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ /* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
rc = writeCache(*id); rc = writeCache(*id);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
rc = sqlite3RealSync(&(*id)->fd); rc = sqlite3RealSync(&(*id)->fd, dataOnly);
return rc; return rc;
} }

View file

@ -18,6 +18,7 @@
#include <time.h> #include <time.h>
#include <sys/time.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
@ -771,6 +772,9 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
int sqlite3OsSeek(OsFile *id, i64 offset){ int sqlite3OsSeek(OsFile *id, i64 offset){
assert( id->isOpen ); assert( id->isOpen );
SEEK(offset/1024 + 1); SEEK(offset/1024 + 1);
#ifdef SQLITE_TEST
if( offset ) SimulateDiskfullError
#endif
lseek(id->h, offset, SEEK_SET); lseek(id->h, offset, SEEK_SET);
return SQLITE_OK; return SQLITE_OK;
} }
@ -796,7 +800,7 @@ int sqlite3_fullsync_count = 0;
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash ** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
** or power failure will likely corrupt the database file. ** or power failure will likely corrupt the database file.
*/ */
static int full_fsync(int fd, int fullSync){ static int full_fsync(int fd, int fullSync, int dataOnly){
int rc; int rc;
/* Record the number of times that we do a normal fsync() and /* Record the number of times that we do a normal fsync() and
@ -824,8 +828,15 @@ static int full_fsync(int fd, int fullSync){
/* If the FULLSYNC failed, try to do a normal fsync() */ /* If the FULLSYNC failed, try to do a normal fsync() */
if( rc ) rc = fsync(fd); if( rc ) rc = fsync(fd);
#else #else /* if !defined(F_FULLSYNC) */
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO>0
if( dataOnly ){
rc = fdatasync(fd);
}else
#endif /* _POSIX_SYNCHRONIZED_IO > 0 */
{
rc = fsync(fd); rc = fsync(fd);
}
#endif /* defined(F_FULLFSYNC) */ #endif /* defined(F_FULLFSYNC) */
#endif /* defined(SQLITE_NO_SYNC) */ #endif /* defined(SQLITE_NO_SYNC) */
@ -835,6 +846,10 @@ static int full_fsync(int fd, int fullSync){
/* /*
** Make sure all writes to a particular file are committed to disk. ** Make sure all writes to a particular file are committed to disk.
** **
** If dataOnly==0 then both the file itself and its metadata (file
** size, access time, etc) are synced. If dataOnly!=0 then only the
** file data is synced.
**
** Under Unix, also make sure that the directory entry for the file ** Under Unix, also make sure that the directory entry for the file
** has been created by fsync-ing the directory that contains the file. ** has been created by fsync-ing the directory that contains the file.
** If we do not do this and we encounter a power failure, the directory ** If we do not do this and we encounter a power failure, the directory
@ -843,16 +858,16 @@ static int full_fsync(int fd, int fullSync){
** the directory entry for the journal was never created) and the transaction ** the directory entry for the journal was never created) and the transaction
** will not roll back - possibly leading to database corruption. ** will not roll back - possibly leading to database corruption.
*/ */
int sqlite3OsSync(OsFile *id){ int sqlite3OsSync(OsFile *id, int dataOnly){
assert( id->isOpen ); assert( id->isOpen );
SimulateIOError(SQLITE_IOERR); SimulateIOError(SQLITE_IOERR);
TRACE2("SYNC %-3d\n", id->h); TRACE2("SYNC %-3d\n", id->h);
if( full_fsync(id->h, id->fullSync) ){ if( full_fsync(id->h, id->fullSync, dataOnly) ){
return SQLITE_IOERR; return SQLITE_IOERR;
} }
if( id->dirfd>=0 ){ if( id->dirfd>=0 ){
TRACE2("DIRSYNC %-3d\n", id->dirfd); TRACE2("DIRSYNC %-3d\n", id->dirfd);
full_fsync(id->dirfd, id->fullSync); full_fsync(id->dirfd, id->fullSync, 0);
close(id->dirfd); /* Only need to sync once, so close the directory */ close(id->dirfd); /* Only need to sync once, so close the directory */
id->dirfd = -1; /* when we are done. */ id->dirfd = -1; /* when we are done. */
} }
@ -1310,10 +1325,14 @@ char *sqlite3OsFullPathname(const char *zRelative){
if( zRelative[0]=='/' ){ if( zRelative[0]=='/' ){
sqlite3SetString(&zFull, zRelative, (char*)0); sqlite3SetString(&zFull, zRelative, (char*)0);
}else{ }else{
char zBuf[5000]; char *zBuf = sqliteMalloc(5000);
if( zBuf==0 ){
return 0;
}
zBuf[0] = 0; zBuf[0] = 0;
sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative, sqlite3SetString(&zFull, getcwd(zBuf, 5000), "/", zRelative,
(char*)0); (char*)0);
sqliteFree(zBuf);
} }
return zFull; return zFull;
} }
@ -1420,9 +1439,16 @@ int sqlite3_current_time = 0;
** return 0. Return 1 if the time and date cannot be found. ** return 0. Return 1 if the time and date cannot be found.
*/ */
int sqlite3OsCurrentTime(double *prNow){ int sqlite3OsCurrentTime(double *prNow){
#ifdef NO_GETTOD
time_t t; time_t t;
time(&t); time(&t);
*prNow = t/86400.0 + 2440587.5; *prNow = t/86400.0 + 2440587.5;
#else
struct timeval sNow;
struct timezone sTz; /* Not used */
gettimeofday(&sNow, &sTz);
*prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
#endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
if( sqlite3_current_time ){ if( sqlite3_current_time ){
*prNow = sqlite3_current_time/86400.0 + 2440587.5; *prNow = sqlite3_current_time/86400.0 + 2440587.5;

View file

@ -41,11 +41,99 @@
*/ */
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
/*
** The following variable is (normally) set once and never changes
** thereafter. It records whether the operating system is Win95
** or WinNT.
**
** 0: Operating system unknown.
** 1: Operating system is Win95.
** 2: Operating system is WinNT.
**
** In order to facilitate testing on a WinNT system, the test fixture
** can manually set this value to 1 to emulate Win98 behavior.
*/
int sqlite3_os_type = 0;
/*
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
** Return false (zero) for Win95, Win98, or WinME.
**
** Here is an interesting observation: Win95, Win98, and WinME lack
** the LockFileEx() API. But we can still statically link against that
** API as long as we don't call it win running Win95/98/ME. A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
*/
static int isNT(void){
if( sqlite3_os_type==0 ){
OSVERSIONINFO sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
GetVersionEx(&sInfo);
sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
}
return sqlite3_os_type==2;
}
/*
** Convert a UTF-8 string to UTF-32. Space to hold the returned string
** is obtained from sqliteMalloc.
*/
static WCHAR *utf8ToUnicode(const char *zFilename){
int nByte;
WCHAR *zWideFilename;
if( !isNT() ){
return 0;
}
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0)*sizeof(WCHAR);
zWideFilename = sqliteMalloc( nByte*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nByte);
if( nByte==0 ){
sqliteFree(zWideFilename);
zWideFilename = 0;
}
return zWideFilename;
}
/*
** Convert UTF-32 to UTF-8. Space to hold the returned string is
** obtained from sqliteMalloc().
*/
static char *unicodeToUtf8(const WCHAR *zWideFilename){
int nByte;
char *zFilename;
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
zFilename = sqliteMalloc( nByte );
if( zFilename==0 ){
return 0;
}
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
0, 0);
if( nByte == 0 ){
sqliteFree(zFilename);
zFilename = 0;
}
return zFilename;
}
/* /*
** Delete the named file ** Delete the named file
*/ */
int sqlite3OsDelete(const char *zFilename){ int sqlite3OsDelete(const char *zFilename){
WCHAR *zWide = utf8ToUnicode(zFilename);
if( zWide ){
DeleteFileW(zWide);
sqliteFree(zWide);
}else{
DeleteFileA(zFilename); DeleteFileA(zFilename);
}
TRACE2("DELETE \"%s\"\n", zFilename); TRACE2("DELETE \"%s\"\n", zFilename);
return SQLITE_OK; return SQLITE_OK;
} }
@ -54,7 +142,15 @@ int sqlite3OsDelete(const char *zFilename){
** Return TRUE if the named file exists. ** Return TRUE if the named file exists.
*/ */
int sqlite3OsFileExists(const char *zFilename){ int sqlite3OsFileExists(const char *zFilename){
return GetFileAttributesA(zFilename) != 0xffffffff; int exists = 0;
WCHAR *zWide = utf8ToUnicode(zFilename);
if( zWide ){
exists = GetFileAttributesW(zWide) != 0xffffffff;
sqliteFree(zWide);
}else{
exists = GetFileAttributesA(zFilename) != 0xffffffff;
}
return exists;
} }
/* /*
@ -76,7 +172,36 @@ int sqlite3OsOpenReadWrite(
int *pReadonly int *pReadonly
){ ){
HANDLE h; HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename);
assert( !id->isOpen ); assert( !id->isOpen );
if( zWide ){
h = CreateFileW(zWide,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
h = CreateFileW(zWide,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
sqliteFree(zWide);
return SQLITE_CANTOPEN;
}
*pReadonly = 1;
}else{
*pReadonly = 0;
}
sqliteFree(zWide);
}else{
h = CreateFileA(zFilename, h = CreateFileA(zFilename,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
@ -101,6 +226,7 @@ int sqlite3OsOpenReadWrite(
}else{ }else{
*pReadonly = 0; *pReadonly = 0;
} }
}
id->h = h; id->h = h;
id->locktype = NO_LOCK; id->locktype = NO_LOCK;
id->sharedLockByte = 0; id->sharedLockByte = 0;
@ -128,6 +254,7 @@ int sqlite3OsOpenReadWrite(
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
HANDLE h; HANDLE h;
int fileflags; int fileflags;
WCHAR *zWide = utf8ToUnicode(zFilename);
assert( !id->isOpen ); assert( !id->isOpen );
if( delFlag ){ if( delFlag ){
fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
@ -135,6 +262,17 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
}else{ }else{
fileflags = FILE_FLAG_RANDOM_ACCESS; fileflags = FILE_FLAG_RANDOM_ACCESS;
} }
if( zWide ){
h = CreateFileW(zWide,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
fileflags,
NULL
);
sqliteFree(zWide);
}else{
h = CreateFileA(zFilename, h = CreateFileA(zFilename,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
0, 0,
@ -143,6 +281,7 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
fileflags, fileflags,
NULL NULL
); );
}
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
@ -164,7 +303,19 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
*/ */
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
HANDLE h; HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename);
assert( !id->isOpen ); assert( !id->isOpen );
if( zWide ){
h = CreateFileW(zWide,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
sqliteFree(zWide);
}else{
h = CreateFileA(zFilename, h = CreateFileA(zFilename,
GENERIC_READ, GENERIC_READ,
0, 0,
@ -173,6 +324,7 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL NULL
); );
}
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
@ -229,6 +381,16 @@ int sqlite3OsTempFileName(char *zBuf){
if( sqlite3_temp_directory ){ if( sqlite3_temp_directory ){
strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30); strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
}else if( isNT() ){
char *zMulti;
WCHAR zWidePath[SQLITE_TEMPNAME_SIZE];
GetTempPathW(SQLITE_TEMPNAME_SIZE-30, zWidePath);
zMulti = unicodeToUtf8(zWidePath);
if( zMulti ){
strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
sqliteFree(zMulti);
}
}else{ }else{
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath); GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
} }
@ -303,6 +465,13 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
return SQLITE_OK; return SQLITE_OK;
} }
/*
** Some microsoft compilers lack this definition.
*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/* /*
** Move the read/write pointer in a file. ** Move the read/write pointer in a file.
*/ */
@ -311,16 +480,22 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
LONG lowerBits = offset & 0xffffffff; LONG lowerBits = offset & 0xffffffff;
DWORD rc; DWORD rc;
assert( id->isOpen ); assert( id->isOpen );
#ifdef SQLITE_TEST
if( offset ) SimulateDiskfullError
#endif
SEEK(offset/1024 + 1); SEEK(offset/1024 + 1);
rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN); rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
TRACE3("SEEK %d %lld\n", id->h, offset); TRACE3("SEEK %d %lld\n", id->h, offset);
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
return SQLITE_FULL;
}
return SQLITE_OK; return SQLITE_OK;
} }
/* /*
** Make sure all writes to a particular file are committed to disk. ** Make sure all writes to a particular file are committed to disk.
*/ */
int sqlite3OsSync(OsFile *id){ int sqlite3OsSync(OsFile *id, int dataOnly){
assert( id->isOpen ); assert( id->isOpen );
TRACE3("SYNC %d lock=%d\n", id->h, id->locktype); TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
if( FlushFileBuffers(id->h) ){ if( FlushFileBuffers(id->h) ){
@ -364,28 +539,6 @@ int sqlite3OsFileSize(OsFile *id, i64 *pSize){
return SQLITE_OK; return SQLITE_OK;
} }
/*
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
** Return false (zero) for Win95, Win98, or WinME.
**
** Here is an interesting observation: Win95, Win98, and WinME lack
** the LockFileEx() API. But we can still statically link against that
** API as long as we don't call it win running Win95/98/ME. A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
*/
static int isNT(void){
static int osType = 0; /* 0=unknown 1=win95 2=winNT */
if( osType==0 ){
OSVERSIONINFO sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
GetVersionEx(&sInfo);
osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
}
return osType==2;
}
/* /*
** Acquire a reader lock. ** Acquire a reader lock.
** Different API routines are called depending on whether or not this ** Different API routines are called depending on whether or not this
@ -426,11 +579,18 @@ static int unlockReadLock(OsFile *id){
** Check that a given pathname is a directory and is writable ** Check that a given pathname is a directory and is writable
** **
*/ */
int sqlite3OsIsDirWritable(char *zBuf){ int sqlite3OsIsDirWritable(char *zDirname){
int fileAttr; int fileAttr;
if(! zBuf ) return 0; WCHAR *zWide;
if(! isNT() && strlen(zBuf) > MAX_PATH ) return 0; if( zDirname==0 ) return 0;
fileAttr = GetFileAttributesA(zBuf); if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
zWide = utf8ToUnicode(zDirname);
if( zWide ){
fileAttr = GetFileAttributesW(zWide);
sqliteFree(zWide);
}else{
fileAttr = GetFileAttributesA(zDirname);
}
if( fileAttr == 0xffffffff ) return 0; if( fileAttr == 0xffffffff ) return 0;
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
return 0; return 0;
@ -641,6 +801,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
char *sqlite3OsFullPathname(const char *zRelative){ char *sqlite3OsFullPathname(const char *zRelative){
char *zNotUsed; char *zNotUsed;
char *zFull; char *zFull;
WCHAR *zWide;
int nByte; int nByte;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
nByte = strlen(zRelative) + MAX_PATH + 1001; nByte = strlen(zRelative) + MAX_PATH + 1001;
@ -648,10 +809,22 @@ char *sqlite3OsFullPathname(const char *zRelative){
if( zFull==0 ) return 0; if( zFull==0 ) return 0;
if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0; if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;
#else #else
zWide = utf8ToUnicode(zRelative);
if( zWide ){
WCHAR *zTemp, *zNotUsedW;
nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1;
zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ) return 0;
GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW);
sqliteFree(zWide);
zFull = unicodeToUtf8(zTemp);
sqliteFree(zTemp);
}else{
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1; nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
zFull = sqliteMalloc( nByte ); zFull = sqliteMalloc( nByte*sizeof(zFull[0]) );
if( zFull==0 ) return 0; if( zFull==0 ) return 0;
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
}
#endif #endif
return zFull; return zFull;
} }

View file

@ -657,9 +657,11 @@ static int writeJournalHdr(Pager *pPager){
** file descriptor to the end of the journal header sector. ** file descriptor to the end of the journal header sector.
*/ */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1); rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(&pPager->jfd, "\000", 1); rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
} }
}
return rc; return rc;
} }
@ -1038,8 +1040,10 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 ); assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize); rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize); rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
}
if( pPg ) pPg->dirty = 0; if( pPg ) pPg->dirty = 0;
} }
if( pPg ){ if( pPg ){
@ -1168,8 +1172,10 @@ static int pager_reload_cache(Pager *pPager){
char zBuf[SQLITE_MAX_PAGE_SIZE]; char zBuf[SQLITE_MAX_PAGE_SIZE];
if( !pPg->dirty ) continue; if( !pPg->dirty ) continue;
if( (int)pPg->pgno <= pPager->origDbSize ){ if( (int)pPg->pgno <= pPager->origDbSize ){
sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1)); rc = sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
if( rc==SQLITE_OK ){
rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize); rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
}
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno); TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc ) break; if( rc ) break;
CODEC(pPager, zBuf, pPg->pgno, 2); CODEC(pPager, zBuf, pPg->pgno, 2);
@ -1485,7 +1491,7 @@ static int pager_stmt_playback(Pager *pPager){
end_stmt_playback: end_stmt_playback:
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
pPager->errMask |= PAGER_ERR_CORRUPT; pPager->errMask |= PAGER_ERR_CORRUPT;
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */ rc = SQLITE_CORRUPT;
}else{ }else{
pPager->journalOff = szJ; pPager->journalOff = szJ;
/* pager_reload_cache(pPager); */ /* pager_reload_cache(pPager); */
@ -1747,13 +1753,18 @@ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
/* /*
** Return the total number of pages in the disk file associated with ** Return the total number of pages in the disk file associated with
** pPager. ** pPager.
**
** If the PENDING_BYTE lies on the page directly after the end of the
** file, then consider this page part of the file too. For example, if
** PENDING_BYTE is byte 4096 (the first byte of page 5) and the size of the
** file is 4096 bytes, 5 is returned instead of 4.
*/ */
int sqlite3pager_pagecount(Pager *pPager){ int sqlite3pager_pagecount(Pager *pPager){
i64 n; i64 n;
assert( pPager!=0 ); assert( pPager!=0 );
if( pPager->dbSize>=0 ){ if( pPager->dbSize>=0 ){
return pPager->dbSize; n = pPager->dbSize;
} } else {
if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){ if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
pPager->errMask |= PAGER_ERR_DISK; pPager->errMask |= PAGER_ERR_DISK;
return 0; return 0;
@ -1763,12 +1774,13 @@ int sqlite3pager_pagecount(Pager *pPager){
}else{ }else{
n /= pPager->pageSize; n /= pPager->pageSize;
} }
if( !MEMDB && n==PENDING_BYTE/pPager->pageSize ){
n++;
}
if( pPager->state!=PAGER_UNLOCK ){ if( pPager->state!=PAGER_UNLOCK ){
pPager->dbSize = n; pPager->dbSize = n;
} }
}
if( n==(PENDING_BYTE/pPager->pageSize) ){
n++;
}
return n; return n;
} }
@ -2121,17 +2133,20 @@ static int syncJournal(Pager *pPager){
*/ */
if( pPager->fullSync ){ if( pPager->fullSync ){
TRACE2("SYNC journal of %d\n", PAGERID(pPager)); TRACE2("SYNC journal of %d\n", PAGERID(pPager));
rc = sqlite3OsSync(&pPager->jfd); rc = sqlite3OsSync(&pPager->jfd, 0);
if( rc!=0 ) return rc; if( rc!=0 ) return rc;
} }
sqlite3OsSeek(&pPager->jfd, pPager->journalHdr + sizeof(aJournalMagic)); rc = sqlite3OsSeek(&pPager->jfd,
pPager->journalHdr + sizeof(aJournalMagic));
if( rc ) return rc;
rc = write32bits(&pPager->jfd, pPager->nRec); rc = write32bits(&pPager->jfd, pPager->nRec);
if( rc ) return rc; if( rc ) return rc;
sqlite3OsSeek(&pPager->jfd, pPager->journalOff); rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
if( rc ) return rc;
} }
TRACE2("SYNC journal of %d\n", PAGERID(pPager)); TRACE2("SYNC journal of %d\n", PAGERID(pPager));
rc = sqlite3OsSync(&pPager->jfd); rc = sqlite3OsSync(&pPager->jfd, pPager->fullSync);
if( rc!=0 ) return rc; if( rc!=0 ) return rc;
pPager->journalStarted = 1; pPager->journalStarted = 1;
} }
@ -2196,7 +2211,8 @@ static int pager_write_pagelist(PgHdr *pList){
while( pList ){ while( pList ){
assert( pList->dirty ); assert( pList->dirty );
sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); rc = sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
if( rc ) return rc;
/* If there are dirty pages in the page cache with page numbers greater /* If there are dirty pages in the page cache with page numbers greater
** than Pager.dbSize, this means sqlite3pager_truncate() was called to ** than Pager.dbSize, this means sqlite3pager_truncate() was called to
** make the file smaller (presumably by auto-vacuum code). Do not write ** make the file smaller (presumably by auto-vacuum code). Do not write
@ -2291,8 +2307,8 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
** number greater than this, or zero, is requested. ** number greater than this, or zero, is requested.
*/ */
if( pgno>PAGER_MAX_PGNO || pgno==0 ){ if( pgno>PAGER_MAX_PGNO || pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
/* Make sure we have not hit any critical errors. /* Make sure we have not hit any critical errors.
@ -2506,8 +2522,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
}else{ }else{
int rc; int rc;
assert( MEMDB==0 ); assert( MEMDB==0 );
sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize); rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
if( rc==SQLITE_OK ){
rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize); rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
}
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno); TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -2815,6 +2833,10 @@ int sqlite3pager_write(void *pData){
} }
}else{ }else{
u32 cksum; u32 cksum;
/* We should never write to the journal file the page that
** contains the database locks. The following assert verifies
** that we do not. */
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
CODEC(pPager, pData, pPg->pgno, 7); CODEC(pPager, pData, pPg->pgno, 7);
cksum = pager_cksum(pPager, pPg->pgno, pData); cksum = pager_cksum(pPager, pPg->pgno, pData);
saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager); saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
@ -3171,7 +3193,7 @@ int sqlite3pager_rollback(Pager *pPager){
rc = pager_playback(pPager); rc = pager_playback(pPager);
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */ rc = SQLITE_CORRUPT_BKPT;
pPager->errMask |= PAGER_ERR_CORRUPT; pPager->errMask |= PAGER_ERR_CORRUPT;
} }
pPager->dbSize = -1; pPager->dbSize = -1;
@ -3441,8 +3463,9 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
*/ */
Pgno i; Pgno i;
void *pPage; void *pPage;
int iSkip = PAGER_MJ_PGNO(pPager);
for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){ for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
if( !(pPager->aInJournal[i/8] & (1<<(i&7))) ){ if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){
rc = sqlite3pager_get(pPager, i, &pPage); rc = sqlite3pager_get(pPager, i, &pPage);
if( rc!=SQLITE_OK ) goto sync_exit; if( rc!=SQLITE_OK ) goto sync_exit;
rc = sqlite3pager_write(pPage); rc = sqlite3pager_write(pPage);
@ -3472,7 +3495,7 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
/* Sync the database file. */ /* Sync the database file. */
if( !pPager->noSync ){ if( !pPager->noSync ){
rc = sqlite3OsSync(&pPager->fd); rc = sqlite3OsSync(&pPager->fd, 0);
} }
pPager->state = PAGER_SYNCED; pPager->state = PAGER_SYNCED;

View file

@ -34,7 +34,7 @@
** reasonable, like 1024. ** reasonable, like 1024.
*/ */
#ifndef SQLITE_MAX_PAGE_SIZE #ifndef SQLITE_MAX_PAGE_SIZE
# define SQLITE_MAX_PAGE_SIZE 8192 # define SQLITE_MAX_PAGE_SIZE 32768
#endif #endif
/* /*

File diff suppressed because it is too large Load diff

View file

@ -6,137 +6,140 @@
#define TK_FUNCTION 6 #define TK_FUNCTION 6
#define TK_COLUMN 7 #define TK_COLUMN 7
#define TK_AGG_FUNCTION 8 #define TK_AGG_FUNCTION 8
#define TK_CONST_FUNC 9 #define TK_AGG_COLUMN 9
#define TK_SEMI 10 #define TK_CONST_FUNC 10
#define TK_EXPLAIN 11 #define TK_SEMI 11
#define TK_BEGIN 12 #define TK_EXPLAIN 12
#define TK_TRANSACTION 13 #define TK_QUERY 13
#define TK_DEFERRED 14 #define TK_PLAN 14
#define TK_IMMEDIATE 15 #define TK_BEGIN 15
#define TK_EXCLUSIVE 16 #define TK_TRANSACTION 16
#define TK_COMMIT 17 #define TK_DEFERRED 17
#define TK_END 18 #define TK_IMMEDIATE 18
#define TK_ROLLBACK 19 #define TK_EXCLUSIVE 19
#define TK_CREATE 20 #define TK_COMMIT 20
#define TK_TABLE 21 #define TK_END 21
#define TK_TEMP 22 #define TK_ROLLBACK 22
#define TK_LP 23 #define TK_CREATE 23
#define TK_RP 24 #define TK_TABLE 24
#define TK_AS 25 #define TK_TEMP 25
#define TK_COMMA 26 #define TK_LP 26
#define TK_ID 27 #define TK_RP 27
#define TK_ABORT 28 #define TK_AS 28
#define TK_AFTER 29 #define TK_COMMA 29
#define TK_ANALYZE 30 #define TK_ID 30
#define TK_ASC 31 #define TK_ABORT 31
#define TK_ATTACH 32 #define TK_AFTER 32
#define TK_BEFORE 33 #define TK_ANALYZE 33
#define TK_CASCADE 34 #define TK_ASC 34
#define TK_CAST 35 #define TK_ATTACH 35
#define TK_CONFLICT 36 #define TK_BEFORE 36
#define TK_DATABASE 37 #define TK_CASCADE 37
#define TK_DESC 38 #define TK_CAST 38
#define TK_DETACH 39 #define TK_CONFLICT 39
#define TK_EACH 40 #define TK_DATABASE 40
#define TK_FAIL 41 #define TK_DESC 41
#define TK_FOR 42 #define TK_DETACH 42
#define TK_IGNORE 43 #define TK_EACH 43
#define TK_INITIALLY 44 #define TK_FAIL 44
#define TK_INSTEAD 45 #define TK_FOR 45
#define TK_LIKE_KW 46 #define TK_IGNORE 46
#define TK_MATCH 47 #define TK_INITIALLY 47
#define TK_KEY 48 #define TK_INSTEAD 48
#define TK_OF 49 #define TK_LIKE_KW 49
#define TK_OFFSET 50 #define TK_MATCH 50
#define TK_PRAGMA 51 #define TK_KEY 51
#define TK_RAISE 52 #define TK_OF 52
#define TK_REPLACE 53 #define TK_OFFSET 53
#define TK_RESTRICT 54 #define TK_PRAGMA 54
#define TK_ROW 55 #define TK_RAISE 55
#define TK_STATEMENT 56 #define TK_REPLACE 56
#define TK_TRIGGER 57 #define TK_RESTRICT 57
#define TK_VACUUM 58 #define TK_ROW 58
#define TK_VIEW 59 #define TK_STATEMENT 59
#define TK_REINDEX 60 #define TK_TRIGGER 60
#define TK_RENAME 61 #define TK_VACUUM 61
#define TK_CTIME_KW 62 #define TK_VIEW 62
#define TK_ALTER 63 #define TK_REINDEX 63
#define TK_OR 64 #define TK_RENAME 64
#define TK_AND 65 #define TK_CTIME_KW 65
#define TK_NOT 66 #define TK_ALTER 66
#define TK_IS 67 #define TK_OR 67
#define TK_BETWEEN 68 #define TK_AND 68
#define TK_IN 69 #define TK_NOT 69
#define TK_ISNULL 70 #define TK_IS 70
#define TK_NOTNULL 71 #define TK_BETWEEN 71
#define TK_NE 72 #define TK_IN 72
#define TK_EQ 73 #define TK_ISNULL 73
#define TK_GT 74 #define TK_NOTNULL 74
#define TK_LE 75 #define TK_NE 75
#define TK_LT 76 #define TK_EQ 76
#define TK_GE 77 #define TK_GT 77
#define TK_ESCAPE 78 #define TK_LE 78
#define TK_BITAND 79 #define TK_LT 79
#define TK_BITOR 80 #define TK_GE 80
#define TK_LSHIFT 81 #define TK_ESCAPE 81
#define TK_RSHIFT 82 #define TK_BITAND 82
#define TK_PLUS 83 #define TK_BITOR 83
#define TK_MINUS 84 #define TK_LSHIFT 84
#define TK_STAR 85 #define TK_RSHIFT 85
#define TK_SLASH 86 #define TK_PLUS 86
#define TK_REM 87 #define TK_MINUS 87
#define TK_CONCAT 88 #define TK_STAR 88
#define TK_UMINUS 89 #define TK_SLASH 89
#define TK_UPLUS 90 #define TK_REM 90
#define TK_BITNOT 91 #define TK_CONCAT 91
#define TK_STRING 92 #define TK_UMINUS 92
#define TK_JOIN_KW 93 #define TK_UPLUS 93
#define TK_CONSTRAINT 94 #define TK_BITNOT 94
#define TK_DEFAULT 95 #define TK_STRING 95
#define TK_NULL 96 #define TK_JOIN_KW 96
#define TK_PRIMARY 97 #define TK_CONSTRAINT 97
#define TK_UNIQUE 98 #define TK_DEFAULT 98
#define TK_CHECK 99 #define TK_NULL 99
#define TK_REFERENCES 100 #define TK_PRIMARY 100
#define TK_COLLATE 101 #define TK_UNIQUE 101
#define TK_AUTOINCR 102 #define TK_CHECK 102
#define TK_ON 103 #define TK_REFERENCES 103
#define TK_DELETE 104 #define TK_COLLATE 104
#define TK_UPDATE 105 #define TK_AUTOINCR 105
#define TK_INSERT 106 #define TK_ON 106
#define TK_SET 107 #define TK_DELETE 107
#define TK_DEFERRABLE 108 #define TK_UPDATE 108
#define TK_FOREIGN 109 #define TK_INSERT 109
#define TK_DROP 110 #define TK_SET 110
#define TK_UNION 111 #define TK_DEFERRABLE 111
#define TK_ALL 112 #define TK_FOREIGN 112
#define TK_INTERSECT 113 #define TK_DROP 113
#define TK_EXCEPT 114 #define TK_UNION 114
#define TK_SELECT 115 #define TK_ALL 115
#define TK_DISTINCT 116 #define TK_INTERSECT 116
#define TK_DOT 117 #define TK_EXCEPT 117
#define TK_FROM 118 #define TK_SELECT 118
#define TK_JOIN 119 #define TK_DISTINCT 119
#define TK_USING 120 #define TK_DOT 120
#define TK_ORDER 121 #define TK_FROM 121
#define TK_BY 122 #define TK_JOIN 122
#define TK_GROUP 123 #define TK_USING 123
#define TK_HAVING 124 #define TK_ORDER 124
#define TK_LIMIT 125 #define TK_BY 125
#define TK_WHERE 126 #define TK_GROUP 126
#define TK_INTO 127 #define TK_HAVING 127
#define TK_VALUES 128 #define TK_LIMIT 128
#define TK_INTEGER 129 #define TK_WHERE 129
#define TK_FLOAT 130 #define TK_INTO 130
#define TK_BLOB 131 #define TK_VALUES 131
#define TK_REGISTER 132 #define TK_INTEGER 132
#define TK_VARIABLE 133 #define TK_FLOAT 133
#define TK_EXISTS 134 #define TK_BLOB 134
#define TK_CASE 135 #define TK_REGISTER 135
#define TK_WHEN 136 #define TK_VARIABLE 136
#define TK_THEN 137 #define TK_EXISTS 137
#define TK_ELSE 138 #define TK_CASE 138
#define TK_INDEX 139 #define TK_WHEN 139
#define TK_TO 140 #define TK_THEN 140
#define TK_ADD 141 #define TK_ELSE 141
#define TK_COLUMNKW 142 #define TK_INDEX 142
#define TK_TO 143
#define TK_ADD 144
#define TK_COLUMNKW 145

View file

@ -93,7 +93,7 @@ struct AttachKey { int type; Token key; };
// add them to the parse.h output file. // add them to the parse.h output file.
// //
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
COLUMN AGG_FUNCTION CONST_FUNC. COLUMN AGG_FUNCTION AGG_COLUMN CONST_FUNC.
// Input is a single SQL command // Input is a single SQL command
input ::= cmdlist. input ::= cmdlist.
@ -105,6 +105,7 @@ ecmd ::= explain cmdx SEMI.
explain ::= . { sqlite3BeginParse(pParse, 0); } explain ::= . { sqlite3BeginParse(pParse, 0); }
%ifndef SQLITE_OMIT_EXPLAIN %ifndef SQLITE_OMIT_EXPLAIN
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); } explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); }
%endif %endif
///////////////////// Begin and end transactions. //////////////////////////// ///////////////////// Begin and end transactions. ////////////////////////////
@ -172,7 +173,7 @@ id(A) ::= ID(X). {A = X;}
%fallback ID %fallback ID
ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH KEY IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN QUERY KEY
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
TEMP TRIGGER VACUUM VIEW TEMP TRIGGER VACUUM VIEW
%ifdef SQLITE_OMIT_COMPOUND_SELECT %ifdef SQLITE_OMIT_COMPOUND_SELECT
@ -660,9 +661,12 @@ expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
sqlite3ExprSpan(A,&X,&Y); sqlite3ExprSpan(A,&X,&Y);
} }
%endif // SQLITE_OMIT_CAST %endif // SQLITE_OMIT_CAST
expr(A) ::= ID(X) LP exprlist(Y) RP(E). { expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
A = sqlite3ExprFunction(Y, &X); A = sqlite3ExprFunction(Y, &X);
sqlite3ExprSpan(A,&X,&E); sqlite3ExprSpan(A,&X,&E);
if( D ){
A->flags |= EP_Distinct;
}
} }
expr(A) ::= ID(X) LP STAR RP(E). { expr(A) ::= ID(X) LP STAR RP(E). {
A = sqlite3ExprFunction(0, &X); A = sqlite3ExprFunction(0, &X);
@ -752,7 +756,11 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
ExprList *pList = sqlite3ExprListAppend(0, X, 0); ExprList *pList = sqlite3ExprListAppend(0, X, 0);
pList = sqlite3ExprListAppend(pList, Y, 0); pList = sqlite3ExprListAppend(pList, Y, 0);
A = sqlite3Expr(TK_BETWEEN, W, 0, 0); A = sqlite3Expr(TK_BETWEEN, W, 0, 0);
if( A ) A->pList = pList; if( A ){
A->pList = pList;
}else{
sqlite3ExprListDelete(pList);
}
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&W->span,&Y->span); sqlite3ExprSpan(A,&W->span,&Y->span);
} }
@ -772,21 +780,31 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
} }
expr(A) ::= LP(B) select(X) RP(E). { expr(A) ::= LP(B) select(X) RP(E). {
A = sqlite3Expr(TK_SELECT, 0, 0, 0); A = sqlite3Expr(TK_SELECT, 0, 0, 0);
if( A ) A->pSelect = X; if( A ){
if( !A ) sqlite3SelectDelete(X); A->pSelect = X;
}else{
sqlite3SelectDelete(X);
}
sqlite3ExprSpan(A,&B,&E); sqlite3ExprSpan(A,&B,&E);
} }
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] { expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
A = sqlite3Expr(TK_IN, X, 0, 0); A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pSelect = Y; if( A ){
if( !A ) sqlite3SelectDelete(Y); A->pSelect = Y;
}else{
sqlite3SelectDelete(Y);
}
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E); sqlite3ExprSpan(A,&X->span,&E);
} }
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] { expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z); SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z);
A = sqlite3Expr(TK_IN, X, 0, 0); A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0); if( A ){
A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
}else{
sqlite3SrcListDelete(pSrc);
}
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y); sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
} }
@ -795,15 +813,20 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
if( p ){ if( p ){
p->pSelect = Y; p->pSelect = Y;
sqlite3ExprSpan(p,&B,&E); sqlite3ExprSpan(p,&B,&E);
}else{
sqlite3SelectDelete(Y);
} }
if( !p ) sqlite3SelectDelete(Y);
} }
%endif // SQLITE_OMIT_SUBQUERY %endif // SQLITE_OMIT_SUBQUERY
/* CASE expressions */ /* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
A = sqlite3Expr(TK_CASE, X, Z, 0); A = sqlite3Expr(TK_CASE, X, Z, 0);
if( A ) A->pList = Y; if( A ){
A->pList = Y;
}else{
sqlite3ExprListDelete(Y);
}
sqlite3ExprSpan(A, &C, &E); sqlite3ExprSpan(A, &C, &E);
} }
%type case_exprlist {ExprList*} %type case_exprlist {ExprList*}

View file

@ -626,14 +626,6 @@ void sqlite3Pragma(
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){ if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
int i, j, addr; int i, j, addr;
/* Code that initializes the integrity check program. Set the
** error count 0
*/
static const VdbeOpList initCode[] = {
{ OP_Integer, 0, 0, 0},
{ OP_MemStore, 0, 1, 0},
};
/* Code that appears at the end of the integrity check. If no error /* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the ** messages have been generated, output OK. Otherwise output the
** error message ** error message
@ -650,7 +642,7 @@ void sqlite3Pragma(
if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC); sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode); sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
/* Do an integrity check on each database file */ /* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
@ -696,8 +688,7 @@ void sqlite3Pragma(
if( pTab->pIndex==0 ) continue; if( pTab->pIndex==0 ) continue;
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
sqlite3VdbeAddOp(v, OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
sqlite3VdbeAddOp(v, OP_MemStore, 1, 1);
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0); loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
@ -715,39 +706,38 @@ void sqlite3Pragma(
jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0); jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr); addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC); sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
sqlite3VdbeChangeP2(v, jmp2, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, jmp2);
} }
sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1); sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
sqlite3VdbeChangeP2(v, loopTop, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, loopTop);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
static const VdbeOpList cntIdx[] = { static const VdbeOpList cntIdx[] = {
{ OP_Integer, 0, 0, 0}, { OP_MemInt, 0, 2, 0},
{ OP_MemStore, 2, 1, 0}, { OP_Rewind, 0, 0, 0}, /* 1 */
{ OP_Rewind, 0, 0, 0}, /* 2 */
{ OP_MemIncr, 2, 0, 0}, { OP_MemIncr, 2, 0, 0},
{ OP_Next, 0, 0, 0}, /* 4 */ { OP_Next, 0, 0, 0}, /* 3 */
{ OP_MemLoad, 1, 0, 0}, { OP_MemLoad, 1, 0, 0},
{ OP_MemLoad, 2, 0, 0}, { OP_MemLoad, 2, 0, 0},
{ OP_Eq, 0, 0, 0}, /* 7 */ { OP_Eq, 0, 0, 0}, /* 6 */
{ OP_MemIncr, 0, 0, 0}, { OP_MemIncr, 0, 0, 0},
{ OP_String8, 0, 0, "wrong # of entries in index "}, { OP_String8, 0, 0, "wrong # of entries in index "},
{ OP_String8, 0, 0, 0}, /* 10 */ { OP_String8, 0, 0, 0}, /* 9 */
{ OP_Concat, 0, 0, 0}, { OP_Concat, 0, 0, 0},
{ OP_Callback, 1, 0, 0}, { OP_Callback, 1, 0, 0},
}; };
if( pIdx->tnum==0 ) continue; if( pIdx->tnum==0 ) continue;
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx); addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
sqlite3VdbeChangeP1(v, addr+2, j+2); sqlite3VdbeChangeP1(v, addr+1, j+2);
sqlite3VdbeChangeP2(v, addr+2, addr+5); sqlite3VdbeChangeP2(v, addr+1, addr+4);
sqlite3VdbeChangeP1(v, addr+4, j+2); sqlite3VdbeChangeP1(v, addr+3, j+2);
sqlite3VdbeChangeP2(v, addr+4, addr+3); sqlite3VdbeChangeP2(v, addr+3, addr+2);
sqlite3VdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx)); sqlite3VdbeJumpHere(v, addr+6);
sqlite3VdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC); sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC);
} }
} }
} }
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode)); sqlite3VdbeJumpHere(v, addr+2);
}else }else
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@ -903,13 +893,13 @@ void sqlite3Pragma(
Btree *pBt; Btree *pBt;
Pager *pPager; Pager *pPager;
if( db->aDb[i].zName==0 ) continue; if( db->aDb[i].zName==0 ) continue;
sqlite3VdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, P3_STATIC); sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC);
pBt = db->aDb[i].pBt; pBt = db->aDb[i].pBt;
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){ if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
sqlite3VdbeOp3(v, OP_String, 0, 0, "closed", P3_STATIC); sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC);
}else{ }else{
int j = sqlite3pager_lockstate(pPager); int j = sqlite3pager_lockstate(pPager);
sqlite3VdbeOp3(v, OP_String, 0, 0, sqlite3VdbeOp3(v, OP_String8, 0, 0,
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC); (j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
} }
sqlite3VdbeAddOp(v, OP_Callback, 2, 0); sqlite3VdbeAddOp(v, OP_Callback, 2, 0);

View file

@ -458,6 +458,12 @@ int sqlite3_prepare(
#ifndef SQLITE_OMIT_EXPLAIN #ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
if( sParse.explain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
sqlite3VdbeSetColName(sParse.pVdbe, 0, "order", P3_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 1, "from", P3_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 2, "detail", P3_STATIC);
}else{
sqlite3VdbeSetNumCols(sParse.pVdbe, 5); sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
@ -465,6 +471,7 @@ int sqlite3_prepare(
sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
} }
}
#endif #endif
prepare_out: prepare_out:

View file

@ -163,7 +163,15 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
} }
#endif #endif
#define etBUFSIZE 1000 /* Size of the output buffer */ /*
** On machines with a small stack size, you can redefine the
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for
** smaller values some %f conversions may go into an infinite loop.
*/
#ifndef SQLITE_PRINT_BUF_SIZE
# define SQLITE_PRINT_BUF_SIZE 350
#endif
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
/* /*
** The root program. All variations call this core. ** The root program. All variations call this core.
@ -440,9 +448,9 @@ static int vxprintf(
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0; exp = 0;
if( realvalue>0.0 ){ if( realvalue>0.0 ){
while( realvalue>1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; } while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
while( realvalue>1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; } while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; } while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
if( exp>350 || exp<-350 ){ if( exp>350 || exp<-350 ){
@ -718,7 +726,11 @@ static void mout(void *arg, const char *zNewText, int nNewChar){
memcpy(pM->zText, pM->zBase, pM->nChar); memcpy(pM->zText, pM->zBase, pM->nChar);
} }
}else{ }else{
pM->zText = pM->xRealloc(pM->zText, pM->nAlloc); char *zNew;
zNew = pM->xRealloc(pM->zText, pM->nAlloc);
if( zNew ){
pM->zText = zNew;
}
} }
} }
} }
@ -756,7 +768,10 @@ static char *base_vprintf(
memcpy(sM.zText, sM.zBase, sM.nChar+1); memcpy(sM.zText, sM.zBase, sM.nChar+1);
} }
}else if( sM.nAlloc>sM.nChar+10 ){ }else if( sM.nAlloc>sM.nChar+10 ){
sM.zText = xRealloc(sM.zText, sM.nChar+1); char *zNew = xRealloc(sM.zText, sM.nChar+1);
if( zNew ){
sM.zText = zNew;
}
} }
} }
return sM.zText; return sM.zText;
@ -774,7 +789,7 @@ static void *printf_realloc(void *old, int size){
** %-conversion extensions. ** %-conversion extensions.
*/ */
char *sqlite3VMPrintf(const char *zFormat, va_list ap){ char *sqlite3VMPrintf(const char *zFormat, va_list ap){
char zBase[1000]; char zBase[SQLITE_PRINT_BUF_SIZE];
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
} }
@ -785,7 +800,7 @@ char *sqlite3VMPrintf(const char *zFormat, va_list ap){
char *sqlite3MPrintf(const char *zFormat, ...){ char *sqlite3MPrintf(const char *zFormat, ...){
va_list ap; va_list ap;
char *z; char *z;
char zBase[1000]; char zBase[SQLITE_PRINT_BUF_SIZE];
va_start(ap, zFormat); va_start(ap, zFormat);
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
va_end(ap); va_end(ap);

File diff suppressed because it is too large Load diff

View file

@ -313,7 +313,7 @@ static void output_c_string(FILE *out, const char *z){
fputc('\\', out); fputc('\\', out);
fputc('r', out); fputc('r', out);
}else if( !isprint(c) ){ }else if( !isprint(c) ){
fprintf(out, "\\%03o", c); fprintf(out, "\\%03o", c&0xff);
}else{ }else{
fputc(c, out); fputc(c, out);
} }
@ -656,10 +656,14 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zType = azArg[1]; zType = azArg[1];
zSql = azArg[2]; zSql = azArg[2];
if( strcmp(zTable,"sqlite_sequence")!=0 ){ if( strcmp(zTable, "sqlite_sequence")==0 ){
fprintf(p->out, "%s;\n", zSql);
}else{
fprintf(p->out, "DELETE FROM sqlite_sequence;\n"); fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
}else if( strcmp(zTable, "sqlite_stat1")==0 ){
fprintf(p->out, "ANALYZE sqlite_master;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else{
fprintf(p->out, "%s;\n", zSql);
} }
if( strcmp(zType, "table")==0 ){ if( strcmp(zType, "table")==0 ){
@ -1290,7 +1294,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
"SELECT sql FROM " "SELECT sql FROM "
" (SELECT * FROM sqlite_master UNION ALL" " (SELECT * FROM sqlite_master UNION ALL"
" SELECT * FROM sqlite_temp_master) " " SELECT * FROM sqlite_temp_master) "
"WHERE type!='meta' AND sql NOTNULL " "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
"ORDER BY substr(type,2,1), name", "ORDER BY substr(type,2,1), name",
callback, &data, &zErrMsg callback, &data, &zErrMsg
); );
@ -1334,7 +1338,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( nArg==1 ){ if( nArg==1 ){
rc = sqlite3_get_table(p->db, rc = sqlite3_get_table(p->db,
"SELECT name FROM sqlite_master " "SELECT name FROM sqlite_master "
"WHERE type IN ('table','view') " "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'"
"UNION ALL " "UNION ALL "
"SELECT name FROM sqlite_temp_master " "SELECT name FROM sqlite_temp_master "
"WHERE type IN ('table','view') " "WHERE type IN ('table','view') "
@ -1698,6 +1702,13 @@ int main(int argc, char **argv){
} }
data.out = stdout; data.out = stdout;
#ifdef SQLITE_OMIT_MEMORYDB
if( data.zDbFilename==0 ){
fprintf(stderr,"%s: no database filename specified\n", argv[0]);
exit(1);
}
#endif
/* Go ahead and open the database file if it already exists. If the /* Go ahead and open the database file if it already exists. If the
** file does not exist, delay opening it. This prevents empty database ** file does not exist, delay opening it. This prevents empty database
** files from being created if a user mistypes the database name argument ** files from being created if a user mistypes the database name argument

View file

@ -373,8 +373,9 @@ void sqlite3_free_table(char **result);
** **
** We can use this text in an SQL statement as follows: ** We can use this text in an SQL statement as follows:
** **
** sqlite3_exec_printf(db, "INSERT INTO table VALUES('%q')", ** char *z = sqlite3_mprintf("INSERT INTO TABLES('%q')", zText);
** callback1, 0, 0, zText); ** sqlite3_exec(db, z, callback1, 0, 0);
** sqlite3_free(z);
** **
** Because the %q format string is used, the '\'' character in zText ** Because the %q format string is used, the '\'' character in zText
** is escaped and the SQL generated is as follows: ** is escaped and the SQL generated is as follows:
@ -464,11 +465,18 @@ int sqlite3_set_authorizer(
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
/* /*
** Register a function that is called at every invocation of sqlite3_exec() ** Register a function for tracing SQL command evaluation. The function
** or sqlite3_prepare(). This function can be used (for example) to generate ** registered by sqlite3_trace() is invoked at the first sqlite3_step()
** a log file of all SQL executed against a database. ** for the evaluation of an SQL statement. The function registered by
** sqlite3_profile() runs at the end of each SQL statement and includes
** information on how long that statement ran.
**
** The sqlite3_profile() API is currently considered experimental and
** is subject to change.
*/ */
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite_uint64), void*);
/* /*
** This routine configures a callback function - the progress callback - that ** This routine configures a callback function - the progress callback - that

View file

@ -16,6 +16,17 @@
#ifndef _SQLITEINT_H_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
/*
** Many people are failing to set -DNDEBUG=1 when compiling SQLite.
** Setting NDEBUG makes the code smaller and run faster. So the following
** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1
** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out
** feature.
*/
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
/* /*
** These #defines should enable >2GB file support on Posix if the ** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it. If the OS lacks ** underlying operating system supports it. If the OS lacks
@ -298,7 +309,7 @@ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
/* /*
** Forward references to structures ** Forward references to structures
*/ */
typedef struct AggExpr AggExpr; typedef struct AggInfo AggInfo;
typedef struct AuthContext AuthContext; typedef struct AuthContext AuthContext;
typedef struct CollSeq CollSeq; typedef struct CollSeq CollSeq;
typedef struct Column Column; typedef struct Column Column;
@ -422,6 +433,8 @@ struct sqlite3 {
int activeVdbeCnt; /* Number of vdbes currently executing */ int activeVdbeCnt; /* Number of vdbes currently executing */
void (*xTrace)(void*,const char*); /* Trace function */ void (*xTrace)(void*,const char*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */ void *pTraceArg; /* Argument to the trace function */
void (*xProfile)(void*,const char*,u64); /* Profiling function */
void *pProfileArg; /* Argument to profile function */
void *pCommitArg; /* Argument to xCommitCallback() */ void *pCommitArg; /* Argument to xCommitCallback() */
int (*xCommitCallback)(void*);/* Invoked at every commit. */ int (*xCommitCallback)(void*);/* Invoked at every commit. */
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
@ -511,7 +524,8 @@ struct FuncDef {
/* /*
** Possible values for FuncDef.flags ** Possible values for FuncDef.flags
*/ */
#define SQLITE_FUNC_LIKEOPT 0x01 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */
/* /*
** information about each column of an SQL table is held in an instance ** information about each column of an SQL table is held in an instance
@ -551,10 +565,19 @@ struct Column {
struct CollSeq { struct CollSeq {
char *zName; /* Name of the collating sequence, UTF-8 encoded */ char *zName; /* Name of the collating sequence, UTF-8 encoded */
u8 enc; /* Text encoding handled by xCmp() */ u8 enc; /* Text encoding handled by xCmp() */
u8 type; /* One of the SQLITE_COLL_... values below */
void *pUser; /* First argument to xCmp() */ void *pUser; /* First argument to xCmp() */
int (*xCmp)(void*,int, const void*, int, const void*); int (*xCmp)(void*,int, const void*, int, const void*);
}; };
/*
** Allowed values of CollSeq flags:
*/
#define SQLITE_COLL_BINARY 1 /* The default memcmp() collating sequence */
#define SQLITE_COLL_NOCASE 2 /* The built-in NOCASE collating sequence */
#define SQLITE_COLL_REVERSE 3 /* The built-in REVERSE collating sequence */
#define SQLITE_COLL_USER 0 /* Any other user-defined collating sequence */
/* /*
** A sort order can be either ASC or DESC. ** A sort order can be either ASC or DESC.
*/ */
@ -776,6 +799,49 @@ struct Token {
unsigned n : 31; /* Number of characters in this token */ unsigned n : 31; /* Number of characters in this token */
}; };
/*
** An instance of this structure contains information needed to generate
** code for a SELECT that contains aggregate functions.
**
** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
** pointer to this structure. The Expr.iColumn field is the index in
** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
** code for that node.
**
** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the
** original Select structure that describes the SELECT statement. These
** fields do not need to be freed when deallocating the AggInfo structure.
*/
struct AggInfo {
u8 directMode; /* Direct rendering mode means take data directly
** from source tables rather than from accumulators */
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
int sortingIdx; /* Cursor number of the sorting index */
ExprList *pGroupBy; /* The group by clause */
int nSortingColumn; /* Number of columns in the sorting index */
struct AggInfo_col { /* For each column used in source tables */
int iTable; /* Cursor number of the source table */
int iColumn; /* Column number within the source table */
int iSorterColumn; /* Column number in the sorting index */
int iMem; /* Memory location that acts as accumulator */
Expr *pExpr; /* The original expression */
} *aCol;
int nColumn; /* Number of used entries in aCol[] */
int nColumnAlloc; /* Number of slots allocated for aCol[] */
int nAccumulator; /* Number of columns that show through to the output.
** Additional columns are used only as parameters to
** aggregate functions */
struct AggInfo_func { /* For each aggregate function */
Expr *pExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */
int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Virtual table used to enforce DISTINCT */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
int nFuncAlloc; /* Number of slots allocated for aFunc[] */
};
/* /*
** Each node of an expression in the parse tree is an instance ** Each node of an expression in the parse tree is an instance
** of this structure. ** of this structure.
@ -835,9 +901,9 @@ struct Expr {
Token span; /* Complete text of the expression */ Token span; /* Complete text of the expression */
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** iColumn-th field of the iTable-th table. */ ** iColumn-th field of the iTable-th table. */
int iAgg; /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
** result from the iAgg-th element of the aggregator */ int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
int iAggCtx; /* The value to pass as P1 of OP_AggGet. */ int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
Select *pSelect; /* When the expression is a sub-select. Also the Select *pSelect; /* When the expression is a sub-select. Also the
** right side of "<expr> IN (<select>)" */ ** right side of "<expr> IN (<select>)" */
Table *pTab; /* Table for OP_Column expressions. */ Table *pTab; /* Table for OP_Column expressions. */
@ -850,7 +916,7 @@ struct Expr {
#define EP_Agg 0x02 /* Contains one or more aggregate functions */ #define EP_Agg 0x02 /* Contains one or more aggregate functions */
#define EP_Resolved 0x04 /* IDs have been resolved to COLUMNs */ #define EP_Resolved 0x04 /* IDs have been resolved to COLUMNs */
#define EP_Error 0x08 /* Expression contains one or more errors */ #define EP_Error 0x08 /* Expression contains one or more errors */
#define EP_Not 0x10 /* Operator preceeded by NOT */ #define EP_Distinct 0x10 /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */ #define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
#define EP_Dequoted 0x40 /* True if the string has been dequoted */ #define EP_Dequoted 0x40 /* True if the string has been dequoted */
@ -874,6 +940,7 @@ struct Expr {
struct ExprList { struct ExprList {
int nExpr; /* Number of expressions on the list */ int nExpr; /* Number of expressions on the list */
int nAlloc; /* Number of entries allocated below */ int nAlloc; /* Number of entries allocated below */
int iECursor; /* VDBE Cursor associated with this ExprList */
struct ExprList_item { struct ExprList_item {
Expr *pExpr; /* The list of expressions */ Expr *pExpr; /* The list of expressions */
char *zName; /* Token associated with this expression */ char *zName; /* Token associated with this expression */
@ -899,12 +966,12 @@ struct ExprList {
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k. ** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
*/ */
struct IdList { struct IdList {
int nId; /* Number of identifiers on the list */
int nAlloc; /* Number of entries allocated for a[] below */
struct IdList_item { struct IdList_item {
char *zName; /* Name of the identifier */ char *zName; /* Name of the identifier */
int idx; /* Index in some Table.aCol[] of a column named zName */ int idx; /* Index in some Table.aCol[] of a column named zName */
} *a; } *a;
int nId; /* Number of identifiers on the list */
int nAlloc; /* Number of entries allocated for a[] below */
}; };
/* /*
@ -944,11 +1011,12 @@ struct SrcList {
** Permitted values of the SrcList.a.jointype field ** Permitted values of the SrcList.a.jointype field
*/ */
#define JT_INNER 0x0001 /* Any kind of inner or cross join */ #define JT_INNER 0x0001 /* Any kind of inner or cross join */
#define JT_NATURAL 0x0002 /* True for a "natural" join */ #define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */
#define JT_LEFT 0x0004 /* Left outer join */ #define JT_NATURAL 0x0004 /* True for a "natural" join */
#define JT_RIGHT 0x0008 /* Right outer join */ #define JT_LEFT 0x0008 /* Left outer join */
#define JT_OUTER 0x0010 /* The "OUTER" keyword is present */ #define JT_RIGHT 0x0010 /* Right outer join */
#define JT_ERROR 0x0020 /* unknown or unsupported join type */ #define JT_OUTER 0x0020 /* The "OUTER" keyword is present */
#define JT_ERROR 0x0040 /* unknown or unsupported join type */
/* /*
** For each nested loop in a WHERE clause implementation, the WhereInfo ** For each nested loop in a WHERE clause implementation, the WhereInfo
@ -1018,8 +1086,9 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */ int nRef; /* Number of names resolved by this context */
int nErr; /* Number of errors encountered while resolving names */ int nErr; /* Number of errors encountered while resolving names */
u8 allowAgg; /* Aggregate functions allowed here */ u8 allowAgg; /* Aggregate functions allowed here */
u8 hasAgg; u8 hasAgg; /* True if aggregates are seen */
int nDepth; /* Depth of subquery recursion. 1 for no recursion */ int nDepth; /* Depth of subquery recursion. 1 for no recursion */
AggInfo *pAggInfo; /* Information about aggregates at this level */
NameContext *pNext; /* Next outer name context. NULL for outermost */ NameContext *pNext; /* Next outer name context. NULL for outermost */
}; };
@ -1032,64 +1101,55 @@ struct NameContext {
** limit and nOffset to the value of the offset (or 0 if there is not ** limit and nOffset to the value of the offset (or 0 if there is not
** offset). But later on, nLimit and nOffset become the memory locations ** offset). But later on, nLimit and nOffset become the memory locations
** in the VDBE that record the limit and offset counters. ** in the VDBE that record the limit and offset counters.
**
** addrOpenVirt[] entries contain the address of OP_OpenVirtual opcodes.
** These addresses must be stored so that we can go back and fill in
** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor
** the number of columns in P2 can be computed at the same time
** as the OP_OpenVirtual instruction is coded because not
** enough information about the compound query is known at that point.
** The KeyInfo for addrOpenVirt[0] and [1] contains collating sequences
** for the result set. The KeyInfo for addrOpenVirt[2] contains collating
** sequences for the ORDER BY clause.
*/ */
struct Select { struct Select {
ExprList *pEList; /* The fields of the result */ ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
u8 isDistinct; /* True if the DISTINCT keyword is present */ u8 isDistinct; /* True if the DISTINCT keyword is present */
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
u8 isAgg; /* True if this is an aggregate query */
u8 usesVirt; /* True if uses an OpenVirtual opcode */
u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */
SrcList *pSrc; /* The FROM clause */ SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */ Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */ ExprList *pGroupBy; /* The GROUP BY clause */
Expr *pHaving; /* The HAVING clause */ Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY clause */ ExprList *pOrderBy; /* The ORDER BY clause */
Select *pPrior; /* Prior select in a compound select statement */ Select *pPrior; /* Prior select in a compound select statement */
Select *pRightmost; /* Right-most select in a compound select statement */
Expr *pLimit; /* LIMIT expression. NULL means not used. */ Expr *pLimit; /* LIMIT expression. NULL means not used. */
Expr *pOffset; /* OFFSET expression. NULL means not used. */ Expr *pOffset; /* OFFSET expression. NULL means not used. */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
IdList **ppOpenVirtual;/* OP_OpenVirtual addresses used by multi-selects */ int addrOpenVirt[3]; /* OP_OpenVirtual opcodes related to this select */
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
u8 isAgg; /* True if this is an aggregate query */
}; };
/* /*
** The results of a select can be distributed in several ways. ** The results of a select can be distributed in several ways.
*/ */
#define SRT_Callback 1 /* Invoke a callback with each row of result */ #define SRT_Union 1 /* Store result as keys in an index */
#define SRT_Mem 2 /* Store result in a memory cell */ #define SRT_Except 2 /* Remove result from a UNION index */
#define SRT_Set 3 /* Store result as unique keys in a table */ #define SRT_Discard 3 /* Do not save the results anywhere */
#define SRT_Union 5 /* Store result as keys in a table */
#define SRT_Except 6 /* Remove result from a UNION table */
#define SRT_Table 7 /* Store result as data with a unique key */
#define SRT_TempTable 8 /* Store result in a trasient table */
#define SRT_Discard 9 /* Do not save the results anywhere */
#define SRT_Sorter 10 /* Store results in the sorter */
#define SRT_Subroutine 11 /* Call a subroutine to handle results */
#define SRT_Exists 12 /* Put 0 or 1 in a memory cell */
/* /* The ORDER BY clause is ignored for all of the above */
** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)") #define IgnorableOrderby(X) (X<=SRT_Discard)
** we have to do some additional analysis of expressions. An instance
** of the following structure holds information about a single subexpression #define SRT_Callback 4 /* Invoke a callback with each row of result */
** somewhere in the SELECT statement. An array of these structures holds #define SRT_Mem 5 /* Store result in a memory cell */
** all the information we need to generate code for aggregate #define SRT_Set 6 /* Store non-null results as keys in an index */
** expressions. #define SRT_Table 7 /* Store result as data with an automatic rowid */
** #define SRT_VirtualTab 8 /* Create virtual table and store like SRT_Table */
** Note that when analyzing a SELECT containing aggregates, both #define SRT_Subroutine 9 /* Call a subroutine to handle results */
** non-aggregate field variables and aggregate functions are stored #define SRT_Exists 10 /* Put 0 or 1 in a memory cell */
** in the AggExpr array of the Parser structure.
**
** The pExpr field points to an expression that is part of either the
** field list, the GROUP BY clause, the HAVING clause or the ORDER BY
** clause. The expression will be freed when those clauses are cleaned
** up. Do not try to delete the expression attached to AggExpr.pExpr.
**
** If AggExpr.pExpr==0, that means the expression is "count(*)".
*/
struct AggExpr {
int isAgg; /* if TRUE contains an aggregate function */
Expr *pExpr; /* The expression */
FuncDef *pFunc; /* Information about the aggregate function */
};
/* /*
** An SQL parser context. A copy of this structure is passed through ** An SQL parser context. A copy of this structure is passed through
@ -1110,7 +1170,6 @@ struct Parse {
u8 nameClash; /* A permanent table name clashes with temp table name */ u8 nameClash; /* A permanent table name clashes with temp table name */
u8 checkSchema; /* Causes schema cookie check after an error */ u8 checkSchema; /* Causes schema cookie check after an error */
u8 nested; /* Number of nested calls to the parser/code generator */ u8 nested; /* Number of nested calls to the parser/code generator */
u8 fillAgg; /* If true, ignore the Expr.iAgg field. Normally false */
int nErr; /* Number of errors seen */ int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */ int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */ int nMem; /* Number of memory cells used so far */
@ -1137,9 +1196,6 @@ struct Parse {
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
TriggerStack *trigStack; /* Trigger actions being coded */ TriggerStack *trigStack; /* Trigger actions being coded */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
int nAgg; /* Number of aggregate expressions */
AggExpr *aAgg; /* An array of aggregate expressions */
int nMaxDepth; /* Maximum depth of subquery recursion */
}; };
/* /*
@ -1319,6 +1375,19 @@ typedef struct {
*/ */
extern int sqlite3_always_code_trigger_setup; extern int sqlite3_always_code_trigger_setup;
/*
** The SQLITE_CORRUPT_BKPT macro can be either a constant (for production
** builds) or a function call (for debugging). If it is a function call,
** it allows the operator to set a breakpoint at the spot where database
** corruption is first detected.
*/
#ifdef SQLITE_DEBUG
extern int sqlite3Corrupt(void);
# define SQLITE_CORRUPT_BKPT sqlite3Corrupt()
#else
# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT
#endif
/* /*
** Internal function prototypes ** Internal function prototypes
*/ */
@ -1346,6 +1415,7 @@ void sqlite3RealToSortable(double r, char *);
# define sqlite3CheckMemory(a,b) # define sqlite3CheckMemory(a,b)
# define sqlite3MallocX sqlite3Malloc # define sqlite3MallocX sqlite3Malloc
#endif #endif
void sqlite3ReallocOrFree(void**,int);
void sqlite3FreeX(void*); void sqlite3FreeX(void*);
void *sqlite3MallocX(int); void *sqlite3MallocX(int);
char *sqlite3MPrintf(const char*, ...); char *sqlite3MPrintf(const char*, ...);
@ -1396,6 +1466,7 @@ void sqlite3EndTable(Parse*,Token*,Token*,Select*);
void sqlite3DropTable(Parse*, SrcList*, int); void sqlite3DropTable(Parse*, SrcList*, int);
void sqlite3DeleteTable(sqlite3*, Table*); void sqlite3DeleteTable(sqlite3*, Table*);
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int); void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
int sqlite3ArrayAllocate(void**,int,int);
IdList *sqlite3IdListAppend(IdList*, Token*); IdList *sqlite3IdListAppend(IdList*, Token*);
int sqlite3IdListIndex(IdList*,const char*); int sqlite3IdListIndex(IdList*,const char*);
SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
@ -1440,6 +1511,7 @@ int sqlite3ExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*); int sqliteFuncId(Token*);
int sqlite3ExprResolveNames(NameContext *, Expr *); int sqlite3ExprResolveNames(NameContext *, Expr *);
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*); Vdbe *sqlite3GetVdbe(Parse*);
void sqlite3Randomness(int, void*); void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*); void sqlite3RollbackAll(sqlite3*);
@ -1557,7 +1629,7 @@ const void *sqlite3ValueText(sqlite3_value*, u8);
int sqlite3ValueBytes(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8);
void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
void sqlite3ValueFree(sqlite3_value*); void sqlite3ValueFree(sqlite3_value*);
sqlite3_value *sqlite3ValueNew(); sqlite3_value *sqlite3ValueNew(void);
sqlite3_value *sqlite3GetTransientValue(sqlite3*db); sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **); int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
@ -1583,7 +1655,7 @@ int sqlite3FindDb(sqlite3*, Token*);
void sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3AnalysisLoad(sqlite3*,int iDB);
void sqlite3DefaultRowEst(Index*); void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int); void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,char*); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
#include "sseInt.h" #include "sseInt.h"

View file

@ -84,6 +84,7 @@ struct SqliteDb {
char *zBusy; /* The busy callback routine */ char *zBusy; /* The busy callback routine */
char *zCommit; /* The commit hook callback routine */ char *zCommit; /* The commit hook callback routine */
char *zTrace; /* The trace callback routine */ char *zTrace; /* The trace callback routine */
char *zProfile; /* The profile callback routine */
char *zProgress; /* The progress callback routine */ char *zProgress; /* The progress callback routine */
char *zAuth; /* The authorization callback routine */ char *zAuth; /* The authorization callback routine */
char *zNull; /* Text to substitute for an SQL NULL value */ char *zNull; /* Text to substitute for an SQL NULL value */
@ -190,6 +191,9 @@ static void DbDeleteCmd(void *db){
if( pDb->zTrace ){ if( pDb->zTrace ){
Tcl_Free(pDb->zTrace); Tcl_Free(pDb->zTrace);
} }
if( pDb->zProfile ){
Tcl_Free(pDb->zProfile);
}
if( pDb->zAuth ){ if( pDb->zAuth ){
Tcl_Free(pDb->zAuth); Tcl_Free(pDb->zAuth);
} }
@ -247,6 +251,25 @@ static void DbTraceHandler(void *cd, const char *zSql){
Tcl_ResetResult(pDb->interp); Tcl_ResetResult(pDb->interp);
} }
/*
** This routine is called by the SQLite profile handler after a statement
** SQL has executed. The TCL script in pDb->zProfile is evaluated.
*/
static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){
SqliteDb *pDb = (SqliteDb*)cd;
Tcl_DString str;
char zTm[100];
sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm);
Tcl_DStringInit(&str);
Tcl_DStringAppend(&str, pDb->zProfile, -1);
Tcl_DStringAppendElement(&str, zSql);
Tcl_DStringAppendElement(&str, zTm);
Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
Tcl_DStringFree(&str);
Tcl_ResetResult(pDb->interp);
}
/* /*
** This routine is called when a transaction is committed. The ** This routine is called when a transaction is committed. The
** TCL script in pDb->zCommit is executed. If it returns non-zero or ** TCL script in pDb->zCommit is executed. If it returns non-zero or
@ -589,9 +612,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"collation_needed", "commit_hook", "complete", "collation_needed", "commit_hook", "complete",
"copy", "errorcode", "eval", "copy", "errorcode", "eval",
"function", "last_insert_rowid", "nullvalue", "function", "last_insert_rowid", "nullvalue",
"onecolumn", "progress", "rekey", "onecolumn", "profile", "progress",
"timeout", "total_changes", "trace", "rekey", "timeout", "total_changes",
"transaction", "version", 0 "trace", "transaction", "version",
0
}; };
enum DB_enum { enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CACHE, DB_AUTHORIZER, DB_BUSY, DB_CACHE,
@ -599,9 +623,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
DB_COPY, DB_ERRORCODE, DB_EVAL, DB_COPY, DB_ERRORCODE, DB_EVAL,
DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE, DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
DB_ONECOLUMN, DB_PROGRESS, DB_REKEY, DB_ONECOLUMN, DB_PROFILE, DB_PROGRESS,
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, DB_REKEY, DB_TIMEOUT, DB_TOTAL_CHANGES,
DB_TRANSACTION, DB_VERSION, DB_TRACE, DB_TRANSACTION, DB_VERSION
}; };
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@ -780,44 +804,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/* $db commit_hook ?CALLBACK?
**
** Invoke the given callback just before committing every SQL transaction.
** If the callback throws an exception or returns non-zero, then the
** transaction is aborted. If CALLBACK is an empty string, the callback
** is disabled.
*/
case DB_COMMIT_HOOK: {
if( objc>3 ){
Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
return TCL_ERROR;
}else if( objc==2 ){
if( pDb->zCommit ){
Tcl_AppendResult(interp, pDb->zCommit, 0);
}
}else{
char *zCommit;
int len;
if( pDb->zCommit ){
Tcl_Free(pDb->zCommit);
}
zCommit = Tcl_GetStringFromObj(objv[2], &len);
if( zCommit && len>0 ){
pDb->zCommit = Tcl_Alloc( len + 1 );
strcpy(pDb->zCommit, zCommit);
}else{
pDb->zCommit = 0;
}
if( pDb->zCommit ){
pDb->interp = interp;
sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);
}else{
sqlite3_commit_hook(pDb->db, 0, 0);
}
}
break;
}
/* /*
** $db collate NAME SCRIPT ** $db collate NAME SCRIPT
** **
@ -870,6 +856,44 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/* $db commit_hook ?CALLBACK?
**
** Invoke the given callback just before committing every SQL transaction.
** If the callback throws an exception or returns non-zero, then the
** transaction is aborted. If CALLBACK is an empty string, the callback
** is disabled.
*/
case DB_COMMIT_HOOK: {
if( objc>3 ){
Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
return TCL_ERROR;
}else if( objc==2 ){
if( pDb->zCommit ){
Tcl_AppendResult(interp, pDb->zCommit, 0);
}
}else{
char *zCommit;
int len;
if( pDb->zCommit ){
Tcl_Free(pDb->zCommit);
}
zCommit = Tcl_GetStringFromObj(objv[2], &len);
if( zCommit && len>0 ){
pDb->zCommit = Tcl_Alloc( len + 1 );
strcpy(pDb->zCommit, zCommit);
}else{
pDb->zCommit = 0;
}
if( pDb->zCommit ){
pDb->interp = interp;
sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);
}else{
sqlite3_commit_hook(pDb->db, 0, 0);
}
}
break;
}
/* $db complete SQL /* $db complete SQL
** **
** Return TRUE if SQL is a complete SQL statement. Return FALSE if ** Return TRUE if SQL is a complete SQL statement. Return FALSE if
@ -891,6 +915,192 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
**
** Copy data into table from filename, optionally using SEPARATOR
** as column separators. If a column contains a null string, or the
** value of NULLINDICATOR, a NULL is inserted for the column.
** conflict-algorithm is one of the sqlite conflict algorithms:
** rollback, abort, fail, ignore, replace
** On success, return the number of lines processed, not necessarily same
** as 'db changes' due to conflict-algorithm selected.
**
** This code is basically an implementation/enhancement of
** the sqlite3 shell.c ".import" command.
**
** This command usage is equivalent to the sqlite2.x COPY statement,
** which imports file data into a table using the PostgreSQL COPY file format:
** $db copy $conflit_algo $table_name $filename \t \\N
*/
case DB_COPY: {
char *zTable; /* Insert data into this table */
char *zFile; /* The file from which to extract data */
char *zConflict; /* The conflict algorithm to use */
sqlite3_stmt *pStmt; /* A statement */
int rc; /* Result code */
int nCol; /* Number of columns in the table */
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
int nSep; /* Number of bytes in zSep[] */
int nNull; /* Number of bytes in zNull[] */
char *zSql; /* An SQL statement */
char *zLine; /* A single line of input from the file */
char **azCol; /* zLine[] broken up into columns */
char *zCommit; /* How to commit changes */
FILE *in; /* The input file */
int lineno = 0; /* Line number of input file */
char zLineNum[80]; /* Line number print buffer */
Tcl_Obj *pResult; /* interp result */
char *zSep;
char *zNull;
if( objc<5 || objc>7 ){
Tcl_WrongNumArgs(interp, 2, objv,
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
return TCL_ERROR;
}
if( objc>=6 ){
zSep = Tcl_GetStringFromObj(objv[5], 0);
}else{
zSep = "\t";
}
if( objc>=7 ){
zNull = Tcl_GetStringFromObj(objv[6], 0);
}else{
zNull = "";
}
zConflict = Tcl_GetStringFromObj(objv[2], 0);
zTable = Tcl_GetStringFromObj(objv[3], 0);
zFile = Tcl_GetStringFromObj(objv[4], 0);
nSep = strlen(zSep);
nNull = strlen(zNull);
if( nSep==0 ){
Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0);
return TCL_ERROR;
}
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
sqlite3StrICmp(zConflict, "abort" ) != 0 &&
sqlite3StrICmp(zConflict, "fail" ) != 0 &&
sqlite3StrICmp(zConflict, "ignore" ) != 0 &&
sqlite3StrICmp(zConflict, "replace" ) != 0 ) {
Tcl_AppendResult(interp, "Error: \"", zConflict,
"\", conflict-algorithm must be one of: rollback, "
"abort, fail, ignore, or replace", 0);
return TCL_ERROR;
}
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
if( zSql==0 ){
Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
return TCL_ERROR;
}
nByte = strlen(zSql);
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
nCol = 0;
}else{
nCol = sqlite3_column_count(pStmt);
}
sqlite3_finalize(pStmt);
if( nCol==0 ) {
return TCL_ERROR;
}
zSql = malloc( nByte + 50 + nCol*2 );
if( zSql==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
return TCL_ERROR;
}
sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
zConflict, zTable);
j = strlen(zSql);
for(i=1; i<nCol; i++){
zSql[j++] = ',';
zSql[j++] = '?';
}
zSql[j++] = ')';
zSql[j] = 0;
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
in = fopen(zFile, "rb");
if( in==0 ){
Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
if( azCol==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
return TCL_ERROR;
}
sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
while( (zLine = local_getline(0, in))!=0 ){
char *z;
i = 0;
lineno++;
azCol[0] = zLine;
for(i=0, z=zLine; *z; z++){
if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
*z = 0;
i++;
if( i<nCol ){
azCol[i] = &z[nSep];
z += nSep-1;
}
}
}
if( i+1!=nCol ){
char *zErr;
zErr = malloc(200 + strlen(zFile));
sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i+1);
Tcl_AppendResult(interp, zErr, 0);
free(zErr);
zCommit = "ROLLBACK";
break;
}
for(i=0; i<nCol; i++){
/* check for null data, if so, bind as null */
if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) {
sqlite3_bind_null(pStmt, i+1);
}else{
sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
}
}
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
free(zLine);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
zCommit = "ROLLBACK";
break;
}
}
free(azCol);
fclose(in);
sqlite3_finalize(pStmt);
sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
if( zCommit[0] == 'C' ){
/* success, set result as number of lines processed */
pResult = Tcl_GetObjResult(interp);
Tcl_SetIntObj(pResult, lineno);
rc = TCL_OK;
}else{
/* failure, append lineno where failed */
sprintf(zLineNum,"%d",lineno);
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
rc = TCL_ERROR;
}
break;
}
/* /*
** $db errorcode ** $db errorcode
** **
@ -1301,6 +1511,37 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/*
** $db nullvalue ?STRING?
**
** Change text used when a NULL comes back from the database. If ?STRING?
** is not present, then the current string used for NULL is returned.
** If STRING is present, then STRING is returned.
**
*/
case DB_NULLVALUE: {
if( objc!=2 && objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE");
return TCL_ERROR;
}
if( objc==3 ){
int len;
char *zNull = Tcl_GetStringFromObj(objv[2], &len);
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
}
if( zNull && len>0 ){
pDb->zNull = Tcl_Alloc( len + 1 );
strncpy(pDb->zNull, zNull, len);
pDb->zNull[len] = '\0';
}else{
pDb->zNull = 0;
}
}
Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull));
break;
}
/* /*
** $db last_insert_rowid ** $db last_insert_rowid
** **
@ -1365,6 +1606,45 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/* $db profile ?CALLBACK?
**
** Make arrangements to invoke the CALLBACK routine after each SQL statement
** that has run. The text of the SQL and the amount of elapse time are
** appended to CALLBACK before the script is run.
*/
case DB_PROFILE: {
if( objc>3 ){
Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
return TCL_ERROR;
}else if( objc==2 ){
if( pDb->zProfile ){
Tcl_AppendResult(interp, pDb->zProfile, 0);
}
}else{
char *zProfile;
int len;
if( pDb->zProfile ){
Tcl_Free(pDb->zProfile);
}
zProfile = Tcl_GetStringFromObj(objv[2], &len);
if( zProfile && len>0 ){
pDb->zProfile = Tcl_Alloc( len + 1 );
strcpy(pDb->zProfile, zProfile);
}else{
pDb->zProfile = 0;
}
#ifndef SQLITE_OMIT_TRACE
if( pDb->zProfile ){
pDb->interp = interp;
sqlite3_profile(pDb->db, DbProfileHandler, pDb);
}else{
sqlite3_profile(pDb->db, 0, 0);
}
#endif
}
break;
}
/* /*
** $db rekey KEY ** $db rekey KEY
** **
@ -1404,37 +1684,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/*
** $db nullvalue ?STRING?
**
** Change text used when a NULL comes back from the database. If ?STRING?
** is not present, then the current string used for NULL is returned.
** If STRING is present, then STRING is returned.
**
*/
case DB_NULLVALUE: {
if( objc!=2 && objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE");
return TCL_ERROR;
}
if( objc==3 ){
int len;
char *zNull = Tcl_GetStringFromObj(objv[2], &len);
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
}
if( zNull && len>0 ){
pDb->zNull = Tcl_Alloc( len + 1 );
strncpy(pDb->zNull, zNull, len);
pDb->zNull[len] = '\0';
}else{
pDb->zNull = 0;
}
}
Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull));
break;
}
/* /*
** $db total_changes ** $db total_changes
** **
@ -1479,12 +1728,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{ }else{
pDb->zTrace = 0; pDb->zTrace = 0;
} }
#ifndef SQLITE_OMIT_TRACE
if( pDb->zTrace ){ if( pDb->zTrace ){
pDb->interp = interp; pDb->interp = interp;
sqlite3_trace(pDb->db, DbTraceHandler, pDb); sqlite3_trace(pDb->db, DbTraceHandler, pDb);
}else{ }else{
sqlite3_trace(pDb->db, 0, 0); sqlite3_trace(pDb->db, 0, 0);
} }
#endif
} }
break; break;
} }
@ -1546,192 +1797,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
**
** Copy data into table from filename, optionally using SEPARATOR
** as column separators. If a column contains a null string, or the
** value of NULLINDICATOR, a NULL is inserted for the column.
** conflict-algorithm is one of the sqlite conflict algorithms:
** rollback, abort, fail, ignore, replace
** On success, return the number of lines processed, not necessarily same
** as 'db changes' due to conflict-algorithm selected.
**
** This code is basically an implementation/enhancement of
** the sqlite3 shell.c ".import" command.
**
** This command usage is equivalent to the sqlite2.x COPY statement,
** which imports file data into a table using the PostgreSQL COPY file format:
** $db copy $conflit_algo $table_name $filename \t \\N
*/
case DB_COPY: {
char *zTable; /* Insert data into this table */
char *zFile; /* The file from which to extract data */
char *zConflict; /* The conflict algorithm to use */
sqlite3_stmt *pStmt; /* A statement */
int rc; /* Result code */
int nCol; /* Number of columns in the table */
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
int nSep; /* Number of bytes in zSep[] */
int nNull; /* Number of bytes in zNull[] */
char *zSql; /* An SQL statement */
char *zLine; /* A single line of input from the file */
char **azCol; /* zLine[] broken up into columns */
char *zCommit; /* How to commit changes */
FILE *in; /* The input file */
int lineno = 0; /* Line number of input file */
char zLineNum[80]; /* Line number print buffer */
Tcl_Obj *pResult; /* interp result */
char *zSep;
char *zNull;
if( objc<5 || objc>7 ){
Tcl_WrongNumArgs(interp, 2, objv,
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
return TCL_ERROR;
}
if( objc>=6 ){
zSep = Tcl_GetStringFromObj(objv[5], 0);
}else{
zSep = "\t";
}
if( objc>=7 ){
zNull = Tcl_GetStringFromObj(objv[6], 0);
}else{
zNull = "";
}
zConflict = Tcl_GetStringFromObj(objv[2], 0);
zTable = Tcl_GetStringFromObj(objv[3], 0);
zFile = Tcl_GetStringFromObj(objv[4], 0);
nSep = strlen(zSep);
nNull = strlen(zNull);
if( nSep==0 ){
Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0);
return TCL_ERROR;
}
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
sqlite3StrICmp(zConflict, "abort" ) != 0 &&
sqlite3StrICmp(zConflict, "fail" ) != 0 &&
sqlite3StrICmp(zConflict, "ignore" ) != 0 &&
sqlite3StrICmp(zConflict, "replace" ) != 0 ) {
Tcl_AppendResult(interp, "Error: \"", zConflict,
"\", conflict-algorithm must be one of: rollback, "
"abort, fail, ignore, or replace", 0);
return TCL_ERROR;
}
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
if( zSql==0 ){
Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
return TCL_ERROR;
}
nByte = strlen(zSql);
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
nCol = 0;
}else{
nCol = sqlite3_column_count(pStmt);
}
sqlite3_finalize(pStmt);
if( nCol==0 ) {
return TCL_ERROR;
}
zSql = malloc( nByte + 50 + nCol*2 );
if( zSql==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
return TCL_ERROR;
}
sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
zConflict, zTable);
j = strlen(zSql);
for(i=1; i<nCol; i++){
zSql[j++] = ',';
zSql[j++] = '?';
}
zSql[j++] = ')';
zSql[j] = 0;
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
in = fopen(zFile, "rb");
if( in==0 ){
Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
if( azCol==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
return TCL_ERROR;
}
sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
while( (zLine = local_getline(0, in))!=0 ){
char *z;
i = 0;
lineno++;
azCol[0] = zLine;
for(i=0, z=zLine; *z; z++){
if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
*z = 0;
i++;
if( i<nCol ){
azCol[i] = &z[nSep];
z += nSep-1;
}
}
}
if( i+1!=nCol ){
char *zErr;
zErr = malloc(200 + strlen(zFile));
sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i+1);
Tcl_AppendResult(interp, zErr, 0);
free(zErr);
zCommit = "ROLLBACK";
break;
}
for(i=0; i<nCol; i++){
/* check for null data, if so, bind as null */
if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) {
sqlite3_bind_null(pStmt, i+1);
}else{
sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
}
}
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
free(zLine);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
zCommit = "ROLLBACK";
break;
}
}
free(azCol);
fclose(in);
sqlite3_finalize(pStmt);
sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
if( zCommit[0] == 'C' ){
/* success, set result as number of lines processed */
pResult = Tcl_GetObjResult(interp);
Tcl_SetIntObj(pResult, lineno);
rc = TCL_OK;
}else{
/* failure, append lineno where failed */
sprintf(zLineNum,"%d",lineno);
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
rc = TCL_ERROR;
}
break;
}
/* $db version /* $db version
** **
** Return the version string for this database. ** Return the version string for this database.

View file

@ -661,7 +661,7 @@ static int sqlite3_mprintf_str(
} }
/* /*
** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE ** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE
** **
** Call mprintf with two integer arguments and one double argument ** Call mprintf with two integer arguments and one double argument
*/ */
@ -676,7 +676,7 @@ static int sqlite3_mprintf_double(
char *z; char *z;
if( argc!=5 ){ if( argc!=5 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" FORMAT INT INT STRING\"", 0); " FORMAT INT INT DOUBLE\"", 0);
return TCL_ERROR; return TCL_ERROR;
} }
for(i=2; i<4; i++){ for(i=2; i<4; i++){
@ -690,7 +690,7 @@ static int sqlite3_mprintf_double(
} }
/* /*
** Usage: sqlite3_mprintf_str FORMAT DOUBLE DOUBLE ** Usage: sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE
** **
** Call mprintf with a single double argument which is the product of the ** Call mprintf with a single double argument which is the product of the
** two arguments given above. This is used to generate overflow and underflow ** two arguments given above. This is used to generate overflow and underflow
@ -744,6 +744,40 @@ static int sqlite3_mprintf_stronly(
return TCL_OK; return TCL_OK;
} }
/*
** Usage: sqlite3_mprintf_hexdouble FORMAT HEX
**
** Call mprintf with a single double argument which is derived from the
** hexadecimal encoding of an IEEE double.
*/
static int sqlite3_mprintf_hexdouble(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
char **argv /* Text of each argument */
){
char *z;
double r;
unsigned x1, x2;
long long unsigned d;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" FORMAT STRING\"", 0);
return TCL_ERROR;
}
if( sscanf(argv[2], "%08x%08x", &x2, &x1)!=2 ){
Tcl_AppendResult(interp, "2nd argument should be 16-characters of hex", 0);
return TCL_ERROR;
}
d = x2;
d = (d<<32) + x1;
memcpy(&r, &d, sizeof(r));
z = sqlite3_mprintf(argv[1], r);
Tcl_AppendResult(interp, z, 0);
sqlite3_free(z);
return TCL_OK;
}
/* /*
** Usage: sqlite_malloc_fail N ?REPEAT-INTERVAL? ** Usage: sqlite_malloc_fail N ?REPEAT-INTERVAL?
** **
@ -1107,6 +1141,7 @@ static int test_collate_func(
Tcl_Interp *i = pTestCollateInterp; Tcl_Interp *i = pTestCollateInterp;
int encin = (int)pCtx; int encin = (int)pCtx;
int res; int res;
int n;
sqlite3_value *pVal; sqlite3_value *pVal;
Tcl_Obj *pX; Tcl_Obj *pX;
@ -1130,9 +1165,11 @@ static int test_collate_func(
pVal = sqlite3ValueNew(); pVal = sqlite3ValueNew();
sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC); sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1)); n = sqlite3_value_bytes(pVal);
Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),n));
sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC); sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1)); n = sqlite3_value_bytes(pVal);
Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),n));
sqlite3ValueFree(pVal); sqlite3ValueFree(pVal);
Tcl_EvalObjEx(i, pX, 0); Tcl_EvalObjEx(i, pX, 0);
@ -2620,27 +2657,51 @@ static int test_interrupt(
return TCL_OK; return TCL_OK;
} }
static u8 *sqlite3_stack_baseline = 0;
/* /*
** Usage: sqlite3_sleep ms ** Fill the stack with a known bitpattern.
**
** Sleep for the specified number of ms.
*/ */
#if 0 static void prepStack(void){
static int test_sleep( int i;
u32 bigBuf[65536];
for(i=0; i<sizeof(bigBuf); i++) bigBuf[i] = 0xdeadbeef;
sqlite3_stack_baseline = (u8*)&bigBuf[65536];
}
/*
** Get the current stack depth. Used for debugging only.
*/
u64 sqlite3StackDepth(void){
u8 x;
return (u64)(sqlite3_stack_baseline - &x);
}
/*
** Usage: sqlite3_stack_used DB SQL
**
** Try to measure the amount of stack space used by a call to sqlite3_exec
*/
static int test_stack_used(
void * clientData, void * clientData,
Tcl_Interp *interp, Tcl_Interp *interp,
int argc, int argc,
char **argv char **argv
){ ){
sqlite3 *db; sqlite3 *db;
if( argc!=2 ){ int i;
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ms", 0); if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB SQL", 0);
return TCL_ERROR; return TCL_ERROR;
} }
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_sleep(atoi(argv[1])))); if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
prepStack();
sqlite3_exec(db, argv[2], 0, 0, 0);
for(i=65535; i>=0 && ((u32*)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){}
Tcl_SetObjResult(interp, Tcl_NewIntObj(i*4));
return TCL_OK; return TCL_OK;
} }
#endif
/* /*
** Usage: sqlite_delete_function DB function-name ** Usage: sqlite_delete_function DB function-name
@ -2954,6 +3015,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "0", TCL_GLOBAL_ONLY);
#endif #endif
#ifdef SQLITE_OMIT_TRACE
Tcl_SetVar2(interp, "sqlite_options", "trace", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "trace", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_TRIGGER #ifdef SQLITE_OMIT_TRIGGER
Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL_GLOBAL_ONLY);
#else #else
@ -3004,6 +3071,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly}, { "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly},
{ "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double }, { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double },
{ "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled }, { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled },
{ "sqlite3_mprintf_hexdouble", (Tcl_CmdProc*)sqlite3_mprintf_hexdouble},
{ "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z },
{ "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
@ -3029,6 +3097,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite_delete_function", (Tcl_CmdProc*)delete_function }, { "sqlite_delete_function", (Tcl_CmdProc*)delete_function },
{ "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation }, { "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation },
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit }, { "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
}; };
static struct { static struct {
char *zName; char *zName;
@ -3111,12 +3180,17 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
extern int sqlite3_opentemp_count; extern int sqlite3_opentemp_count;
extern int sqlite3_memUsed; extern int sqlite3_memUsed;
extern int sqlite3_memMax; extern int sqlite3_memMax;
extern char sqlite3_query_plan[];
extern int sqlite3_like_count; extern int sqlite3_like_count;
#if OS_WIN
extern int sqlite3_os_type;
#endif
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
extern int sqlite3_vdbe_addop_trace; extern int sqlite3_vdbe_addop_trace;
#endif #endif
#ifdef SQLITE_TEST
extern char sqlite3_query_plan[];
static char *query_plan = sqlite3_query_plan; static char *query_plan = sqlite3_query_plan;
#endif
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
@ -3139,11 +3213,19 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_current_time, TCL_LINK_INT); (char*)&sqlite3_current_time, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_os_trace", Tcl_LinkVar(interp, "sqlite_os_trace",
(char*)&sqlite3_os_trace, TCL_LINK_INT); (char*)&sqlite3_os_trace, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_where_trace", #if OS_WIN
(char*)&sqlite3_where_trace, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_os_type",
(char*)&sqlite3_os_type, TCL_LINK_INT);
#endif
#ifdef SQLITE_TEST
Tcl_LinkVar(interp, "sqlite_query_plan",
(char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
#endif
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
Tcl_LinkVar(interp, "sqlite_addop_trace", Tcl_LinkVar(interp, "sqlite_addop_trace",
(char*)&sqlite3_vdbe_addop_trace, TCL_LINK_INT); (char*)&sqlite3_vdbe_addop_trace, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_where_trace",
(char*)&sqlite3_where_trace, TCL_LINK_INT);
#endif #endif
#ifdef SQLITE_MEMDEBUG #ifdef SQLITE_MEMDEBUG
Tcl_LinkVar(interp, "sqlite_memused", Tcl_LinkVar(interp, "sqlite_memused",
@ -3151,8 +3233,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
Tcl_LinkVar(interp, "sqlite_memmax", Tcl_LinkVar(interp, "sqlite_memmax",
(char*)&sqlite3_memMax, TCL_LINK_INT | TCL_LINK_READ_ONLY); (char*)&sqlite3_memMax, TCL_LINK_INT | TCL_LINK_READ_ONLY);
#endif #endif
Tcl_LinkVar(interp, "sqlite_query_plan",
(char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
Tcl_LinkVar(interp, "sqlite_opentemp_count", Tcl_LinkVar(interp, "sqlite_opentemp_count",
(char*)&sqlite3_opentemp_count, TCL_LINK_INT); (char*)&sqlite3_opentemp_count, TCL_LINK_INT);

View file

@ -561,6 +561,7 @@ static int fake_big_file(
int Sqlitetest2_Init(Tcl_Interp *interp){ int Sqlitetest2_Init(Tcl_Interp *interp){
extern int sqlite3_io_error_pending; extern int sqlite3_io_error_pending;
extern int sqlite3_diskfull_pending; extern int sqlite3_diskfull_pending;
extern int sqlite3_diskfull;
static struct { static struct {
char *zName; char *zName;
Tcl_CmdProc *xProc; Tcl_CmdProc *xProc;
@ -593,6 +594,10 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
(char*)&sqlite3_io_error_pending, TCL_LINK_INT); (char*)&sqlite3_io_error_pending, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_diskfull_pending", Tcl_LinkVar(interp, "sqlite_diskfull_pending",
(char*)&sqlite3_diskfull_pending, TCL_LINK_INT); (char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_diskfull",
(char*)&sqlite3_diskfull, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_pending_byte",
(char*)&sqlite3_pending_byte, TCL_LINK_INT);
Tcl_LinkVar(interp, "pager_pagesize", Tcl_LinkVar(interp, "pager_pagesize",
(char*)&test_pagesize, TCL_LINK_INT); (char*)&test_pagesize, TCL_LINK_INT);
return TCL_OK; return TCL_OK;

View file

@ -11,6 +11,7 @@
* *
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "vdbe.h"
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
/* /*

View file

@ -259,13 +259,13 @@ void sqlite3Update(
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb); sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
/* If we are trying to update a view, construct that view into /* If we are trying to update a view, realize that view into
** a temporary table. ** a ephemeral table.
*/ */
if( isView ){ if( isView ){
Select *pView; Select *pView;
pView = sqlite3SelectDup(pTab->pSelect); pView = sqlite3SelectDup(pTab->pSelect);
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0); sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView); sqlite3SelectDelete(pView);
} }
@ -469,7 +469,7 @@ void sqlite3Update(
** all record selected by the WHERE clause have been updated. ** all record selected by the WHERE clause have been updated.
*/ */
sqlite3VdbeAddOp(v, OP_Goto, 0, addr); sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeJumpHere(v, addr);
/* Close all tables if there were no FOR EACH ROW triggers */ /* Close all tables if there were no FOR EACH ROW triggers */
if( !triggers_exist ){ if( !triggers_exist ){

View file

@ -366,6 +366,19 @@ char *sqlite3StrNDup(const char *z, int n){
} }
#endif /* !defined(SQLITE_MEMDEBUG) */ #endif /* !defined(SQLITE_MEMDEBUG) */
/*
** Reallocate a buffer to a different size. This is similar to
** sqliteRealloc() except that if the allocation fails the buffer
** is freed.
*/
void sqlite3ReallocOrFree(void **ppBuf, int newSize){
void *pNew = sqliteRealloc(*ppBuf, newSize);
if( pNew==0 ){
sqliteFree(*ppBuf);
}
*ppBuf = pNew;
}
/* /*
** Create a string from the 2nd and subsequent arguments (up to the ** Create a string from the 2nd and subsequent arguments (up to the
** first NULL argument), store the string in memory obtained from ** first NULL argument), store the string in memory obtained from

View file

@ -160,38 +160,6 @@ static void _storeTypeInfo(Mem *pMem){
} }
} }
/*
** Insert a new aggregate element and make it the element that
** has focus.
**
** Return 0 on success and 1 if memory is exhausted.
*/
static int AggInsert(Agg *p, char *zKey, int nKey){
AggElem *pElem;
int i;
int rc;
pElem = sqliteMalloc( sizeof(AggElem) + nKey +
(p->nMem-1)*sizeof(pElem->aMem[0]) );
if( pElem==0 ) return SQLITE_NOMEM;
pElem->zKey = (char*)&pElem->aMem[p->nMem];
memcpy(pElem->zKey, zKey, nKey);
pElem->nKey = nKey;
if( p->pCsr ){
rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*));
if( rc!=SQLITE_OK ){
sqliteFree(pElem);
return rc;
}
}
for(i=0; i<p->nMem; i++){
pElem->aMem[i].flags = MEM_Null;
}
p->pCurrent = pElem;
return 0;
}
/* /*
** Pop the stack N times. ** Pop the stack N times.
*/ */
@ -205,39 +173,6 @@ static void popStack(Mem **ppTos, int N){
*ppTos = pTos; *ppTos = pTos;
} }
/*
** The parameters are pointers to the head of two sorted lists
** of Sorter structures. Merge these two lists together and return
** a single sorted list. This routine forms the core of the merge-sort
** algorithm.
**
** In the case of a tie, left sorts in front of right.
*/
static Sorter *Merge(Sorter *pLeft, Sorter *pRight, KeyInfo *pKeyInfo){
Sorter sHead;
Sorter *pTail;
pTail = &sHead;
pTail->pNext = 0;
while( pLeft && pRight ){
int c = sqlite3VdbeRecordCompare(pKeyInfo, pLeft->nKey, pLeft->zKey,
pRight->nKey, pRight->zKey);
if( c<=0 ){
pTail->pNext = pLeft;
pLeft = pLeft->pNext;
}else{
pTail->pNext = pRight;
pRight = pRight->pNext;
}
pTail = pTail->pNext;
}
if( pLeft ){
pTail->pNext = pLeft;
}else if( pRight ){
pTail->pNext = pRight;
}
return sHead.pNext;
}
/* /*
** Allocate cursor number iCur. Return a pointer to it. Return NULL ** Allocate cursor number iCur. Return a pointer to it. Return NULL
** if we run out of memory. ** if we run out of memory.
@ -635,7 +570,7 @@ case OP_Return: { /* no-push */
/* Opcode: Halt P1 P2 P3 /* Opcode: Halt P1 P2 P3
** **
** Exit immediately. All open cursors, Lists, Sorts, etc are closed ** Exit immediately. All open cursors, Fifos, etc are closed
** automatically. ** automatically.
** **
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(), ** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
@ -773,6 +708,7 @@ case OP_String: {
case OP_Null: { case OP_Null: {
pTos++; pTos++;
pTos->flags = MEM_Null; pTos->flags = MEM_Null;
pTos->n = 0;
break; break;
} }
@ -1164,26 +1100,25 @@ case OP_CollSeq: { /* no-push */
/* Opcode: Function P1 P2 P3 /* Opcode: Function P1 P2 P3
** **
** Invoke a user function (P3 is a pointer to a Function structure that ** Invoke a user function (P3 is a pointer to a Function structure that
** defines the function) with P1 arguments taken from the stack. Pop all ** defines the function) with P2 arguments taken from the stack. Pop all
** arguments from the stack and push back the result. ** arguments from the stack and push back the result.
** **
** P2 is a 32-bit bitmask indicating whether or not each argument to the ** P1 is a 32-bit bitmask indicating whether or not each argument to the
** function was determined to be constant at compile time. If the first ** function was determined to be constant at compile time. If the first
** argument was constant then bit 0 of P2 is set. This is used to determine ** argument was constant then bit 0 of P1 is set. This is used to determine
** whether meta data associated with a user function argument using the ** whether meta data associated with a user function argument using the
** sqlite3_set_auxdata() API may be safely retained until the next ** sqlite3_set_auxdata() API may be safely retained until the next
** invocation of this opcode. ** invocation of this opcode.
** **
** See also: AggFunc ** See also: AggStep and AggFinal
*/ */
case OP_Function: { case OP_Function: {
int i; int i;
Mem *pArg; Mem *pArg;
sqlite3_context ctx; sqlite3_context ctx;
sqlite3_value **apVal; sqlite3_value **apVal;
int n = pOp->p1; int n = pOp->p2;
n = pOp->p1;
apVal = p->apArg; apVal = p->apArg;
assert( apVal || n==0 ); assert( apVal || n==0 );
@ -1222,7 +1157,7 @@ case OP_Function: {
** immediately call the destructor for any non-static values. ** immediately call the destructor for any non-static values.
*/ */
if( ctx.pVdbeFunc ){ if( ctx.pVdbeFunc ){
sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p2); sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1);
pOp->p3 = (char *)ctx.pVdbeFunc; pOp->p3 = (char *)ctx.pVdbeFunc;
pOp->p3type = P3_VDBEFUNC; pOp->p3type = P3_VDBEFUNC;
} }
@ -1476,9 +1411,16 @@ case OP_ToBlob: { /* no-push */
** jump to instruction P2. Otherwise, continue to the next instruction. ** jump to instruction P2. Otherwise, continue to the next instruction.
** **
** If the 0x100 bit of P1 is true and either operand is NULL then take the ** If the 0x100 bit of P1 is true and either operand is NULL then take the
** jump. If the 0x100 bit of P1 is false then fall thru if either operand ** jump. If the 0x100 bit of P1 is clear then fall thru if either operand
** is NULL. ** is NULL.
** **
** If the 0x200 bit of P1 is set and either operand is NULL then
** both operands are converted to integers prior to comparison.
** NULL operands are converted to zero and non-NULL operands are
** converted to 1. Thus, for example, with 0x200 set, NULL==NULL is true
** whereas it would normally be NULL. Similarly, NULL==123 is false when
** 0x200 is set but is NULL when the 0x200 bit of P1 is clear.
**
** The least significant byte of P1 (mask 0xff) must be an affinity character - ** The least significant byte of P1 (mask 0xff) must be an affinity character -
** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values ** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
** according to the affinity before the comparison is made. If the byte is ** according to the affinity before the comparison is made. If the byte is
@ -1546,15 +1488,37 @@ case OP_Ge: { /* same as TK_GE, no-push */
** the stack. ** the stack.
*/ */
if( flags&MEM_Null ){ if( flags&MEM_Null ){
if( (pOp->p1 & 0x200)!=0 ){
/* The 0x200 bit of P1 means, roughly "do not treat NULL as the
** magic SQL value it normally is - treat it as if it were another
** integer".
**
** With 0x200 set, if either operand is NULL then both operands
** are converted to integers prior to being passed down into the
** normal comparison logic below. NULL operands are converted to
** zero and non-NULL operands are converted to 1. Thus, for example,
** with 0x200 set, NULL==NULL is true whereas it would normally
** be NULL. Similarly, NULL!=123 is true.
*/
sqlite3VdbeMemSetInt64(pTos, (pTos->flags & MEM_Null)==0);
sqlite3VdbeMemSetInt64(pNos, (pNos->flags & MEM_Null)==0);
}else{
/* If the 0x200 bit of P1 is clear and either operand is NULL then
** the result is always NULL. The jump is taken if the 0x100 bit
** of P1 is set.
*/
popStack(&pTos, 2); popStack(&pTos, 2);
if( pOp->p2 ){ if( pOp->p2 ){
if( pOp->p1 & 0x100 ) pc = pOp->p2-1; if( pOp->p1 & 0x100 ){
pc = pOp->p2-1;
}
}else{ }else{
pTos++; pTos++;
pTos->flags = MEM_Null; pTos->flags = MEM_Null;
} }
break; break;
} }
}
affinity = pOp->p1 & 0xFF; affinity = pOp->p1 & 0xFF;
if( affinity ){ if( affinity ){
@ -1710,6 +1674,13 @@ case OP_BitNot: { /* same as TK_BITNOT, no-push */
** Do nothing. This instruction is often useful as a jump ** Do nothing. This instruction is often useful as a jump
** destination. ** destination.
*/ */
/*
** The magic Explain opcode are only inserted when explain==2 (which
** is to say when the EXPLAIN QUERY PLAN syntax is used.)
** This opcode records information from the optimizer. It is the
** the same as a no-op. This opcodesnever appears in a real VM program.
*/
case OP_Explain:
case OP_Noop: { /* no-push */ case OP_Noop: { /* no-push */
break; break;
} }
@ -2020,7 +1991,7 @@ case OP_Column: {
** we are dealing with a malformed record. ** we are dealing with a malformed record.
*/ */
if( idx!=szHdr || offset!=payloadSize ){ if( idx!=szHdr || offset!=payloadSize ){
rc = SQLITE_CORRUPT; rc = SQLITE_CORRUPT_BKPT;
goto op_column_out; goto op_column_out;
} }
@ -2574,7 +2545,7 @@ case OP_OpenWrite: { /* no-push */
** only mean that we are dealing with a corrupt database file ** only mean that we are dealing with a corrupt database file
*/ */
if( (flags & 0xf0)!=0 || ((flags & 0x07)!=5 && (flags & 0x07)!=2) ){ if( (flags & 0xf0)!=0 || ((flags & 0x07)!=5 && (flags & 0x07)!=2) ){
rc = SQLITE_CORRUPT; rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error; goto abort_due_to_error;
} }
pCur->isTable = (flags & BTREE_INTKEY)!=0; pCur->isTable = (flags & BTREE_INTKEY)!=0;
@ -2585,7 +2556,7 @@ case OP_OpenWrite: { /* no-push */
*/ */
if( (pCur->isTable && pOp->p3type==P3_KEYINFO) if( (pCur->isTable && pOp->p3type==P3_KEYINFO)
|| (pCur->isIndex && pOp->p3type!=P3_KEYINFO) ){ || (pCur->isIndex && pOp->p3type!=P3_KEYINFO) ){
rc = SQLITE_CORRUPT; rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error; goto abort_due_to_error;
} }
break; break;
@ -2603,13 +2574,14 @@ case OP_OpenWrite: { /* no-push */
break; break;
} }
/* Opcode: OpenVirtual P1 * P3 /* Opcode: OpenVirtual P1 P2 P3
** **
** Open a new cursor to a transient or virtual table. ** Open a new cursor P1 to a transient or virtual table.
** The cursor is always opened read/write even if ** The cursor is always opened read/write even if
** the main database is read-only. The transient or virtual ** the main database is read-only. The transient or virtual
** table is deleted automatically when the cursor is closed. ** table is deleted automatically when the cursor is closed.
** **
** P2 is the number of columns in the virtual table.
** The cursor points to a BTree table if P3==0 and to a BTree index ** The cursor points to a BTree table if P3==0 and to a BTree index
** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure ** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index. ** that defines the format of keys in the index.
@ -2650,6 +2622,7 @@ case OP_OpenVirtual: { /* no-push */
pCx->pIncrKey = &pCx->bogusIncrKey; pCx->pIncrKey = &pCx->bogusIncrKey;
} }
} }
pCx->nField = pOp->p2;
pCx->isIndex = !pCx->isTable; pCx->isIndex = !pCx->isTable;
break; break;
} }
@ -3035,6 +3008,24 @@ case OP_NotExists: { /* no-push */
break; break;
} }
/* Opcode: Sequence P1 * *
**
** Push an integer onto the stack which is the next available
** sequence number for cursor P1. The sequence number on the
** cursor is incremented after the push.
*/
case OP_Sequence: {
int i = pOp->p1;
assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
pTos++;
pTos->i = p->apCsr[i]->seqCount++;
pTos->flags = MEM_Int;
break;
}
/* Opcode: NewRowid P1 P2 * /* Opcode: NewRowid P1 P2 *
** **
** Get a new integer record number (a.k.a "rowid") used as the key to a table. ** Get a new integer record number (a.k.a "rowid") used as the key to a table.
@ -3094,7 +3085,7 @@ case OP_NewRowid: {
cnt = 0; cnt = 0;
if( (sqlite3BtreeFlags(pC->pCursor)&(BTREE_INTKEY|BTREE_ZERODATA)) != if( (sqlite3BtreeFlags(pC->pCursor)&(BTREE_INTKEY|BTREE_ZERODATA)) !=
BTREE_INTKEY ){ BTREE_INTKEY ){
rc = SQLITE_CORRUPT; rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error; goto abort_due_to_error;
} }
assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_INTKEY)!=0 ); assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_INTKEY)!=0 );
@ -3464,6 +3455,24 @@ case OP_Last: { /* no-push */
break; break;
} }
/* Opcode: Sort P1 P2 *
**
** This opcode does exactly the same thing as OP_Rewind except that
** it increments an undocumented global variable used for testing.
**
** Sorting is accomplished by writing records into a sorting index,
** then rewinding that index and playing it back from beginning to
** end. We use the OP_Sort opcode instead of OP_Rewind to do the
** rewinding so that the global variable will be incremented and
** regression tests can determine whether or not the optimizer is
** correctly optimizing out sorts.
*/
case OP_Sort: { /* no-push */
sqlite3_sort_count++;
sqlite3_search_count--;
/* Fall through into OP_Rewind */
}
/* Opcode: Rewind P1 P2 * /* Opcode: Rewind P1 P2 *
** **
** The next use of the Rowid or Column or Next instruction for P1 ** The next use of the Rowid or Column or Next instruction for P1
@ -3685,13 +3694,12 @@ case OP_IdxLT: /* no-push */
case OP_IdxGT: /* no-push */ case OP_IdxGT: /* no-push */
case OP_IdxGE: { /* no-push */ case OP_IdxGE: { /* no-push */
int i= pOp->p1; int i= pOp->p1;
BtCursor *pCrsr;
Cursor *pC; Cursor *pC;
assert( i>=0 && i<p->nCursor ); assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 ); assert( p->apCsr[i]!=0 );
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ if( (pC = p->apCsr[i])->pCursor!=0 ){
int res, rc; int res, rc;
assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */ assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */
@ -4023,31 +4031,6 @@ case OP_FifoRead: {
break; break;
} }
#ifndef SQLITE_OMIT_SUBQUERY
/* Opcode: AggContextPush * * *
**
** Save the state of the current aggregator. It is restored an
** AggContextPop opcode.
**
*/
case OP_AggContextPush: { /* no-push */
p->pAgg++;
assert( p->pAgg<&p->apAgg[p->nAgg] );
break;
}
/* Opcode: AggContextPop * * *
**
** Restore the aggregator to the state it was in when AggContextPush
** was last called. Any data in the current aggregator is deleted.
*/
case OP_AggContextPop: { /* no-push */
p->pAgg--;
assert( p->pAgg>=p->apAgg );
break;
}
#endif
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
/* Opcode: ContextPush * * * /* Opcode: ContextPush * * *
** **
@ -4063,7 +4046,7 @@ case OP_ContextPush: { /* no-push */
/* FIX ME: This should be allocated as part of the vdbe at compile-time */ /* FIX ME: This should be allocated as part of the vdbe at compile-time */
if( i>=p->contextStackDepth ){ if( i>=p->contextStackDepth ){
p->contextStackDepth = i+1; p->contextStackDepth = i+1;
p->contextStack = sqliteRealloc(p->contextStack, sizeof(Context)*(i+1)); sqlite3ReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
if( p->contextStack==0 ) goto no_mem; if( p->contextStack==0 ) goto no_mem;
} }
pContext = &p->contextStack[i]; pContext = &p->contextStack[i];
@ -4091,108 +4074,6 @@ case OP_ContextPop: { /* no-push */
} }
#endif /* #ifndef SQLITE_OMIT_TRIGGER */ #endif /* #ifndef SQLITE_OMIT_TRIGGER */
/* Opcode: SortInsert * * *
**
** The TOS is the key and the NOS is the data. Pop both from the stack
** and put them on the sorter. The key and data should have been
** made using the MakeRecord opcode.
*/
case OP_SortInsert: { /* no-push */
Mem *pNos = &pTos[-1];
Sorter *pSorter;
assert( pNos>=p->aStack );
if( Dynamicify(pTos, db->enc) ) goto no_mem;
pSorter = sqliteMallocRaw( sizeof(Sorter) );
if( pSorter==0 ) goto no_mem;
pSorter->pNext = 0;
if( p->pSortTail ){
p->pSortTail->pNext = pSorter;
}else{
p->pSort = pSorter;
}
p->pSortTail = pSorter;
assert( pTos->flags & MEM_Dyn );
pSorter->nKey = pTos->n;
pSorter->zKey = pTos->z;
pSorter->data.flags = MEM_Null;
rc = sqlite3VdbeMemMove(&pSorter->data, pNos);
pTos -= 2;
break;
}
/* Opcode: Sort * * P3
**
** Sort all elements on the sorter. The algorithm is a
** mergesort. The P3 argument is a pointer to a KeyInfo structure
** that describes the keys to be sorted.
*/
case OP_Sort: { /* no-push */
int i;
KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
Sorter *pElem;
Sorter *apSorter[NSORT];
sqlite3_sort_count++;
pKeyInfo->enc = p->db->enc;
for(i=0; i<NSORT; i++){
apSorter[i] = 0;
}
while( p->pSort ){
pElem = p->pSort;
p->pSort = pElem->pNext;
pElem->pNext = 0;
for(i=0; i<NSORT-1; i++){
if( apSorter[i]==0 ){
apSorter[i] = pElem;
break;
}else{
pElem = Merge(apSorter[i], pElem, pKeyInfo);
apSorter[i] = 0;
}
}
if( i>=NSORT-1 ){
apSorter[NSORT-1] = Merge(apSorter[NSORT-1],pElem, pKeyInfo);
}
}
pElem = 0;
for(i=0; i<NSORT; i++){
pElem = Merge(apSorter[i], pElem, pKeyInfo);
}
p->pSort = pElem;
break;
}
/* Opcode: SortNext * P2 *
**
** Push the data for the topmost element in the sorter onto the
** stack, then remove the element from the sorter. If the sorter
** is empty, push nothing on the stack and instead jump immediately
** to instruction P2.
*/
case OP_SortNext: {
Sorter *pSorter = p->pSort;
CHECK_FOR_INTERRUPT;
if( pSorter!=0 ){
p->pSort = pSorter->pNext;
pTos++;
pTos->flags = MEM_Null;
rc = sqlite3VdbeMemMove(pTos, &pSorter->data);
sqliteFree(pSorter->zKey);
sqliteFree(pSorter);
}else{
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: SortReset * * *
**
** Remove any elements that remain on the sorter.
*/
case OP_SortReset: { /* no-push */
sqlite3VdbeSorterReset(p);
break;
}
/* Opcode: MemStore P1 P2 * /* Opcode: MemStore P1 P2 *
** **
** Write the top of the stack into memory location P1. ** Write the top of the stack into memory location P1.
@ -4296,64 +4177,49 @@ case OP_IfMemPos: { /* no-push */
break; break;
} }
/* Opcode: AggReset P1 P2 P3 /* Opcode: MemNull P1 * *
** **
** Reset the current aggregator context so that it no longer contains any ** Store a NULL in memory cell P1
** data. Future aggregator elements will contain P2 values each and be sorted
** using the KeyInfo structure pointed to by P3.
**
** If P1 is non-zero, then only a single aggregator row is available (i.e.
** there is no GROUP BY expression). In this case it is illegal to invoke
** OP_AggFocus.
*/ */
case OP_AggReset: { /* no-push */ case OP_MemNull: {
assert( !pOp->p3 || pOp->p3type==P3_KEYINFO ); assert( pOp->p1>=0 && pOp->p1<p->nMem );
if( pOp->p1 ){ sqlite3VdbeMemSetNull(&p->aMem[pOp->p1]);
rc = sqlite3VdbeAggReset(0, p->pAgg, (KeyInfo *)pOp->p3);
p->pAgg->nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
rc = AggInsert(p->pAgg, 0, 0);
}else{
rc = sqlite3VdbeAggReset(db, p->pAgg, (KeyInfo *)pOp->p3);
p->pAgg->nMem = pOp->p2;
}
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
p->pAgg->apFunc = sqliteMalloc( p->pAgg->nMem*sizeof(p->pAgg->apFunc[0]) );
if( p->pAgg->apFunc==0 ) goto no_mem;
break; break;
} }
/* Opcode: AggInit P1 P2 P3 /* Opcode: MemInt P1 P2 *
** **
** Initialize the function parameters for an aggregate function. ** Store the integer value P1 in memory cell P2.
** The aggregate will operate out of aggregate column P2.
** P3 is a pointer to the FuncDef structure for the function.
**
** The P1 argument is not used by this opcode. However if the SSE
** extension is compiled in, P1 is set to the number of arguments that
** will be passed to the aggregate function, if any. This is used
** by SSE to select the correct function when (de)serializing statements.
*/ */
case OP_AggInit: { /* no-push */ case OP_MemInt: {
int i = pOp->p2; assert( pOp->p2>=0 && pOp->p2<p->nMem );
assert( i>=0 && i<p->pAgg->nMem ); sqlite3VdbeMemSetInt64(&p->aMem[pOp->p2], pOp->p1);
p->pAgg->apFunc[i] = (FuncDef*)pOp->p3;
break; break;
} }
/* Opcode: AggFunc * P2 P3 /* Opcode: MemMove P1 P2 *
**
** Move the content of memory cell P2 over to memory cell P1.
** Any prior content of P1 is erased. Memory cell P2 is left
** containing a NULL.
*/
case OP_MemMove: {
assert( pOp->p1>=0 && pOp->p1<p->nMem );
assert( pOp->p2>=0 && pOp->p2<p->nMem );
rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], &p->aMem[pOp->p2]);
break;
}
/* Opcode: AggStep P1 P2 P3
** **
** Execute the step function for an aggregate. The ** Execute the step function for an aggregate. The
** function has P2 arguments. P3 is a pointer to the FuncDef ** function has P2 arguments. P3 is a pointer to the FuncDef
** structure that specifies the function. ** structure that specifies the function. Use memory location
** P1 as the accumulator.
** **
** The top of the stack must be an integer which is the index of ** The P2 arguments are popped from the stack.
** the aggregate column that corresponds to this aggregate function.
** Ideally, this index would be another parameter, but there are
** no free parameters left. The integer is popped from the stack.
*/ */
case OP_AggFunc: { /* no-push */ case OP_AggStep: { /* no-push */
int n = pOp->p2; int n = pOp->p2;
int i; int i;
Mem *pMem, *pRec; Mem *pMem, *pRec;
@ -4361,24 +4227,18 @@ case OP_AggFunc: { /* no-push */
sqlite3_value **apVal; sqlite3_value **apVal;
assert( n>=0 ); assert( n>=0 );
assert( pTos->flags==MEM_Int ); pRec = &pTos[1-n];
pRec = &pTos[-n];
assert( pRec>=p->aStack ); assert( pRec>=p->aStack );
apVal = p->apArg; apVal = p->apArg;
assert( apVal || n==0 ); assert( apVal || n==0 );
for(i=0; i<n; i++, pRec++){ for(i=0; i<n; i++, pRec++){
apVal[i] = pRec; apVal[i] = pRec;
storeTypeInfo(pRec, db->enc); storeTypeInfo(pRec, db->enc);
} }
i = pTos->i;
assert( i>=0 && i<p->pAgg->nMem );
ctx.pFunc = (FuncDef*)pOp->p3; ctx.pFunc = (FuncDef*)pOp->p3;
pMem = &p->pAgg->pCurrent->aMem[i]; assert( pOp->p1>=0 && pOp->p1<p->nMem );
ctx.s.z = pMem->zShort; /* Space used for small aggregate contexts */ ctx.pMem = pMem = &p->aMem[pOp->p1];
ctx.pAgg = pMem->z; pMem->n++;
ctx.cnt = ++pMem->i;
ctx.isError = 0; ctx.isError = 0;
ctx.pColl = 0; ctx.pColl = 0;
if( ctx.pFunc->needCollSeq ){ if( ctx.pFunc->needCollSeq ){
@ -4388,182 +4248,34 @@ case OP_AggFunc: { /* no-push */
ctx.pColl = (CollSeq *)pOp[-1].p3; ctx.pColl = (CollSeq *)pOp[-1].p3;
} }
(ctx.pFunc->xStep)(&ctx, n, apVal); (ctx.pFunc->xStep)(&ctx, n, apVal);
pMem->z = ctx.pAgg; popStack(&pTos, n);
pMem->flags = MEM_AggCtx;
popStack(&pTos, n+1);
if( ctx.isError ){ if( ctx.isError ){
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }
break; break;
} }
/* Opcode: AggFocus * P2 * /* Opcode: AggFinal P1 P2 P3
** **
** Pop the top of the stack and use that as an aggregator key. If ** Execute the finalizer function for an aggregate. P1 is
** an aggregator with that same key already exists, then make the ** the memory location that is the accumulator for the aggregate.
** aggregator the current aggregator and jump to P2. If no aggregator
** with the given key exists, create one and make it current but
** do not jump.
** **
** The order of aggregator opcodes is important. The order is: ** P2 is the number of arguments that the step function takes and
** AggReset AggFocus AggNext. In other words, you must execute ** P3 is a pointer to the FuncDef for this function. The P2
** AggReset first, then zero or more AggFocus operations, then ** argument is not used by this opcode. It is only there to disambiguate
** zero or more AggNext operations. You must not execute an AggFocus ** functions that can take varying numbers of arguments. The
** in between an AggNext and an AggReset. ** P3 argument is only needed for the degenerate case where
** the step function was not previously called.
*/ */
case OP_AggFocus: { /* no-push */ case OP_AggFinal: { /* no-push */
char *zKey; Mem *pMem;
int nKey; assert( pOp->p1>=0 && pOp->p1<p->nMem );
int res; pMem = &p->aMem[pOp->p1];
assert( pTos>=p->aStack ); assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
Stringify(pTos, db->enc); sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
zKey = pTos->z;
nKey = pTos->n;
assert( p->pAgg->pBtree );
assert( p->pAgg->pCsr );
rc = sqlite3BtreeMoveto(p->pAgg->pCsr, zKey, nKey, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( res==0 ){
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
(char *)&p->pAgg->pCurrent);
pc = pOp->p2 - 1;
}else{
rc = AggInsert(p->pAgg, zKey, nKey);
}
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
Release(pTos);
pTos--;
break; break;
} }
/* Opcode: AggSet * P2 *
**
** Move the top of the stack into the P2-th field of the current
** aggregate. String values are duplicated into new memory.
*/
case OP_AggSet: { /* no-push */
AggElem *pFocus;
int i = pOp->p2;
pFocus = p->pAgg->pCurrent;
assert( pTos>=p->aStack );
if( pFocus==0 ) goto no_mem;
assert( i>=0 && i<p->pAgg->nMem );
rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos);
pTos--;
break;
}
/* Opcode: AggGet P1 P2 *
**
** Push a new entry onto the stack which is a copy of the P2-th field
** of the current aggregate. Strings are not duplicated so
** string values will be ephemeral.
**
** If P1 is zero, then the value is pulled out of the current aggregate
** in the current aggregate context. If P1 is greater than zero, then
** the value is taken from the P1th outer aggregate context. (i.e. if
** P1==1 then read from the aggregate context that will be restored
** by the next OP_AggContextPop opcode).
*/
case OP_AggGet: {
AggElem *pFocus;
int i = pOp->p2;
Agg *pAgg = &p->pAgg[-pOp->p1];
assert( pAgg>=p->apAgg );
pFocus = pAgg->pCurrent;
if( pFocus==0 ){
int res;
if( sqlite3_malloc_failed ) goto no_mem;
rc = sqlite3BtreeFirst(pAgg->pCsr, &res);
if( rc!=SQLITE_OK ){
return rc;
}
if( res!=0 ){
rc = AggInsert(pAgg, "", 1);
pFocus = pAgg->pCurrent;
}else{
rc = sqlite3BtreeData(pAgg->pCsr, 0, 4, (char *)&pFocus);
}
}
assert( i>=0 && i<pAgg->nMem );
pTos++;
sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
if( pTos->flags&MEM_Str ){
sqlite3VdbeChangeEncoding(pTos, db->enc);
}
break;
}
/* Opcode: AggNext * P2 *
**
** Make the next aggregate value the current aggregate. The prior
** aggregate is deleted. If all aggregate values have been consumed,
** jump to P2.
**
** The order of aggregator opcodes is important. The order is:
** AggReset AggFocus AggNext. In other words, you must execute
** AggReset first, then zero or more AggFocus operations, then
** zero or more AggNext operations. You must not execute an AggFocus
** in between an AggNext and an AggReset.
*/
case OP_AggNext: { /* no-push */
int res;
assert( rc==SQLITE_OK );
CHECK_FOR_INTERRUPT;
if( p->pAgg->searching==0 ){
p->pAgg->searching = 1;
if( p->pAgg->pCsr ){
rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
}else{
res = 0;
}
}else{
if( p->pAgg->pCsr ){
rc = sqlite3BtreeNext(p->pAgg->pCsr, &res);
}else{
res = 1;
}
}
if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( res!=0 ){
pc = pOp->p2 - 1;
}else{
int i;
sqlite3_context ctx;
Mem *aMem;
if( p->pAgg->pCsr ){
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
(char *)&p->pAgg->pCurrent);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
aMem = p->pAgg->pCurrent->aMem;
for(i=0; i<p->pAgg->nMem; i++){
FuncDef *pFunc = p->pAgg->apFunc[i];
Mem *pMem = &aMem[i];
if( pFunc==0 || pFunc->xFinalize==0 ) continue;
ctx.s.flags = MEM_Null;
ctx.s.z = pMem->zShort;
ctx.pAgg = (void*)pMem->z;
ctx.cnt = pMem->i;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx);
pMem->z = ctx.pAgg;
if( pMem->z && pMem->z!=pMem->zShort ){
sqliteFree( pMem->z );
}
*pMem = ctx.s;
if( pMem->flags & MEM_Short ){
pMem->z = pMem->zShort;
}
}
}
break;
}
/* Opcode: Vacuum * * * /* Opcode: Vacuum * * *
** **

View file

@ -104,11 +104,12 @@ int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N); void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*); int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int); void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
int sqlite3VdbeFinalize(Vdbe*); int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int); void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*); int sqlite3VdbeCurrentAddr(Vdbe*);

View file

@ -81,6 +81,7 @@ struct Cursor {
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */ u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
int nField; /* Number of fields in the header */ int nField; /* Number of fields in the header */
i64 seqCount; /* Sequence counter */
/* Cached information about the header for the data record that the /* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheValid is true. ** cursor is currently pointing to. Only valid if cacheValid is true.
@ -113,35 +114,18 @@ typedef struct Cursor Cursor;
** SQLITE_BLOB. ** SQLITE_BLOB.
*/ */
struct Mem { struct Mem {
i64 i; /* Integer value */ i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
double r; /* Real value */
char *z; /* String or BLOB value */
int n; /* Number of characters in string value, including '\0' */ int n; /* Number of characters in string value, including '\0' */
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 type; /* One of MEM_Null, MEM_Str, etc. */ u8 type; /* One of MEM_Null, MEM_Str, etc. */
u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */ u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
double r; /* Real value */
char *z; /* String or BLOB value */
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
char zShort[NBFS]; /* Space for short strings */ char zShort[NBFS]; /* Space for short strings */
}; };
typedef struct Mem Mem; typedef struct Mem Mem;
/*
** A sorter builds a list of elements to be sorted. Each element of
** the list is an instance of the following structure.
*/
typedef struct Sorter Sorter;
struct Sorter {
int nKey; /* Number of bytes in the key */
char *zKey; /* The key by which we will sort */
Mem data;
Sorter *pNext; /* Next in the list */
};
/*
** Number of buckets used for merge-sort.
*/
#define NSORT 30
/* One or more of the following flags are set to indicate the validOK /* One or more of the following flags are set to indicate the validOK
** representations of the value stored in the Mem struct. ** representations of the value stored in the Mem struct.
** **
@ -173,12 +157,7 @@ struct Sorter {
#define MEM_Static 0x0080 /* Mem.z points to a static string */ #define MEM_Static 0x0080 /* Mem.z points to a static string */
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ #define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */ #define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */
/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
** It indicates that the corresponding AggElem.aMem.z points to a
** aggregate function context that needs to be finalized.
*/
#define MEM_AggCtx 0x0400 /* Mem.z points to an agg function context */
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains /* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
@ -210,41 +189,16 @@ typedef struct VdbeFunc VdbeFunc;
** But this file is the only place where the internal details of this ** But this file is the only place where the internal details of this
** structure are known. ** structure are known.
** **
** This structure is defined inside of vdbe.c because it uses substructures ** This structure is defined inside of vdbeInt.h because it uses substructures
** (Mem) which are only defined there. ** (Mem) which are only defined there.
*/ */
struct sqlite3_context { struct sqlite3_context {
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
Mem s; /* The return value is stored here */ Mem s; /* The return value is stored here */
void *pAgg; /* Aggregate context */ Mem *pMem; /* Memory cell used to store aggregate context */
u8 isError; /* Set to true for an error */ u8 isError; /* Set to true for an error */
int cnt; /* Number of times that the step function has been called */ CollSeq *pColl; /* Collating sequence */
CollSeq *pColl;
};
/*
** An Agg structure describes an Aggregator. Each Agg consists of
** zero or more Aggregator elements (AggElem). Each AggElem contains
** a key and one or more values. The values are used in processing
** aggregate functions in a SELECT. The key is used to implement
** the GROUP BY clause of a select.
*/
typedef struct Agg Agg;
typedef struct AggElem AggElem;
struct Agg {
int nMem; /* Number of values stored in each AggElem */
AggElem *pCurrent; /* The AggElem currently in focus */
FuncDef **apFunc; /* Information about aggregate functions */
Btree *pBtree; /* The tmp. btree used to group elements, if required. */
BtCursor *pCsr; /* Read/write cursor to the table in pBtree */
int nTab; /* Root page of the table in pBtree */
u8 searching; /* True between the first AggNext and AggReset */
};
struct AggElem {
char *zKey; /* The key to this AggElem */
int nKey; /* Number of bytes in the key, including '\0' at end */
Mem aMem[1]; /* The values for this AggElem */
}; };
/* /*
@ -324,8 +278,6 @@ struct Vdbe {
Mem *aColName; /* Column names to return */ Mem *aColName; /* Column names to return */
int nCursor; /* Number of slots in apCsr[] */ int nCursor; /* Number of slots in apCsr[] */
Cursor **apCsr; /* One element of this array for each open cursor */ Cursor **apCsr; /* One element of this array for each open cursor */
Sorter *pSort; /* A linked list of objects to be sorted */
Sorter *pSortTail; /* Last element on the pSort list */
int nVar; /* Number of entries in aVar[] */ int nVar; /* Number of entries in aVar[] */
Mem *aVar; /* Values for the OP_Variable opcode. */ Mem *aVar; /* Values for the OP_Variable opcode. */
char **azVar; /* Name of variables */ char **azVar; /* Name of variables */
@ -333,9 +285,6 @@ struct Vdbe {
int magic; /* Magic number for sanity checking */ int magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */ int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */ Mem *aMem; /* The memory locations */
int nAgg; /* Number of elements in apAgg */
Agg *apAgg; /* Array of aggregate contexts */
Agg *pAgg; /* Current aggregate context */
int nCallback; /* Number of callbacks invoked so far */ int nCallback; /* Number of callbacks invoked so far */
Fifo sFifo; /* A list of ROWIDs */ Fifo sFifo; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */ int contextStackTop; /* Index of top element in the context stack */
@ -358,6 +307,7 @@ struct Vdbe {
u8 aborted; /* True if ROLLBACK in another VM causes an abort */ u8 aborted; /* True if ROLLBACK in another VM causes an abort */
u8 expired; /* True if the VM needs to be recompiled */ u8 expired; /* True if the VM needs to be recompiled */
int nChange; /* Number of db changes made since last reset */ int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
}; };
/* /*
@ -372,8 +322,6 @@ struct Vdbe {
** Function prototypes ** Function prototypes
*/ */
void sqlite3VdbeFreeCursor(Cursor*); void sqlite3VdbeFreeCursor(Cursor*);
void sqlite3VdbeSorterReset(Vdbe*);
int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
void sqliteVdbePopStack(Vdbe*,int); void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*); int sqlite3VdbeCursorMoveto(Cursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@ -415,6 +363,7 @@ double sqlite3VdbeRealValue(Mem*);
int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p); void sqlite3VdbeMemRelease(Mem *p);
void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef NDEBUG #ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*, u8); void sqlite3VdbeMemSanity(Mem*, u8);
int sqlite3VdbeOpcodeNoPush(u8); int sqlite3VdbeOpcodeNoPush(u8);

View file

@ -15,6 +15,7 @@
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "vdbeInt.h" #include "vdbeInt.h"
#include "os.h"
/* /*
** Return TRUE (non-zero) of the statement supplied as an argument needs ** Return TRUE (non-zero) of the statement supplied as an argument needs
@ -173,9 +174,10 @@ int sqlite3_step(sqlite3_stmt *pStmt){
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
if( p->pc<0 ){ if( p->pc<0 ){
#ifndef SQLITE_OMIT_TRACE
/* Invoke the trace callback if there is one /* Invoke the trace callback if there is one
*/ */
if( (db = p->db)->xTrace && !db->init.busy ){ if( db->xTrace && !db->init.busy ){
assert( p->nOp>0 ); assert( p->nOp>0 );
assert( p->aOp[p->nOp-1].opcode==OP_Noop ); assert( p->aOp[p->nOp-1].opcode==OP_Noop );
assert( p->aOp[p->nOp-1].p3!=0 ); assert( p->aOp[p->nOp-1].p3!=0 );
@ -187,6 +189,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
} }
if( db->xProfile && !db->init.busy ){
double rNow;
sqlite3OsCurrentTime(&rNow);
p->startTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0;
}
#endif
/* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned /* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned
** on in debugging mode. ** on in debugging mode.
@ -213,6 +221,23 @@ int sqlite3_step(sqlite3_stmt *pStmt){
rc = SQLITE_MISUSE; rc = SQLITE_MISUSE;
} }
#ifndef SQLITE_OMIT_TRACE
/* Invoke the profile callback if there is one
*/
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy ){
double rNow;
u64 elapseTime;
sqlite3OsCurrentTime(&rNow);
elapseTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0 - p->startTime;
assert( p->nOp>0 );
assert( p->aOp[p->nOp-1].opcode==OP_Noop );
assert( p->aOp[p->nOp-1].p3!=0 );
assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC );
db->xProfile(db->pProfileArg, p->aOp[p->nOp-1].p3, elapseTime);
}
#endif
sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
return rc; return rc;
} }
@ -232,16 +257,25 @@ void *sqlite3_user_data(sqlite3_context *p){
** same context that was returned on prior calls. ** same context that was returned on prior calls.
*/ */
void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
Mem *pMem = p->pMem;
assert( p && p->pFunc && p->pFunc->xStep ); assert( p && p->pFunc && p->pFunc->xStep );
if( p->pAgg==0 ){ if( (pMem->flags & MEM_Agg)==0 ){
if( nByte<=NBFS ){ if( nByte==0 ){
p->pAgg = (void*)p->s.z; assert( pMem->flags==MEM_Null );
memset(p->pAgg, 0, nByte); pMem->z = 0;
}else{ }else{
p->pAgg = sqliteMalloc( nByte ); pMem->flags = MEM_Agg;
pMem->xDel = sqlite3FreeX;
*(FuncDef**)&pMem->i = p->pFunc;
if( nByte<=NBFS ){
pMem->z = pMem->zShort;
memset(pMem->z, 0, nByte);
}else{
pMem->z = sqliteMalloc( nByte );
} }
} }
return p->pAgg; }
return (void*)pMem->z;
} }
/* /*
@ -274,8 +308,9 @@ void sqlite3_set_auxdata(
pVdbeFunc = pCtx->pVdbeFunc; pVdbeFunc = pCtx->pVdbeFunc;
if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){ if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg; int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
pCtx->pVdbeFunc = pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc); pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc);
if( !pVdbeFunc ) return; if( !pVdbeFunc ) return;
pCtx->pVdbeFunc = pVdbeFunc;
memset(&pVdbeFunc->apAux[pVdbeFunc->nAux], 0, memset(&pVdbeFunc->apAux[pVdbeFunc->nAux], 0,
sizeof(struct AuxData)*(iArg+1-pVdbeFunc->nAux)); sizeof(struct AuxData)*(iArg+1-pVdbeFunc->nAux));
pVdbeFunc->nAux = iArg+1; pVdbeFunc->nAux = iArg+1;
@ -300,7 +335,7 @@ void sqlite3_set_auxdata(
*/ */
int sqlite3_aggregate_count(sqlite3_context *p){ int sqlite3_aggregate_count(sqlite3_context *p){
assert( p && p->pFunc && p->pFunc->xStep ); assert( p && p->pFunc && p->pFunc->xStep );
return p->cnt; return p->pMem->n;
} }
/* /*

View file

@ -62,16 +62,18 @@ void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
** elements. ** elements.
*/ */
static void resizeOpArray(Vdbe *p, int N){ static void resizeOpArray(Vdbe *p, int N){
if( p->magic==VDBE_MAGIC_RUN ){ int runMode = p->magic==VDBE_MAGIC_RUN;
assert( N==p->nOp ); if( runMode || p->nOpAlloc<N ){
p->nOpAlloc = N; VdbeOp *pNew;
p->aOp = sqliteRealloc(p->aOp, N*sizeof(Op)); int nNew = N + 100*(!runMode);
}else if( p->nOpAlloc<N ){
int oldSize = p->nOpAlloc; int oldSize = p->nOpAlloc;
p->nOpAlloc = N+100; pNew = sqliteRealloc(p->aOp, nNew*sizeof(Op));
p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); if( pNew ){
if( p->aOp ){ p->nOpAlloc = nNew;
memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); p->aOp = pNew;
if( nNew>oldSize ){
memset(&p->aOp[oldSize], 0, (nNew-oldSize)*sizeof(Op));
}
} }
} }
} }
@ -100,7 +102,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
p->nOp++; p->nOp++;
assert( p->magic==VDBE_MAGIC_INIT ); assert( p->magic==VDBE_MAGIC_INIT );
resizeOpArray(p, i+1); resizeOpArray(p, i+1);
if( p->aOp==0 ){ if( sqlite3_malloc_failed ){
return 0; return 0;
} }
pOp = &p->aOp[i]; pOp = &p->aOp[i];
@ -145,7 +147,8 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
assert( p->magic==VDBE_MAGIC_INIT ); assert( p->magic==VDBE_MAGIC_INIT );
if( i>=p->nLabelAlloc ){ if( i>=p->nLabelAlloc ){
p->nLabelAlloc = p->nLabelAlloc*2 + 10; p->nLabelAlloc = p->nLabelAlloc*2 + 10;
p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); sqlite3ReallocOrFree((void**)&p->aLabel,
p->nLabelAlloc*sizeof(p->aLabel[0]));
} }
if( p->aLabel ){ if( p->aLabel ){
p->aLabel[i] = -1; p->aLabel[i] = -1;
@ -215,8 +218,8 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
** **
** This routine is called once after all opcodes have been inserted. ** This routine is called once after all opcodes have been inserted.
** **
** Variable *pMaxFuncArgs is set to the maximum value of any P1 argument ** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
** to an OP_Function or P2 to an OP_AggFunc opcode. This is used by ** to an OP_Function or OP_AggStep opcode. This is used by
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
** **
** The integer *pMaxStack is set to the maximum number of vdbe stack ** The integer *pMaxStack is set to the maximum number of vdbe stack
@ -239,12 +242,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
u8 opcode = pOp->opcode; u8 opcode = pOp->opcode;
/* Todo: Maybe OP_AggFunc should change to use P1 in the same if( opcode==OP_Function || opcode==OP_AggStep ){
* way as OP_Function.
*/
if( opcode==OP_Function ){
if( pOp->p1>nMaxArgs ) nMaxArgs = pOp->p1;
}else if( opcode==OP_AggFunc ){
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
}else if( opcode==OP_Halt ){ }else if( opcode==OP_Halt ){
if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
@ -302,7 +300,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
int addr; int addr;
assert( p->magic==VDBE_MAGIC_INIT ); assert( p->magic==VDBE_MAGIC_INIT );
resizeOpArray(p, p->nOp + nOp); resizeOpArray(p, p->nOp + nOp);
if( p->aOp==0 ){ if( sqlite3_malloc_failed ){
return 0; return 0;
} }
addr = p->nOp; addr = p->nOp;
@ -353,6 +351,41 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
} }
} }
/*
** Change teh P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
void sqlite3VdbeJumpHere(Vdbe *p, int addr){
sqlite3VdbeChangeP2(p, addr, p->nOp);
}
/*
** Delete a P3 value if necessary.
*/
static void freeP3(int p3type, void *p3){
if( p3 ){
switch( p3type ){
case P3_DYNAMIC:
case P3_KEYINFO:
case P3_KEYINFO_HANDOFF: {
sqliteFree(p3);
break;
}
case P3_VDBEFUNC: {
VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
sqliteFree(pVdbeFunc);
break;
}
case P3_MEM: {
sqlite3ValueFree((sqlite3_value*)p3);
break;
}
}
}
}
/* /*
** Change the value of the P3 operand for a specific instruction. ** Change the value of the P3 operand for a specific instruction.
** This routine is useful when a large program is loaded from a ** This routine is useful when a large program is loaded from a
@ -382,12 +415,7 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
Op *pOp; Op *pOp;
assert( p->magic==VDBE_MAGIC_INIT ); assert( p->magic==VDBE_MAGIC_INIT );
if( p==0 || p->aOp==0 ){ if( p==0 || p->aOp==0 ){
if( n==P3_DYNAMIC || n==P3_KEYINFO_HANDOFF ){ freeP3(n, (void*)*(char**)&zP3);
sqliteFree((void*)zP3);
}
if( n==P3_MEM ){
sqlite3ValueFree((sqlite3_value *)zP3);
}
return; return;
} }
if( addr<0 || addr>=p->nOp ){ if( addr<0 || addr>=p->nOp ){
@ -395,16 +423,19 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
if( addr<0 ) return; if( addr<0 ) return;
} }
pOp = &p->aOp[addr]; pOp = &p->aOp[addr];
if( pOp->p3 && pOp->p3type==P3_DYNAMIC ){ freeP3(pOp->p3type, pOp->p3);
sqliteFree(pOp->p3);
pOp->p3 = 0; pOp->p3 = 0;
}
if( zP3==0 ){ if( zP3==0 ){
pOp->p3 = 0; pOp->p3 = 0;
pOp->p3type = P3_NOTUSED; pOp->p3type = P3_NOTUSED;
}else if( n==P3_KEYINFO ){ }else if( n==P3_KEYINFO ){
KeyInfo *pKeyInfo; KeyInfo *pKeyInfo;
int nField, nByte; int nField, nByte;
/* KeyInfo structures that include an KeyInfo.aSortOrder are always
** sent in using P3_KEYINFO_HANDOFF. The KeyInfo.aSortOrder array
** is not duplicated when P3_KEYINFO is used. */
/* assert( pKeyInfo->aSortOrder==0 ); */
nField = ((KeyInfo*)zP3)->nField; nField = ((KeyInfo*)zP3)->nField;
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]); nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]);
pKeyInfo = sqliteMallocRaw( nByte ); pKeyInfo = sqliteMallocRaw( nByte );
@ -577,8 +608,9 @@ int sqlite3VdbeList(
} }
p->resOnStack = 0; p->resOnStack = 0;
do{
i = p->pc++; i = p->pc++;
}while( i<p->nOp && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
if( i>=p->nOp ){ if( i>=p->nOp ){
p->rc = SQLITE_OK; p->rc = SQLITE_OK;
rc = SQLITE_DONE; rc = SQLITE_DONE;
@ -617,7 +649,7 @@ int sqlite3VdbeList(
pMem->type = SQLITE_TEXT; pMem->type = SQLITE_TEXT;
pMem->enc = SQLITE_UTF8; pMem->enc = SQLITE_UTF8;
p->nResColumn = 5; p->nResColumn = 5 - 2*(p->explain-1);
p->pTos = pMem; p->pTos = pMem;
p->rc = SQLITE_OK; p->rc = SQLITE_OK;
p->resOnStack = 1; p->resOnStack = 1;
@ -658,7 +690,6 @@ void sqlite3VdbeMakeReady(
int nVar, /* Number of '?' see in the SQL statement */ int nVar, /* Number of '?' see in the SQL statement */
int nMem, /* Number of memory cells to allocate */ int nMem, /* Number of memory cells to allocate */
int nCursor, /* Number of cursors to allocate */ int nCursor, /* Number of cursors to allocate */
int nAgg, /* Number of aggregate contexts required */
int isExplain /* True if the EXPLAIN keywords is present */ int isExplain /* True if the EXPLAIN keywords is present */
){ ){
int n; int n;
@ -701,7 +732,6 @@ void sqlite3VdbeMakeReady(
+ nVar*sizeof(char*) /* azVar */ + nVar*sizeof(char*) /* azVar */
+ nMem*sizeof(Mem) /* aMem */ + nMem*sizeof(Mem) /* aMem */
+ nCursor*sizeof(Cursor*) /* apCsr */ + nCursor*sizeof(Cursor*) /* apCsr */
+ nAgg*sizeof(Agg) /* Aggregate contexts */
); );
if( !sqlite3_malloc_failed ){ if( !sqlite3_malloc_failed ){
p->aMem = &p->aStack[nStack]; p->aMem = &p->aStack[nStack];
@ -712,17 +742,12 @@ void sqlite3VdbeMakeReady(
p->apArg = (Mem**)&p->aVar[nVar]; p->apArg = (Mem**)&p->aVar[nVar];
p->azVar = (char**)&p->apArg[nArg]; p->azVar = (char**)&p->apArg[nArg];
p->apCsr = (Cursor**)&p->azVar[nVar]; p->apCsr = (Cursor**)&p->azVar[nVar];
if( nAgg>0 ){
p->nAgg = nAgg;
p->apAgg = (Agg*)&p->apCsr[nCursor];
}
p->nCursor = nCursor; p->nCursor = nCursor;
for(n=0; n<nVar; n++){ for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null; p->aVar[n].flags = MEM_Null;
} }
} }
} }
p->pAgg = p->apAgg;
for(n=0; n<p->nMem; n++){ for(n=0; n<p->nMem; n++){
p->aMem[n].flags = MEM_Null; p->aMem[n].flags = MEM_Null;
} }
@ -763,155 +788,6 @@ void sqlite3VdbeMakeReady(
#endif #endif
} }
/*
** Remove any elements that remain on the sorter for the VDBE given.
*/
void sqlite3VdbeSorterReset(Vdbe *p){
while( p->pSort ){
Sorter *pSorter = p->pSort;
p->pSort = pSorter->pNext;
sqliteFree(pSorter->zKey);
sqlite3VdbeMemRelease(&pSorter->data);
sqliteFree(pSorter);
}
p->pSortTail = 0;
}
/*
** Free all resources allociated with AggElem pElem, an element of
** aggregate pAgg.
*/
static void freeAggElem(AggElem *pElem, Agg *pAgg){
int i;
for(i=0; i<pAgg->nMem; i++){
Mem *pMem = &pElem->aMem[i];
if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
sqlite3_context ctx;
ctx.pFunc = pAgg->apFunc[i];
ctx.s.flags = MEM_Null;
ctx.pAgg = pMem->z;
ctx.cnt = pMem->i;
ctx.isError = 0;
(*ctx.pFunc->xFinalize)(&ctx);
pMem->z = ctx.pAgg;
if( pMem->z!=0 && pMem->z!=pMem->zShort ){
sqliteFree(pMem->z);
}
sqlite3VdbeMemRelease(&ctx.s);
}else{
sqlite3VdbeMemRelease(pMem);
}
}
sqliteFree(pElem);
}
/*
** Reset an Agg structure. Delete all its contents.
**
** For installable aggregate functions, if the step function has been
** called, make sure the finalizer function has also been called. The
** finalizer might need to free memory that was allocated as part of its
** private context. If the finalizer has not been called yet, call it
** now.
**
** If db is NULL, then this is being called from sqliteVdbeReset(). In
** this case clean up all references to the temp-table used for
** aggregates (if it was ever opened).
**
** If db is not NULL, then this is being called from with an OP_AggReset
** opcode. Open the temp-table, if it has not already been opened and
** delete the contents of the table used for aggregate information, ready
** for the next round of aggregate processing.
*/
int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
int rc = 0;
BtCursor *pCsr;
if( !pAgg ) return SQLITE_OK;
pCsr = pAgg->pCsr;
assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0)
|| sqlite3_malloc_failed );
/* If pCsr is not NULL, then the table used for aggregate information
** is open. Loop through it and free the AggElem* structure pointed at
** by each entry. If the finalizer has not been called for an AggElem,
** do that too. Finally, clear the btree table itself.
*/
if( pCsr ){
int res;
assert( pAgg->pBtree );
assert( pAgg->nTab>0 );
rc=sqlite3BtreeFirst(pCsr, &res);
while( res==0 && rc==SQLITE_OK ){
AggElem *pElem;
rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
if( rc!=SQLITE_OK ){
return rc;
}
assert( pAgg->apFunc!=0 );
freeAggElem(pElem, pAgg);
rc=sqlite3BtreeNext(pCsr, &res);
}
if( rc!=SQLITE_OK ){
return rc;
}
sqlite3BtreeCloseCursor(pCsr);
sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab);
}else{
/* The cursor may not be open because the aggregator was never used,
** or it could be that it was used but there was no GROUP BY clause.
*/
if( pAgg->pCurrent ){
freeAggElem(pAgg->pCurrent, pAgg);
}
}
/* If db is not NULL and we have not yet and we have not yet opened
** the temporary btree then do so and create the table to store aggregate
** information.
**
** If db is NULL, then close the temporary btree if it is open.
*/
if( db ){
if( !pAgg->pBtree ){
assert( pAgg->nTab==0 );
#ifndef SQLITE_OMIT_MEMORYDB
rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree);
#else
rc = sqlite3BtreeFactory(db, 0, 0, TEMP_PAGES, &pAgg->pBtree);
#endif
if( rc!=SQLITE_OK ) return rc;
sqlite3BtreeBeginTrans(pAgg->pBtree, 1);
rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0);
if( rc!=SQLITE_OK ) return rc;
}
assert( pAgg->nTab!=0 );
rc = sqlite3BtreeCursor(pAgg->pBtree, pAgg->nTab, 1,
sqlite3VdbeRecordCompare, pKeyInfo, &pAgg->pCsr);
if( rc!=SQLITE_OK ) return rc;
}else{
if( pAgg->pBtree ){
sqlite3BtreeClose(pAgg->pBtree);
pAgg->pBtree = 0;
pAgg->nTab = 0;
}
pAgg->pCsr = 0;
}
if( pAgg->apFunc ){
sqliteFree(pAgg->apFunc);
pAgg->apFunc = 0;
}
pAgg->pCurrent = 0;
pAgg->nMem = 0;
pAgg->searching = 0;
return SQLITE_OK;
}
/* /*
** Close a cursor and release all the resources that cursor happens ** Close a cursor and release all the resources that cursor happens
** to hold. ** to hold.
@ -965,10 +841,6 @@ static void Cleanup(Vdbe *p){
} }
sqliteFree(p->contextStack); sqliteFree(p->contextStack);
} }
sqlite3VdbeSorterReset(p);
for(i=0; i<p->nAgg; i++){
sqlite3VdbeAggReset(0, &p->apAgg[i], 0);
}
p->contextStack = 0; p->contextStack = 0;
p->contextStackDepth = 0; p->contextStackDepth = 0;
p->contextStackTop = 0; p->contextStackTop = 0;
@ -1145,7 +1017,8 @@ static int vdbeCommit(sqlite3 *db){
*/ */
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt); zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
rc = sqlite3OsOpenDirectory(zMainFile, &master); rc = sqlite3OsOpenDirectory(zMainFile, &master);
if( rc!=SQLITE_OK || (needSync && (rc=sqlite3OsSync(&master))!=SQLITE_OK) ){ if( rc!=SQLITE_OK ||
(needSync && (rc=sqlite3OsSync(&master,0))!=SQLITE_OK) ){
sqlite3OsClose(&master); sqlite3OsClose(&master);
sqlite3OsDelete(zMaster); sqlite3OsDelete(zMaster);
sqliteFree(zMaster); sqliteFree(zMaster);
@ -1489,17 +1362,7 @@ void sqlite3VdbeDelete(Vdbe *p){
if( p->aOp ){ if( p->aOp ){
for(i=0; i<p->nOp; i++){ for(i=0; i<p->nOp; i++){
Op *pOp = &p->aOp[i]; Op *pOp = &p->aOp[i];
if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){ freeP3(pOp->p3type, pOp->p3);
sqliteFree(pOp->p3);
}
if( pOp->p3type==P3_VDBEFUNC ){
VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
sqliteFree(pVdbeFunc);
}
if( pOp->p3type==P3_MEM ){
sqlite3ValueFree((sqlite3_value*)pOp->p3);
}
} }
sqliteFree(p->aOp); sqliteFree(p->aOp);
} }
@ -1714,8 +1577,18 @@ int sqlite3VdbeSerialGet(
} }
case 6: /* 8-byte signed integer */ case 6: /* 8-byte signed integer */
case 7: { /* IEEE floating point */ case 7: { /* IEEE floating point */
u64 x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; u64 x;
u32 y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7]; u32 y;
#ifndef NDEBUG
/* Verify that integers and floating point values use the same
** byte order. The byte order differs on some (broken) architectures.
*/
static const u64 t1 = ((u64)0x3ff00000)<<32;
assert( 1.0==*(double*)&t1 );
#endif
x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
x = (x<<32) | y; x = (x<<32) | y;
if( serial_type==6 ){ if( serial_type==6 ){
pMem->i = *(i64*)&x; pMem->i = *(i64*)&x;
@ -1853,7 +1726,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
sqlite3BtreeKeySize(pCur, &nCellKey); sqlite3BtreeKeySize(pCur, &nCellKey);
if( nCellKey<=0 ){ if( nCellKey<=0 ){
return SQLITE_CORRUPT; return SQLITE_CORRUPT_BKPT;
} }
rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m); rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m);
if( rc ){ if( rc ){

View file

@ -187,15 +187,45 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
return rc; return rc;
} }
/*
** Memory cell pMem contains the context of an aggregate function.
** This routine calls the finalize method for that function. The
** result of the aggregate is stored back into pMem.
*/
void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
if( pFunc && pFunc->xFinalize ){
sqlite3_context ctx;
assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
ctx.s.flags = MEM_Null;
ctx.s.z = pMem->zShort;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx);
if( pMem->z && pMem->z!=pMem->zShort ){
sqliteFree( pMem->z );
}
*pMem = ctx.s;
if( pMem->flags & MEM_Short ){
pMem->z = pMem->zShort;
}
}
}
/* /*
** Release any memory held by the Mem. This may leave the Mem in an ** Release any memory held by the Mem. This may leave the Mem in an
** inconsistent state, for example with (Mem.z==0) and ** inconsistent state, for example with (Mem.z==0) and
** (Mem.type==SQLITE_TEXT). ** (Mem.type==SQLITE_TEXT).
*/ */
void sqlite3VdbeMemRelease(Mem *p){ void sqlite3VdbeMemRelease(Mem *p){
if( p->flags & MEM_Dyn ){ if( p->flags & (MEM_Dyn|MEM_Agg) ){
if( p->xDel ){ if( p->xDel ){
if( p->flags & MEM_Agg ){
sqlite3VdbeMemFinalize(p, *(FuncDef**)&p->i);
assert( (p->flags & MEM_Agg)==0 );
sqlite3VdbeMemRelease(p);
}else{
p->xDel((void *)p->z); p->xDel((void *)p->z);
}
}else{ }else{
sqliteFree(p->z); sqliteFree(p->z);
} }
@ -287,6 +317,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
sqlite3VdbeMemRelease(pMem); sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Null; pMem->flags = MEM_Null;
pMem->type = SQLITE_NULL; pMem->type = SQLITE_NULL;
pMem->n = 0;
} }
/* /*
@ -699,7 +730,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
/* /*
** Create a new sqlite3_value object. ** Create a new sqlite3_value object.
*/ */
sqlite3_value* sqlite3ValueNew(){ sqlite3_value* sqlite3ValueNew(void){
Mem *p = sqliteMalloc(sizeof(*p)); Mem *p = sqliteMalloc(sizeof(*p));
if( p ){ if( p ){
p->flags = MEM_Null; p->flags = MEM_Null;

View file

@ -232,7 +232,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
/* /*
** This routine identifies subexpressions in the WHERE clause where ** This routine identifies subexpressions in the WHERE clause where
** each subexpression is separate by the AND operator or some other ** each subexpression is separated by the AND operator or some other
** operator specified in the op parameter. The WhereClause structure ** operator specified in the op parameter. The WhereClause structure
** is filled with pointers to subexpressions. For example: ** is filled with pointers to subexpressions. For example:
** **
@ -281,7 +281,7 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
** **
** There is one cursor per table in the FROM clause. The number of ** There is one cursor per table in the FROM clause. The number of
** tables in the FROM clause is limited by a test early in the ** tables in the FROM clause is limited by a test early in the
** sqlite3WhereBegin() routien. So we know that the pMaskSet->ix[] ** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[]
** array will never overflow. ** array will never overflow.
*/ */
static void createMask(ExprMaskSet *pMaskSet, int iCursor){ static void createMask(ExprMaskSet *pMaskSet, int iCursor){
@ -304,6 +304,7 @@ static void createMask(ExprMaskSet *pMaskSet, int iCursor){
** the bitmasks together. ** the bitmasks together.
*/ */
static Bitmask exprListTableUsage(ExprMaskSet*, ExprList*); static Bitmask exprListTableUsage(ExprMaskSet*, ExprList*);
static Bitmask exprSelectTableUsage(ExprMaskSet*, Select*);
static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){ static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
Bitmask mask = 0; Bitmask mask = 0;
if( p==0 ) return 0; if( p==0 ) return 0;
@ -314,14 +315,7 @@ static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
mask = exprTableUsage(pMaskSet, p->pRight); mask = exprTableUsage(pMaskSet, p->pRight);
mask |= exprTableUsage(pMaskSet, p->pLeft); mask |= exprTableUsage(pMaskSet, p->pLeft);
mask |= exprListTableUsage(pMaskSet, p->pList); mask |= exprListTableUsage(pMaskSet, p->pList);
if( p->pSelect ){ mask |= exprSelectTableUsage(pMaskSet, p->pSelect);
Select *pS = p->pSelect;
mask |= exprListTableUsage(pMaskSet, pS->pEList);
mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
mask |= exprTableUsage(pMaskSet, pS->pWhere);
mask |= exprTableUsage(pMaskSet, pS->pHaving);
}
return mask; return mask;
} }
static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){ static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
@ -334,6 +328,19 @@ static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
} }
return mask; return mask;
} }
static Bitmask exprSelectTableUsage(ExprMaskSet *pMaskSet, Select *pS){
Bitmask mask;
if( pS==0 ){
mask = 0;
}else{
mask = exprListTableUsage(pMaskSet, pS->pEList);
mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
mask |= exprTableUsage(pMaskSet, pS->pWhere);
mask |= exprTableUsage(pMaskSet, pS->pHaving);
}
return mask;
}
/* /*
** Return TRUE if the given operator is one of the operators that is ** Return TRUE if the given operator is one of the operators that is
@ -479,8 +486,11 @@ static int isLikeOrGlob(
Expr *pRight, *pLeft; Expr *pRight, *pLeft;
ExprList *pList; ExprList *pList;
int c, cnt; int c, cnt;
int noCase;
char wc[3]; char wc[3];
if( !sqlite3IsLikeFunction(db, pExpr, wc) ){ CollSeq *pColl;
if( !sqlite3IsLikeFunction(db, pExpr, &noCase, wc) ){
return 0; return 0;
} }
pList = pExpr->pList; pList = pExpr->pList;
@ -492,6 +502,14 @@ static int isLikeOrGlob(
if( pLeft->op!=TK_COLUMN ){ if( pLeft->op!=TK_COLUMN ){
return 0; return 0;
} }
pColl = pLeft->pColl;
if( pColl==0 ){
pColl = db->pDfltColl;
}
if( (pColl->type!=SQLITE_COLL_BINARY || noCase) &&
(pColl->type!=SQLITE_COLL_NOCASE || !noCase) ){
return 0;
}
sqlite3DequoteExpr(pRight); sqlite3DequoteExpr(pRight);
z = pRight->token.z; z = pRight->token.z;
for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){} for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
@ -514,7 +532,7 @@ static int isLikeOrGlob(
** to the standard form of "X <op> <expr>". If the expression is of ** to the standard form of "X <op> <expr>". If the expression is of
** the form "X <op> Y" where both X and Y are columns, then the original ** the form "X <op> Y" where both X and Y are columns, then the original
** expression is unchanged and a new virtual expression of the form ** expression is unchanged and a new virtual expression of the form
** "Y <op> X" is added to the WHERE clause. ** "Y <op> X" is added to the WHERE clause and analyzed separately.
*/ */
static void exprAnalyze( static void exprAnalyze(
SrcList *pSrc, /* the FROM clause */ SrcList *pSrc, /* the FROM clause */
@ -526,18 +544,26 @@ static void exprAnalyze(
Expr *pExpr = pTerm->pExpr; Expr *pExpr = pTerm->pExpr;
Bitmask prereqLeft; Bitmask prereqLeft;
Bitmask prereqAll; Bitmask prereqAll;
int idxRight;
int nPattern; int nPattern;
int isComplete; int isComplete;
if( sqlite3_malloc_failed ) return; if( sqlite3_malloc_failed ) return;
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
if( pExpr->op==TK_IN ){
assert( pExpr->pRight==0 );
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
}else{
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight); pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
pTerm->prereqAll = prereqAll = exprTableUsage(pMaskSet, pExpr); }
prereqAll = exprTableUsage(pMaskSet, pExpr);
if( ExprHasProperty(pExpr, EP_FromJoin) ){
prereqAll |= getMask(pMaskSet, pExpr->iRightJoinTable);
}
pTerm->prereqAll = prereqAll;
pTerm->leftCursor = -1; pTerm->leftCursor = -1;
pTerm->iParent = -1; pTerm->iParent = -1;
pTerm->operator = 0; pTerm->operator = 0;
idxRight = -1;
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){ if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
Expr *pLeft = pExpr->pLeft; Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight; Expr *pRight = pExpr->pRight;
@ -599,7 +625,13 @@ static void exprAnalyze(
#ifndef SQLITE_OMIT_OR_OPTIMIZATION #ifndef SQLITE_OMIT_OR_OPTIMIZATION
/* Attempt to convert OR-connected terms into an IN operator so that /* Attempt to convert OR-connected terms into an IN operator so that
** they can make use of indices. ** they can make use of indices. Example:
**
** x = expr1 OR expr2 = x OR x = expr3
**
** is converted into
**
** x IN (expr1,expr2,expr3)
*/ */
else if( pExpr->op==TK_OR ){ else if( pExpr->op==TK_OR ){
int ok; int ok;
@ -647,7 +679,11 @@ static void exprAnalyze(
pDup->iColumn = iColumn; pDup->iColumn = iColumn;
} }
pNew = sqlite3Expr(TK_IN, pDup, 0, 0); pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
if( pNew ) pNew->pList = pList; if( pNew ){
pNew->pList = pList;
}else{
sqlite3ExprListDelete(pList);
}
pTerm->pExpr = pNew; pTerm->pExpr = pNew;
pTerm->flags |= TERM_DYNAMIC; pTerm->flags |= TERM_DYNAMIC;
exprAnalyze(pSrc, pMaskSet, pWC, idxTerm); exprAnalyze(pSrc, pMaskSet, pWC, idxTerm);
@ -726,7 +762,7 @@ static int isSortingIndex(
int *pbRev /* Set to 1 if ORDER BY is DESC */ int *pbRev /* Set to 1 if ORDER BY is DESC */
){ ){
int i, j; /* Loop counters */ int i, j; /* Loop counters */
int sortOrder; /* Which direction we are sorting */ int sortOrder = SQLITE_SO_ASC; /* Which direction we are sorting */
int nTerm; /* Number of ORDER BY terms */ int nTerm; /* Number of ORDER BY terms */
struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
@ -802,7 +838,8 @@ static int sortableByRowid(
assert( pOrderBy!=0 ); assert( pOrderBy!=0 );
assert( pOrderBy->nExpr>0 ); assert( pOrderBy->nExpr>0 );
p = pOrderBy->a[0].pExpr; p = pOrderBy->a[0].pExpr;
if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1 ){ if( pOrderBy->nExpr==1 && p->op==TK_COLUMN && p->iTable==base
&& p->iColumn==-1 ){
*pbRev = pOrderBy->a[0].sortOrder; *pbRev = pOrderBy->a[0].sortOrder;
return 1; return 1;
} }
@ -810,7 +847,7 @@ static int sortableByRowid(
} }
/* /*
** Prepare a crude estimate of the logorithm of the input value. ** Prepare a crude estimate of the logarithm of the input value.
** The results need not be exact. This is only used for estimating ** The results need not be exact. This is only used for estimating
** the total cost of performing operatings with O(logN) or O(NlogN) ** the total cost of performing operatings with O(logN) or O(NlogN)
** complexity. Because N is just a guess, it is no great tragedy if ** complexity. Because N is just a guess, it is no great tragedy if
@ -1069,11 +1106,12 @@ static double bestIndex(
** of a LEFT OUTER JOIN. In (1), the term is not disabled. ** of a LEFT OUTER JOIN. In (1), the term is not disabled.
** **
** Disabling a term causes that term to not be tested in the inner loop ** Disabling a term causes that term to not be tested in the inner loop
** of the join. Disabling is an optimization. We would get the correct ** of the join. Disabling is an optimization. When terms are satisfied
** results if nothing were ever disabled, but joins might run a little ** by indices, we disable them to prevent redundant tests in the inner
** slower. The trick is to disable as much as we can without disabling ** loop. We would get the correct results if nothing were ever disabled,
** too much. If we disabled in (1), we'd get the wrong answer. ** but joins might run a little slower. The trick is to disable as much
** See ticket #813. ** as we can without disabling too much. If we disabled in (1), we'd get
** the wrong answer. See ticket #813.
*/ */
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
if( pTerm if( pTerm
@ -1142,8 +1180,9 @@ static void codeEqualityTerm(
sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk); sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z)); VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
pLevel->nIn++; pLevel->nIn++;
pLevel->aInLoop = aIn = sqliteRealloc(pLevel->aInLoop, sqlite3ReallocOrFree((void**)&pLevel->aInLoop,
sizeof(pLevel->aInLoop[0])*3*pLevel->nIn); sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
aIn = pLevel->aInLoop;
if( aIn ){ if( aIn ){
aIn += pLevel->nIn*3 - 3; aIn += pLevel->nIn*3 - 3;
aIn[0] = OP_Next; aIn[0] = OP_Next;
@ -1229,7 +1268,7 @@ static void codeAllEqualityTerms(
} }
} }
#ifdef SQLITE_TEST #if defined(SQLITE_TEST)
/* /*
** The following variable holds a text description of query plan generated ** The following variable holds a text description of query plan generated
** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin ** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin
@ -1387,7 +1426,7 @@ WhereInfo *sqlite3WhereBegin(
/* Analyze all of the subexpressions. Note that exprAnalyze() might /* Analyze all of the subexpressions. Note that exprAnalyze() might
** add new virtual terms onto the end of the WHERE clause. We do not ** add new virtual terms onto the end of the WHERE clause. We do not
** want to analyze these virtual terms, so start analyzing at the end ** want to analyze these virtual terms, so start analyzing at the end
** and work forward so that they added virtual terms are never processed. ** and work forward so that the added virtual terms are never processed.
*/ */
for(i=0; i<pTabList->nSrc; i++){ for(i=0; i<pTabList->nSrc; i++){
createMask(&maskSet, pTabList->a[i].iCursor); createMask(&maskSet, pTabList->a[i].iCursor);
@ -1415,6 +1454,7 @@ WhereInfo *sqlite3WhereBegin(
pTabItem = pTabList->a; pTabItem = pTabList->a;
pLevel = pWInfo->a; pLevel = pWInfo->a;
andFlags = ~0; andFlags = ~0;
TRACE(("*** Optimizer Start ***\n"));
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
Index *pIdx; /* Index for FROM table at pTabItem */ Index *pIdx; /* Index for FROM table at pTabItem */
int flags; /* Flags asssociated with pIdx */ int flags; /* Flags asssociated with pIdx */
@ -1435,7 +1475,7 @@ WhereInfo *sqlite3WhereBegin(
continue; continue;
} }
cost = bestIndex(pParse, &wc, pTabItem, notReady, cost = bestIndex(pParse, &wc, pTabItem, notReady,
(j==0 && ppOrderBy) ? *ppOrderBy : 0, (i==0 && ppOrderBy) ? *ppOrderBy : 0,
&pIdx, &flags, &nEq); &pIdx, &flags, &nEq);
if( cost<lowestCost ){ if( cost<lowestCost ){
lowestCost = cost; lowestCost = cost;
@ -1444,12 +1484,14 @@ WhereInfo *sqlite3WhereBegin(
bestNEq = nEq; bestNEq = nEq;
bestJ = j; bestJ = j;
} }
if( (pTabItem->jointype & JT_LEFT)!=0 if( (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
|| (j>0 && (pTabItem[-1].jointype & JT_LEFT)!=0) || (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0)
){ ){
break; break;
} }
} }
TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
pLevel-pWInfo->a));
if( (bestFlags & WHERE_ORDERBY)!=0 ){ if( (bestFlags & WHERE_ORDERBY)!=0 ){
*ppOrderBy = 0; *ppOrderBy = 0;
} }
@ -1467,6 +1509,7 @@ WhereInfo *sqlite3WhereBegin(
notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor); notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = bestJ; pLevel->iFrom = bestJ;
} }
TRACE(("*** Optimizer Finished ***\n"));
/* If the total query only selects a single row, then the ORDER BY /* If the total query only selects a single row, then the ORDER BY
** clause is irrelevant. ** clause is irrelevant.
@ -1485,6 +1528,20 @@ WhereInfo *sqlite3WhereBegin(
Index *pIx; Index *pIx;
int iIdxCur = pLevel->iIdxCur; int iIdxCur = pLevel->iIdxCur;
#ifndef SQLITE_OMIT_EXPLAIN
if( pParse->explain==2 ){
char *zMsg;
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
zMsg = sqlite3MPrintf("TABLE %s", pItem->zName);
if( pItem->zAlias ){
zMsg = sqlite3MPrintf("%z AS %s", zMsg, pItem->zAlias);
}
if( (pIx = pLevel->pIdx)!=0 ){
zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
}
sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
}
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom]; pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab; pTab = pTabItem->pTab;
if( pTab->isTransient || pTab->pSelect ) continue; if( pTab->isTransient || pTab->pSelect ) continue;
@ -1540,8 +1597,7 @@ WhereInfo *sqlite3WhereBegin(
if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){ if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
if( !pParse->nMem ) pParse->nMem++; if( !pParse->nMem ) pParse->nMem++;
pLevel->iLeftJoin = pParse->nMem++; pLevel->iLeftJoin = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_Null, 0, 0); sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin);
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
VdbeComment((v, "# init LEFT JOIN no-match flag")); VdbeComment((v, "# init LEFT JOIN no-match flag"));
} }
@ -1821,8 +1877,7 @@ WhereInfo *sqlite3WhereBegin(
*/ */
if( pLevel->iLeftJoin ){ if( pLevel->iLeftJoin ){
pLevel->top = sqlite3VdbeCurrentAddr(v); pLevel->top = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp(v, OP_Integer, 1, 0); sqlite3VdbeAddOp(v, OP_MemInt, 1, pLevel->iLeftJoin);
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
VdbeComment((v, "# record LEFT JOIN hit")); VdbeComment((v, "# record LEFT JOIN hit"));
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){ for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
@ -1924,13 +1979,13 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
} }
if( pLevel->iLeftJoin ){ if( pLevel->iLeftJoin ){
int addr; int addr;
addr = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0); addr = sqlite3VdbeAddOp(v, OP_IfMemPos, pLevel->iLeftJoin, 0);
sqlite3VdbeAddOp(v, OP_NotNull, 1, addr+4 + (pLevel->iIdxCur>=0));
sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0); sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
if( pLevel->iIdxCur>=0 ){ if( pLevel->iIdxCur>=0 ){
sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0); sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0);
} }
sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top); sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top);
sqlite3VdbeJumpHere(v, addr);
} }
} }