From 111df261a58e2dec22b1e6375edcced5ca547344 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Wed, 18 Apr 2007 22:53:46 +0000 Subject: [PATCH] Upgraded SQLite 3 to version 3.3.16 --- NEWS | 2 +- ext/pdo_sqlite/sqlite/VERSION | 2 +- ext/pdo_sqlite/sqlite/src/btree.c | 34 +++-- ext/pdo_sqlite/sqlite/src/build.c | 23 ++- ext/pdo_sqlite/sqlite/src/callback.c | 2 +- ext/pdo_sqlite/sqlite/src/delete.c | 2 +- ext/pdo_sqlite/sqlite/src/expr.c | 8 +- ext/pdo_sqlite/sqlite/src/func.c | 2 +- ext/pdo_sqlite/sqlite/src/insert.c | 26 ++-- ext/pdo_sqlite/sqlite/src/main.c | 14 +- ext/pdo_sqlite/sqlite/src/os_common.h | 1 + ext/pdo_sqlite/sqlite/src/os_win.c | 10 +- ext/pdo_sqlite/sqlite/src/pager.c | 195 ++++++++++++++------------ ext/pdo_sqlite/sqlite/src/pager.h | 2 +- ext/pdo_sqlite/sqlite/src/select.c | 53 ++++--- ext/pdo_sqlite/sqlite/src/sqliteInt.h | 16 ++- ext/pdo_sqlite/sqlite/src/test1.c | 64 +++++++++ ext/pdo_sqlite/sqlite/src/tokenize.c | 2 +- ext/pdo_sqlite/sqlite/src/vdbe.c | 20 ++- ext/pdo_sqlite/sqlite/src/vdbeaux.c | 11 +- ext/pdo_sqlite/sqlite/src/vtab.c | 32 ++++- 21 files changed, 337 insertions(+), 184 deletions(-) diff --git a/NEWS b/NEWS index 2e365be4bf..93e4f6cedb 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? Apr 2007, PHP 5.2.2RC2 +- Upgraded SQLite 3 to version 3.3.16 (Ilia) - Fixed bug #41109 (recursiveiterator.inc says "implements" Iterator instead of "extends"). (Marcus) - Fixed bug #41093 (magic_quotes_gpc ignores first arrays keys). (Arpad, Ilia) @@ -45,7 +46,6 @@ PHP NEWS . libpq (PostgreSQL) to version 8.2.3 . libmysql (MySQL) to version 5.0.37 . openssl to version 0.9.8e -- Upgraded SQLite 3 to version 3.3.15 (Ilia) - Upgraded PCRE to version 7.0 (Nuno) - Updated timezone database to version 2007.3. (Derick) - Improved FastCGI SAPI to support external pipe and socket servers on win32. diff --git a/ext/pdo_sqlite/sqlite/VERSION b/ext/pdo_sqlite/sqlite/VERSION index a9c846e62f..272a1ca301 100644 --- a/ext/pdo_sqlite/sqlite/VERSION +++ b/ext/pdo_sqlite/sqlite/VERSION @@ -1 +1 @@ -3.3.15 +3.3.16 diff --git a/ext/pdo_sqlite/sqlite/src/btree.c b/ext/pdo_sqlite/sqlite/src/btree.c index c1d9844f5b..3df2a3b01d 100644 --- a/ext/pdo_sqlite/sqlite/src/btree.c +++ b/ext/pdo_sqlite/sqlite/src/btree.c @@ -1396,13 +1396,20 @@ static void zeroPage(MemPage *pPage, int flags){ /* ** Get a page from the pager. Initialize the MemPage.pBt and ** MemPage.aData elements if needed. +** +** If the noContent flag is set, it means that we do not care about +** the content of the page at this time. So do not go to the disk +** to fetch the content. Just fill in the content with zeros for now. +** If in the future we call sqlite3PagerWrite() on this page, that +** means we have started to be concerned about content and the disk +** read should occur at that point. */ -static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage, int clrFlag){ +static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage, int noContent){ int rc; MemPage *pPage; DbPage *pDbPage; - rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, clrFlag); + rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent); if( rc ) return rc; pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage); pPage->aData = sqlite3PagerGetData(pDbPage); @@ -1411,9 +1418,6 @@ static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage, int clrFlag){ pPage->pgno = pgno; pPage->hdrOffset = pPage->pgno==1 ? 100 : 0; *ppPage = pPage; - if( clrFlag ){ - sqlite3PagerDontRollback(pPage->pDbPage); - } return SQLITE_OK; } @@ -3830,6 +3834,7 @@ static int allocateBtreePage( put4byte(&aData[4], k-1); rc = getPage(pBt, *pPgno, ppPage, 1); if( rc==SQLITE_OK ){ + sqlite3PagerDontRollback((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); @@ -3948,7 +3953,7 @@ static int freePage(MemPage *pPage){ put4byte(&pTrunk->aData[4], k+1); put4byte(&pTrunk->aData[8+k*4], pPage->pgno); #ifndef SQLITE_SECURE_DELETE - sqlite3PagerDontWrite(pBt->pPager, pPage->pgno); + sqlite3PagerDontWrite(pPage->pDbPage); #endif } TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno)); @@ -3982,7 +3987,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){ if( ovflPgno==0 || ovflPgno>sqlite3PagerPagecount(pBt->pPager) ){ return SQLITE_CORRUPT_BKPT; } - rc = getPage(pBt, ovflPgno, &pOvfl, 0); + rc = getPage(pBt, ovflPgno, &pOvfl, nOvfl==0); if( rc ) return rc; if( nOvfl ){ ovflPgno = get4byte(pOvfl->aData); @@ -6561,18 +6566,31 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ rc = sqlite3PagerOverwrite(pBtTo->pPager, i, sqlite3PagerGetData(pDbPage)); sqlite3PagerUnref(pDbPage); } + + /* If the file is shrinking, journal the pages that are being truncated + ** so that they can be rolled back if the commit fails. + */ for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ DbPage *pDbPage; if( i==iSkip ) continue; rc = sqlite3PagerGet(pBtTo->pPager, i, &pDbPage); if( rc ) break; rc = sqlite3PagerWrite(pDbPage); + sqlite3PagerDontWrite(pDbPage); + /* Yeah. It seems wierd to call DontWrite() right after Write(). But + ** that is because the names of those procedures do not exactly + ** represent what they do. Write() really means "put this page in the + ** rollback journal and mark it as dirty so that it will be written + ** to the database file later." DontWrite() undoes the second part of + ** that and prevents the page from being written to the database. The + ** page is still on the rollback journal, though. And that is the whole + ** point of this loop: to put pages on the rollback journal. */ sqlite3PagerUnref(pDbPage); - sqlite3PagerDontWrite(pBtTo->pPager, i); } if( !rc && nPagepPager, nPage); } + if( rc ){ sqlite3BtreeRollback(pTo); } diff --git a/ext/pdo_sqlite/sqlite/src/build.c b/ext/pdo_sqlite/sqlite/src/build.c index 250c968aa9..2dc8c52b42 100644 --- a/ext/pdo_sqlite/sqlite/src/build.c +++ b/ext/pdo_sqlite/sqlite/src/build.c @@ -478,18 +478,11 @@ static void sqliteResetColumnNames(Table *pTable){ ** foreign keys from the sqlite.aFKey hash table. But it does destroy ** memory structures of the indices and foreign keys associated with ** the table. -** -** Indices associated with the table are unlinked from the "db" -** data structure if db!=NULL. If db==NULL, indices attached to -** the table are deleted, but it is assumed they have already been -** unlinked. */ -void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ +void sqlite3DeleteTable(Table *pTable){ Index *pIndex, *pNext; FKey *pFKey, *pNextFKey; - db = 0; - if( pTable==0 ) return; /* Do not delete the table until the reference count reaches zero. */ @@ -509,7 +502,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ #ifndef SQLITE_OMIT_FOREIGN_KEY /* Delete all foreign keys associated with this table. The keys - ** should have already been unlinked from the db->aFKey hash table + ** should have already been unlinked from the pSchema->aFKey hash table */ for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){ pNextFKey = pFKey->pNextFrom; @@ -561,7 +554,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ } } #endif - sqlite3DeleteTable(db, p); + sqlite3DeleteTable(p); } db->flags |= SQLITE_InternChanges; } @@ -810,7 +803,7 @@ void sqlite3StartTable( pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; - if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable); + if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable); pParse->pNewTable = pTable; /* If this is the magic sqlite_sequence table used by autoincrement, @@ -1484,7 +1477,7 @@ void sqlite3EndTable( p->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; - sqlite3DeleteTable(0, pSelTab); + sqlite3DeleteTable(pSelTab); } } @@ -1712,7 +1705,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ pTable->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; - sqlite3DeleteTable(0, pSelTab); + sqlite3DeleteTable(pSelTab); pTable->pSchema->flags |= DB_UnresetViews; }else{ pTable->nCol = 0; @@ -2210,7 +2203,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2); sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, "indexed columns are not unique", P3_STATIC); - assert( addr2==sqlite3VdbeCurrentAddr(v) ); + assert( sqlite3MallocFailed() || addr2==sqlite3VdbeCurrentAddr(v) ); } sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0); sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1); @@ -2959,7 +2952,7 @@ void sqlite3SrcListDelete(SrcList *pList){ sqliteFree(pItem->zDatabase); sqliteFree(pItem->zName); sqliteFree(pItem->zAlias); - sqlite3DeleteTable(0, pItem->pTab); + sqlite3DeleteTable(pItem->pTab); sqlite3SelectDelete(pItem->pSelect); sqlite3ExprDelete(pItem->pOn); sqlite3IdListDelete(pItem->pUsing); diff --git a/ext/pdo_sqlite/sqlite/src/callback.c b/ext/pdo_sqlite/sqlite/src/callback.c index 788b622109..7d2efeb7ab 100644 --- a/ext/pdo_sqlite/sqlite/src/callback.c +++ b/ext/pdo_sqlite/sqlite/src/callback.c @@ -344,7 +344,7 @@ void sqlite3SchemaFree(void *p){ sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0); for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); - sqlite3DeleteTable(0, pTab); + sqlite3DeleteTable(pTab); } sqlite3HashClear(&temp1); pSchema->pSeqTab = 0; diff --git a/ext/pdo_sqlite/sqlite/src/delete.c b/ext/pdo_sqlite/sqlite/src/delete.c index ea9e99b877..64199b02e8 100644 --- a/ext/pdo_sqlite/sqlite/src/delete.c +++ b/ext/pdo_sqlite/sqlite/src/delete.c @@ -27,7 +27,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ struct SrcList_item *pItem; for(i=0, pItem=pSrc->a; inSrc; i++, pItem++){ pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase); - sqlite3DeleteTable(pParse->db, pItem->pTab); + sqlite3DeleteTable(pItem->pTab); pItem->pTab = pTab; if( pTab ){ pTab->nRef++; diff --git a/ext/pdo_sqlite/sqlite/src/expr.c b/ext/pdo_sqlite/sqlite/src/expr.c index 54a9f6abe1..4ba63d54b7 100644 --- a/ext/pdo_sqlite/sqlite/src/expr.c +++ b/ext/pdo_sqlite/sqlite/src/expr.c @@ -1420,7 +1420,9 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int iParm = pExpr->iTable + (((int)affinity)<<16); ExprList *pEList; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); - sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0); + if( sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0) ){ + return; + } pEList = pExpr->pSelect->pEList; if( pEList && pEList->nExpr>0 ){ keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft, @@ -1491,7 +1493,9 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ } sqlite3ExprDelete(pSel->pLimit); pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one); - sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0); + if( sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0) ){ + return; + } break; } } diff --git a/ext/pdo_sqlite/sqlite/src/func.c b/ext/pdo_sqlite/sqlite/src/func.c index 567a4fbff8..5b3d0e0370 100644 --- a/ext/pdo_sqlite/sqlite/src/func.c +++ b/ext/pdo_sqlite/sqlite/src/func.c @@ -655,8 +655,8 @@ static void hexFunc( const unsigned char *pBlob; char *zHex, *z; assert( argc==1 ); - pBlob = sqlite3_value_blob(argv[0]); n = sqlite3_value_bytes(argv[0]); + pBlob = sqlite3_value_blob(argv[0]); z = zHex = sqlite3_malloc(n*2 + 1); if( zHex==0 ) return; for(i=0; ia[keyColumn].pExpr); pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1); - if( pOp->opcode==OP_Null ){ + if( pOp && pOp->opcode==OP_Null ){ appendFlag = 1; pOp->opcode = OP_NewRowid; pOp->p1 = base; @@ -1374,10 +1374,10 @@ static int xferOptimization( int addr1, addr2; /* Loop addresses */ int emptyDestTest; /* Address of test for empty pDest */ int emptySrcTest; /* Address of test for empty pSrc */ - int memRowid = 0; /* A memcell containing a rowid from pSrc */ Vdbe *v; /* The VDBE we are building */ KeyInfo *pKey; /* Key information for an index */ int counterMem; /* Memory register used by AUTOINC */ + int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */ if( pSelect==0 ){ return 0; /* Must be of the form INSERT INTO ... SELECT ... */ @@ -1474,6 +1474,9 @@ static int xferOptimization( } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ + if( pDestIdx->onError!=OE_None ){ + destHasUniqueIdx = 1; + } for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; } @@ -1504,11 +1507,16 @@ static int xferOptimization( iDest = pParse->nTab++; counterMem = autoIncBegin(pParse, iDbDest, pDest); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); - if( pDest->iPKey<0 && pDest->pIndex!=0 ){ + if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ){ /* If tables do not have an INTEGER PRIMARY KEY and there ** are indices to be copied and the destination is not empty, ** we have to disallow the transfer optimization because the ** the rowids might change which will mess up indexing. + ** + ** Or if the destination has a UNIQUE index and is not empty, + ** we also disallow the transfer optimization because we cannot + ** insure that all entries in the union of DEST and SRC will be + ** unique. */ addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iDest, 0); emptyDestTest = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); @@ -1518,11 +1526,6 @@ static int xferOptimization( } sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0); - if( pDest->pIndex!=0 ){ - sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0); - memRowid = pParse->nMem++; - sqlite3VdbeAddOp(v, OP_MemStore, memRowid, pDest->iPKey>=0); - } if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0); sqlite3VdbeAddOp(v, OP_Dup, 0, 0); @@ -1562,13 +1565,6 @@ static int xferOptimization( (char*)pKey, P3_KEYINFO_HANDOFF); addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0); sqlite3VdbeAddOp(v, OP_RowKey, iSrc, 0); - if( pDestIdx->onError!=OE_None ){ - sqlite3VdbeAddOp(v, OP_MemLoad, memRowid, 0); - addr2 = sqlite3VdbeAddOp(v, OP_IsUnique, iDest, 0); - sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, - "UNIQUE constraint failed", P3_STATIC); - sqlite3VdbeJumpHere(v, addr2); - } sqlite3VdbeAddOp(v, OP_IdxInsert, iDest, 1); sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1+1); sqlite3VdbeJumpHere(v, addr1); diff --git a/ext/pdo_sqlite/sqlite/src/main.c b/ext/pdo_sqlite/sqlite/src/main.c index 9f996136f0..daac62f8c3 100644 --- a/ext/pdo_sqlite/sqlite/src/main.c +++ b/ext/pdo_sqlite/sqlite/src/main.c @@ -127,8 +127,18 @@ int sqlite3_close(sqlite3 *db){ } #endif - /* If there are any outstanding VMs, return SQLITE_BUSY. */ sqlite3ResetInternalSchema(db, 0); + + /* If a transaction is open, the ResetInternalSchema() call above + ** will not have called the xDisconnect() method on any virtual + ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback() + ** call will do so. We need to do this before the check for active + ** SQL statements below, as the v-table implementation may be storing + ** some prepared statements internally. + */ + sqlite3VtabRollback(db); + + /* If there are any outstanding VMs, return SQLITE_BUSY. */ if( db->pVdbe ){ sqlite3Error(db, SQLITE_BUSY, "Unable to close due to unfinalised statements"); @@ -149,8 +159,6 @@ int sqlite3_close(sqlite3 *db){ return SQLITE_ERROR; } - sqlite3VtabRollback(db); - for(j=0; jnDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ diff --git a/ext/pdo_sqlite/sqlite/src/os_common.h b/ext/pdo_sqlite/sqlite/src/os_common.h index 6aa244f9c8..ba52314ce8 100644 --- a/ext/pdo_sqlite/sqlite/src/os_common.h +++ b/ext/pdo_sqlite/sqlite/src/os_common.h @@ -97,6 +97,7 @@ int sqlite3_diskfull = 0; || (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \ { local_ioerr(); CODE; } static void local_ioerr(){ + IOTRACE(("IOERR\n")); sqlite3_io_error_hit = 1; } #define SimulateDiskfullError(CODE) \ diff --git a/ext/pdo_sqlite/sqlite/src/os_win.c b/ext/pdo_sqlite/sqlite/src/os_win.c index 9da53e9fee..b15de03340 100644 --- a/ext/pdo_sqlite/sqlite/src/os_win.c +++ b/ext/pdo_sqlite/sqlite/src/os_win.c @@ -408,6 +408,12 @@ static void winceDestroyLock(winFile *pFile){ UnmapViewOfFile(pFile->shared); CloseHandle(pFile->hShared); + if( pFile->zDeleteOnClose ){ + DeleteFileW(pFile->zDeleteOnClose); + sqliteFree(pFile->zDeleteOnClose); + pFile->zDeleteOnClose = 0; + } + /* Done with the mutex */ winceMutexRelease(pFile->hMutex); CloseHandle(pFile->hMutex); @@ -975,10 +981,6 @@ static int winClose(OsFile **pId){ }while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) ); #if OS_WINCE winceDestroyLock(pFile); - if( pFile->zDeleteOnClose ){ - DeleteFileW(pFile->zDeleteOnClose); - sqliteFree(pFile->zDeleteOnClose); - } #endif OpenCounter(-1); sqliteFree(pFile); diff --git a/ext/pdo_sqlite/sqlite/src/pager.c b/ext/pdo_sqlite/sqlite/src/pager.c index a39a431720..6b44448f09 100644 --- a/ext/pdo_sqlite/sqlite/src/pager.c +++ b/ext/pdo_sqlite/sqlite/src/pager.c @@ -162,6 +162,7 @@ struct PgHdr { u8 dirty; /* TRUE if we need to write back changes */ u8 needSync; /* Sync journal before writing this page */ u8 alwaysRollback; /* Disable DontRollback() for this page */ + u8 needRead; /* Read content if PagerWrite() is called */ short int nRef; /* Number of users of this page */ PgHdr *pDirty, *pPrevDirty; /* Dirty pages */ u32 notUsed; /* Buffer space */ @@ -293,19 +294,26 @@ struct Pager { Pager *pNext; /* Linked list of pagers in this thread */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ - u32 iChangeCount; /* Db change-counter for which cache is valid */ + char dbFileVers[16]; /* Changes whenever database file changes */ }; /* -** If SQLITE_TEST is defined then increment the variable given in -** the argument +** The following global variables hold counters used for +** testing purposes only. These variables do not exist in +** a non-testing build. These variables are not thread-safe. */ #ifdef SQLITE_TEST -# define TEST_INCR(x) x++ +int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */ +int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */ +int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */ +int sqlite3_pager_pgfree_count = 0; /* Number of cache pages freed */ +# define PAGER_INCR(v) v++ #else -# define TEST_INCR(x) +# define PAGER_INCR(v) #endif + + /* ** Journal files begin with the following magic string. The data ** was obtained from /dev/random. It is used only as a sanity check. @@ -898,6 +906,8 @@ static void pager_reset(Pager *pPager){ PgHdr *pPg, *pNext; if( pPager->errCode ) return; for(pPg=pPager->pAll; pPg; pPg=pNext){ + IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); + PAGER_INCR(sqlite3_pager_pgfree_count); pNext = pPg->pNextAll; sqliteFree(pPg); } @@ -1121,12 +1131,14 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){ #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif - CODEC1(pPager, pData, pPg->pgno, 3); - - /* If this was page 1, then restore the value of Pager.iChangeCount */ + /* If this was page 1, then restore the value of Pager.dbFileVers. + ** Do this before any decoding. */ if( pgno==1 ){ - pPager->iChangeCount = retrieve32bits(pPg, 24); + memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } + + /* Decode the page just read from disk */ + CODEC1(pPager, pData, pPg->pgno, 3); } return rc; } @@ -1219,51 +1231,6 @@ delmaster_out: return rc; } -#if 0 -/* -** Make every page in the cache agree with what is on disk. In other words, -** reread the disk to reset the state of the cache. -** -** This routine is called after a rollback in which some of the dirty cache -** pages had never been written out to disk. We need to roll back the -** cache content and the easiest way to do that is to reread the old content -** back from the disk. -*/ -static int pager_reload_cache(Pager *pPager){ - PgHdr *pPg; - int rc = SQLITE_OK; - for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ - char *zBuf = pPager->pTmpSpace; /* Temp storage for one page */ - if( !pPg->dirty ) continue; - if( (int)pPg->pgno <= pPager->origDbSize ){ - rc = sqlite3OsSeek(pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1)); - if( rc==SQLITE_OK ){ - rc = sqlite3OsRead(pPager->fd, zBuf, pPager->pageSize); - } - PAGERTRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno); - if( rc ) break; - CODEC1(pPager, zBuf, pPg->pgno, 2); - }else{ - memset(zBuf, 0, pPager->pageSize); - } - if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), pPager->pageSize) ){ - memcpy(PGHDR_TO_DATA(pPg), zBuf, pPager->pageSize); - if( pPager->xReiniter ){ - pPager->xReiniter(pPg, pPager->pageSize); - }else{ - memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra); - } - } - pPg->needSync = 0; - pPg->dirty = 0; -#ifdef SQLITE_CHECK_PAGES - pPg->pageHash = pager_pagehash(pPg); -#endif - } - pPager->pDirty = 0; - return rc; -} -#endif static void pager_truncate_cache(Pager *pPager); @@ -2049,6 +2016,8 @@ static void pager_truncate_cache(Pager *pPager){ ppPg = &pPg->pNextAll; }else{ *ppPg = pPg->pNextAll; + IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); + PAGER_INCR(sqlite3_pager_pgfree_count); unlinkPage(pPg); makeClean(pPg); sqliteFree(pPg); @@ -2470,9 +2439,13 @@ static int pager_write_pagelist(PgHdr *pList){ if( pList->pgno<=pPager->dbSize ){ char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); PAGERTRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno); - IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno)) + IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno)); rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize); - TEST_INCR(pPager->nWrite); + PAGER_INCR(sqlite3_pager_writedb_count); + PAGER_INCR(pPager->nWrite); + if( pList->pgno==1 ){ + memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers)); + } } #ifndef NDEBUG else{ @@ -2674,6 +2647,8 @@ int sqlite3PagerReleaseMemory(int nReq){ pTmp->pNextAll = pPg->pNextAll; } nReleased += sqliteAllocSize(pPg); + IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); + PAGER_INCR(sqlite3_pager_pgfree_count); sqliteFree(pPg); } @@ -2706,8 +2681,14 @@ static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){ rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize); } - IOTRACE(("PGIN %p %d\n", pPager, pgno)) + PAGER_INCR(sqlite3_pager_readdb_count); + PAGER_INCR(pPager->nRead); + IOTRACE(("PGIN %p %d\n", pPager, pgno)); PAGERTRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno); + if( pgno==1 ){ + memcpy(&pPager->dbFileVers, &((u8*)PGHDR_TO_DATA(pPg))[24], + sizeof(pPager->dbFileVers)); + } CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); return rc; } @@ -2808,16 +2789,21 @@ static int pagerSharedLock(Pager *pPager){ if( pPager->pAll ){ /* The shared-lock has just been acquired on the database file ** and there are already pages in the cache (from a previous - ** read or write transaction). If the value of the change-counter - ** stored in Pager.iChangeCount matches that found on page 1 of - ** the database file, then no database changes have occured since - ** the cache was last valid and it is safe to retain the cached - ** pages. Otherwise, if Pager.iChangeCount does not match the - ** change-counter on page 1 of the file, the current cache contents - ** must be discarded. + ** read or write transaction). Check to see if the database + ** has been modified. If the database has changed, flush the + ** cache. + ** + ** Database changes is detected by looking at 15 bytes beginning + ** at offset 24 into the file. The first 4 of these 16 bytes are + ** a 32-bit counter that is incremented with each change. The + ** other bytes change randomly with each file change when + ** a codec is in use. + ** + ** There is a vanishingly small chance that a change will not be + ** deteched. The chance of an undetected change is so small that + ** it can be neglected. */ - u8 zC[4]; - u32 iChangeCounter = 0; + char dbFileVers[sizeof(pPager->dbFileVers)]; sqlite3PagerPagecount(pPager); if( pPager->errCode ){ @@ -2825,19 +2811,19 @@ static int pagerSharedLock(Pager *pPager){ } if( pPager->dbSize>0 ){ - /* Read the 4-byte change counter directly from the file. */ rc = sqlite3OsSeek(pPager->fd, 24); if( rc!=SQLITE_OK ){ return rc; } - rc = sqlite3OsRead(pPager->fd, zC, 4); + rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers)); if( rc!=SQLITE_OK ){ return rc; } - iChangeCounter = (zC[0]<<24) + (zC[1]<<16) + (zC[2]<<8) + zC[3]; + }else{ + memset(dbFileVers, 0, sizeof(dbFileVers)); } - if( iChangeCounter!=pPager->iChangeCount ){ + if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ pager_reset(pPager); } } @@ -2959,12 +2945,20 @@ pager_allocate_out: ** Since _lookup() never goes to disk, it never has to deal with locks ** or journal files. ** -** If clrFlag is false, the page contents are actually read from disk. -** If clfFlag is true, it means the page is about to be erased and -** rewritten without first being read so there is no point it doing -** the disk I/O. +** If noContent is false, the page contents are actually read from disk. +** If noContent is true, it means that we do not care about the contents +** of the page at this time, so do not do a disk read. Just fill in the +** page content with zeros. But mark the fact that we have not read the +** content by setting the PgHdr.needRead flag. Later on, if +** sqlite3PagerWrite() is called on this page, that means that the +** content is needed and the disk read should occur at that point. */ -int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag){ +int sqlite3PagerAcquire( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int noContent /* Do not bother reading content from disk if true */ +){ PgHdr *pPg; int rc; @@ -3000,7 +2994,7 @@ int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag){ /* The requested page is not in the page cache. */ int nMax; int h; - TEST_INCR(pPager->nMiss); + PAGER_INCR(pPager->nMiss); rc = pagerAllocatePage(pPager, &pPg); if( rc!=SQLITE_OK ){ return rc; @@ -3036,16 +3030,16 @@ int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag){ /* Populate the page with data, either by reading from the database ** file, or by setting the entire page to zero. */ - if( nMax<(int)pgno || MEMDB || (clrFlag && !pPager->alwaysRollback) ){ + if( nMax<(int)pgno || MEMDB || (noContent && !pPager->alwaysRollback) ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); + pPg->needRead = noContent && !pPager->alwaysRollback; + IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ rc = readDbPage(pPager, pPg, pgno); if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ pPg->pgno = 0; sqlite3PagerUnref(pPg); return rc; - }else{ - TEST_INCR(pPager->nRead); } } @@ -3065,7 +3059,7 @@ int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag){ }else{ /* The requested page is in the page cache. */ assert(pPager->nRef>0 || pgno==1); - TEST_INCR(pPager->nHit); + PAGER_INCR(pPager->nHit); page_ref(pPg); } *ppPage = pPg; @@ -3365,6 +3359,23 @@ static int pager_write(PgHdr *pPg){ CHECK_PAGE(pPg); + /* If this page was previously acquired with noContent==1, that means + ** we didn't really read in the content of the page. This can happen + ** (for example) when the page is being moved to the freelist. But + ** now we are (perhaps) moving the page off of the freelist for + ** reuse and we need to know its original content so that content + ** can be stored in the rollback journal. So do the read at this + ** time. + */ + if( pPg->needRead ){ + rc = readDbPage(pPager, pPg, pPg->pgno); + if( rc==SQLITE_OK ){ + pPg->needRead = 0; + }else{ + return rc; + } + } + /* Mark the page as dirty. If the page has already been written ** to the journal then we can return right away. */ @@ -3425,7 +3436,8 @@ static int pager_write(PgHdr *pPg){ put32bits(pData2, pPg->pgno); rc = sqlite3OsWrite(pPager->jfd, pData2, szPg); IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, - pPager->journalOff, szPg)) + pPager->journalOff, szPg)); + PAGER_INCR(sqlite3_pager_writej_count); pPager->journalOff += szPg; PAGERTRACE4("JOURNAL %d page %d needSync=%d\n", PAGERID(pPager), pPg->pgno, pPg->needSync); @@ -3608,7 +3620,7 @@ int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void *pData){ /* ** A call to this routine tells the pager that it is not necessary to -** write the information on page "pgno" back to the disk, even though +** write the information on page pPg back to the disk, even though ** that page might be marked as dirty. ** ** The overlying software layer calls this routine when all of the data @@ -3630,13 +3642,11 @@ int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void *pData){ ** page contains critical data, we still need to be sure it gets ** rolled back in spite of the sqlite3PagerDontRollback() call. */ -void sqlite3PagerDontWrite(Pager *pPager, Pgno pgno){ - PgHdr *pPg; +void sqlite3PagerDontWrite(DbPage *pDbPage){ + PgHdr *pPg = pDbPage; + Pager *pPager = pPg->pPager; if( MEMDB ) return; - - pPg = pager_lookup(pPager, pgno); - assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */ pPg->alwaysRollback = 1; if( pPg->dirty && !pPager->stmtInUse ){ assert( pPager->state>=PAGER_SHARED ); @@ -3650,8 +3660,8 @@ void sqlite3PagerDontWrite(Pager *pPager, Pgno pgno){ ** corruption during the next transaction. */ }else{ - PAGERTRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager)); - IOTRACE(("CLEAN %p %d\n", pPager, pgno)) + PAGERTRACE3("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)); + IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno)) makeClean(pPg); #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); @@ -3665,6 +3675,11 @@ void sqlite3PagerDontWrite(Pager *pPager, Pgno pgno){ ** it is not necessary to restore the data on the given page. This ** means that the pager does not have to record the given page in the ** rollback journal. +** +** If we have not yet actually read the content of this page (if +** the PgHdr.needRead flag is set) then this routine acts as a promise +** that we will never need to read the page content in the future. +** so the needRead flag can be cleared at this point. */ void sqlite3PagerDontRollback(DbPage *pPg){ Pager *pPager = pPg->pPager; @@ -3676,6 +3691,7 @@ void sqlite3PagerDontRollback(DbPage *pPg){ assert( pPager->aInJournal!=0 ); pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); pPg->inJournal = 1; + pPg->needRead = 0; if( pPager->stmtInUse ){ pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); } @@ -3715,7 +3731,6 @@ static int pager_incr_changecounter(Pager *pPager){ /* Increment the value just read and write it back to byte 24. */ change_counter++; put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); - pPager->iChangeCount = change_counter; /* Release the page reference. */ sqlite3PagerUnref(pPgHdr); diff --git a/ext/pdo_sqlite/sqlite/src/pager.h b/ext/pdo_sqlite/sqlite/src/pager.h index 104a795982..5e011d1185 100644 --- a/ext/pdo_sqlite/sqlite/src/pager.h +++ b/ext/pdo_sqlite/sqlite/src/pager.h @@ -109,7 +109,7 @@ int sqlite3PagerStmtBegin(Pager*); int sqlite3PagerStmtCommit(Pager*); int sqlite3PagerStmtRollback(Pager*); void sqlite3PagerDontRollback(DbPage*); -void sqlite3PagerDontWrite(Pager*, Pgno); +void sqlite3PagerDontWrite(DbPage*); int sqlite3PagerRefcount(Pager*); int *sqlite3PagerStats(Pager*); void sqlite3PagerSetSafetyLevel(Pager*,int,int); diff --git a/ext/pdo_sqlite/sqlite/src/select.c b/ext/pdo_sqlite/sqlite/src/select.c index 59120b32ee..120470b565 100644 --- a/ext/pdo_sqlite/sqlite/src/select.c +++ b/ext/pdo_sqlite/sqlite/src/select.c @@ -551,6 +551,7 @@ static int selectInnerLoop( sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); + p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr,(iParm>>16)&0xff); if( pOrderBy ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set @@ -558,9 +559,7 @@ static int selectInnerLoop( ** case the order does matter */ pushOntoSorter(pParse, pOrderBy, p); }else{ - char affinity = (iParm>>16)&0xFF; - affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, affinity); - sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); + sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); } sqlite3VdbeJumpHere(v, addr2); @@ -721,7 +720,7 @@ static void generateSortTail( sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "c", P3_STATIC); + sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); break; } @@ -1096,7 +1095,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ sqlite3Dequote(zName); if( sqlite3MallocFailed() ){ sqliteFree(zName); - sqlite3DeleteTable(0, pTab); + sqlite3DeleteTable(pTab); return 0; } @@ -1400,8 +1399,11 @@ static int matchOrderbyToColumn( } pEList = pSelect->pEList; for(i=0; inExpr; i++){ + struct ExprList_item *pItem; Expr *pE = pOrderBy->a[i].pExpr; int iCol = -1; + char *zLabel; + if( pOrderBy->a[i].done ) continue; if( sqlite3ExprIsInteger(pE, &iCol) ){ if( iCol<=0 || iCol>pEList->nExpr ){ @@ -1414,20 +1416,23 @@ static int matchOrderbyToColumn( if( !mustComplete ) continue; iCol--; } - for(j=0; iCol<0 && jnExpr; j++){ - if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){ - char *zName, *zLabel; - zName = pEList->a[j].zName; - zLabel = sqlite3NameFromToken(&pE->token); - assert( zLabel!=0 ); - if( sqlite3StrICmp(zName, zLabel)==0 ){ + if( iCol<0 && (zLabel = sqlite3NameFromToken(&pE->token))!=0 ){ + for(j=0, pItem=pEList->a; jnExpr; j++, pItem++){ + char *zName; + int isMatch; + if( pItem->zName ){ + zName = sqlite3StrDup(pItem->zName); + }else{ + zName = sqlite3NameFromToken(&pItem->pExpr->token); + } + isMatch = zName && sqlite3StrICmp(zName, zLabel)==0; + sqliteFree(zName); + if( isMatch ){ iCol = j; + break; } - sqliteFree(zLabel); - } - if( iCol<0 && sqlite3ExprCompare(pE, pEList->a[j].pExpr) ){ - iCol = j; } + sqliteFree(zLabel); } if( iCol>=0 ){ pE->op = TK_COLUMN; @@ -1435,8 +1440,7 @@ static int matchOrderbyToColumn( pE->iTable = iTable; pE->iAgg = -1; pOrderBy->a[i].done = 1; - } - if( iCol<0 && mustComplete ){ + }else if( mustComplete ){ sqlite3ErrorMsg(pParse, "ORDER BY term number %d does not match any result column", i+1); nErr++; @@ -2212,7 +2216,7 @@ static int flattenSubquery( int nSubSrc = pSubSrc->nSrc; int jointype = pSubitem->jointype; - sqlite3DeleteTable(0, pSubitem->pTab); + sqlite3DeleteTable(pSubitem->pTab); sqliteFree(pSubitem->zDatabase); sqliteFree(pSubitem->zName); sqliteFree(pSubitem->zAlias); @@ -2590,12 +2594,15 @@ int sqlite3SelectResolve( */ sNC.pEList = p->pEList; if( sqlite3ExprResolveNames(&sNC, p->pWhere) || - sqlite3ExprResolveNames(&sNC, p->pHaving) || - processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") || - processOrderGroupBy(&sNC, pGroupBy, "GROUP") - ){ + sqlite3ExprResolveNames(&sNC, p->pHaving) ){ return SQLITE_ERROR; } + if( p->pPrior==0 ){ + if( processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") || + processOrderGroupBy(&sNC, pGroupBy, "GROUP") ){ + return SQLITE_ERROR; + } + } /* Make sure the GROUP BY clause does not contain aggregate functions. */ diff --git a/ext/pdo_sqlite/sqlite/src/sqliteInt.h b/ext/pdo_sqlite/sqlite/src/sqliteInt.h index 0b8950d7bc..15a27efb34 100644 --- a/ext/pdo_sqlite/sqlite/src/sqliteInt.h +++ b/ext/pdo_sqlite/sqlite/src/sqliteInt.h @@ -381,6 +381,14 @@ struct Db { /* ** An instance of the following structure stores a database schema. +** +** If there are no virtual tables configured in this schema, the +** Schema.db variable is set to NULL. After the first virtual table +** has been added, it is set to point to the database connection +** used to create the connection. Once a virtual table has been +** added to the Schema structure and the Schema.db variable populated, +** only that database connection may use the Schema to prepare +** statements. */ struct Schema { int schema_cookie; /* Database schema version number for this file */ @@ -393,6 +401,9 @@ struct Schema { u8 enc; /* Text encoding used by this database */ u16 flags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3 *db; /* "Owner" connection. See comment above */ +#endif }; /* @@ -1266,6 +1277,7 @@ struct Select { u8 isAgg; /* True if this is an aggregate query */ u8 usesEphm; /* True if uses an OpenEphemeral opcode */ u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */ + char affinity; /* MakeRecord with this affinity for SRT_Set */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ @@ -1631,7 +1643,7 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); #endif void sqlite3DropTable(Parse*, SrcList*, int, int); -void sqlite3DeleteTable(sqlite3*, Table*); +void sqlite3DeleteTable(Table*); void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int); void *sqlite3ArrayAllocate(void*,int,int,int*,int*,int*); IdList *sqlite3IdListAppend(IdList*, Token*); @@ -1889,7 +1901,7 @@ int sqlite3OpenTempDatabase(Parse *); int sqlite3VtabCommit(sqlite3 *db); #endif void sqlite3VtabLock(sqlite3_vtab*); -void sqlite3VtabUnlock(sqlite3_vtab*); +void sqlite3VtabUnlock(sqlite3*, sqlite3_vtab*); void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabArgInit(Parse*); diff --git a/ext/pdo_sqlite/sqlite/src/test1.c b/ext/pdo_sqlite/sqlite/src/test1.c index f271eee875..7448de0e66 100644 --- a/ext/pdo_sqlite/sqlite/src/test1.c +++ b/ext/pdo_sqlite/sqlite/src/test1.c @@ -197,6 +197,57 @@ static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ return 0; } +/* +** The I/O tracing callback. +*/ +static FILE *iotrace_file = 0; +static void io_trace_callback(const char *zFormat, ...){ + va_list ap; + va_start(ap, zFormat); + vfprintf(iotrace_file, zFormat, ap); + va_end(ap); + fflush(iotrace_file); +} + +/* +** Usage: io_trace FILENAME +** +** Turn I/O tracing on or off. If FILENAME is not an empty string, +** I/O tracing begins going into FILENAME. If FILENAME is an empty +** string, I/O tracing is turned off. +*/ +static int test_io_trace( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " FILENAME\"", 0); + return TCL_ERROR; + } + if( iotrace_file ){ + if( iotrace_file!=stdout && iotrace_file!=stderr ){ + fclose(iotrace_file); + } + iotrace_file = 0; + sqlite3_io_trace = 0; + } + if( argv[1][0] ){ + if( strcmp(argv[1],"stdout")==0 ){ + iotrace_file = stdout; + }else if( strcmp(argv[1],"stderr")==0 ){ + iotrace_file = stderr; + }else{ + iotrace_file = fopen(argv[1], "w"); + } + sqlite3_io_trace = io_trace_callback; + } + return SQLITE_OK; +} + + /* ** Usage: sqlite3_exec_printf DB FORMAT STRING ** @@ -4216,6 +4267,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used }, { "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout }, { "printf", (Tcl_CmdProc*)test_printf }, + { "sqlite3_io_trace", (Tcl_CmdProc*)test_io_trace }, }; static struct { char *zName; @@ -4338,6 +4390,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_like_count; extern int sqlite3_tsd_count; extern int sqlite3_xferopt_count; + extern int sqlite3_pager_readdb_count; + extern int sqlite3_pager_writedb_count; + extern int sqlite3_pager_writej_count; + extern int sqlite3_pager_pgfree_count; #if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE extern int threadsOverrideEachOthersLocks; #endif @@ -4377,6 +4433,14 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ (char*)&sqlite3_tsd_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite3_xferopt_count", (char*)&sqlite3_xferopt_count, TCL_LINK_INT); + Tcl_LinkVar(interp, "sqlite3_pager_readdb_count", + (char*)&sqlite3_pager_readdb_count, TCL_LINK_INT); + Tcl_LinkVar(interp, "sqlite3_pager_writedb_count", + (char*)&sqlite3_pager_writedb_count, TCL_LINK_INT); + Tcl_LinkVar(interp, "sqlite3_pager_writej_count", + (char*)&sqlite3_pager_writej_count, TCL_LINK_INT); + Tcl_LinkVar(interp, "sqlite3_pager_pgfree_count", + (char*)&sqlite3_pager_pgfree_count, TCL_LINK_INT); #ifndef SQLITE_OMIT_UTF16 Tcl_LinkVar(interp, "unaligned_string_counter", (char*)&unaligned_string_counter, TCL_LINK_INT); diff --git a/ext/pdo_sqlite/sqlite/src/tokenize.c b/ext/pdo_sqlite/sqlite/src/tokenize.c index 3837e276ec..96212b5888 100644 --- a/ext/pdo_sqlite/sqlite/src/tokenize.c +++ b/ext/pdo_sqlite/sqlite/src/tokenize.c @@ -495,7 +495,7 @@ abort_parse: ** structure built up in pParse->pNewTable. The calling code (see vtab.c) ** will take responsibility for freeing the Table structure. */ - sqlite3DeleteTable(pParse->db, pParse->pNewTable); + sqlite3DeleteTable(pParse->pNewTable); } sqlite3DeleteTrigger(pParse->pNewTrigger); diff --git a/ext/pdo_sqlite/sqlite/src/vdbe.c b/ext/pdo_sqlite/sqlite/src/vdbe.c index cab35069cc..9bbc65a2eb 100644 --- a/ext/pdo_sqlite/sqlite/src/vdbe.c +++ b/ext/pdo_sqlite/sqlite/src/vdbe.c @@ -2521,7 +2521,23 @@ case OP_VerifyCookie: { /* no-push */ } if( rc==SQLITE_OK && iMeta!=pOp->p2 ){ sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0); - sqlite3ResetInternalSchema(db, pOp->p1); + /* If the schema-cookie from the database file matches the cookie + ** stored with the in-memory representation of the schema, do + ** not reload the schema from the database file. + ** + ** If virtual-tables are in use, this is not just an optimisation. + ** Often, v-tables store their data in other SQLite tables, which + ** are queried from within xNext() and other v-table methods using + ** prepared queries. If such a query is out-of-date, we do not want to + ** discard the database schema, as the user code implementing the + ** v-table would have to be ready for the sqlite3_vtab structure itself + ** to be invalidated whenever sqlite3_step() is called from within + ** a v-table method. + */ + if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ + sqlite3ResetInternalSchema(db, pOp->p1); + } + sqlite3ExpirePreparedStatements(db); rc = SQLITE_SCHEMA; } @@ -4881,7 +4897,7 @@ case OP_VUpdate: { /* no-push */ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; sqlite3VtabLock(pVtab); rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); - sqlite3VtabUnlock(pVtab); + sqlite3VtabUnlock(db, pVtab); if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( pOp->p1 && rc==SQLITE_OK ){ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); diff --git a/ext/pdo_sqlite/sqlite/src/vdbeaux.c b/ext/pdo_sqlite/sqlite/src/vdbeaux.c index 064849a36a..6c1af395a0 100644 --- a/ext/pdo_sqlite/sqlite/src/vdbeaux.c +++ b/ext/pdo_sqlite/sqlite/src/vdbeaux.c @@ -145,7 +145,6 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ VdbeOp *pOp; i = p->nOp; - p->nOp++; assert( p->magic==VDBE_MAGIC_INIT ); if( p->nOpAlloc<=i ){ resizeOpArray(p, i+1); @@ -153,6 +152,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ return 0; } } + p->nOp++; pOp = &p->aOp[i]; pOp->opcode = op; pOp->p1 = p1; @@ -557,9 +557,8 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ */ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_list ap; - assert( p->nOp>0 ); - assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 - || sqlite3MallocFailed() ); + assert( p->nOp>0 || p->aOp==0 ); + assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 || sqlite3MallocFailed() ); va_start(ap, zFormat); sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC); va_end(ap); @@ -571,8 +570,8 @@ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ */ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ assert( p->magic==VDBE_MAGIC_INIT ); - assert( addr>=0 && addrnOp ); - return &p->aOp[addr]; + assert( (addr>=0 && addrnOp) || sqlite3MallocFailed() ); + return ((addr>=0 && addrnOp)?(&p->aOp[addr]):0); } #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \ diff --git a/ext/pdo_sqlite/sqlite/src/vtab.c b/ext/pdo_sqlite/sqlite/src/vtab.c index 5f1d560273..862b3835eb 100644 --- a/ext/pdo_sqlite/sqlite/src/vtab.c +++ b/ext/pdo_sqlite/sqlite/src/vtab.c @@ -56,10 +56,18 @@ void sqlite3VtabLock(sqlite3_vtab *pVtab){ ** Unlock a virtual table. When the last lock is removed, ** disconnect the virtual table. */ -void sqlite3VtabUnlock(sqlite3_vtab *pVtab){ +void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){ pVtab->nRef--; + assert(db); + assert(!sqlite3SafetyCheck(db)); if( pVtab->nRef==0 ){ - pVtab->pModule->xDisconnect(pVtab); + if( db->magic==SQLITE_MAGIC_BUSY ){ + sqlite3SafetyOff(db); + pVtab->pModule->xDisconnect(pVtab); + sqlite3SafetyOn(db); + } else { + pVtab->pModule->xDisconnect(pVtab); + } } } @@ -72,7 +80,7 @@ void sqlite3VtabClear(Table *p){ sqlite3_vtab *pVtab = p->pVtab; if( pVtab ){ assert( p->pMod && p->pMod->pModule ); - sqlite3VtabUnlock(pVtab); + sqlite3VtabUnlock(p->pSchema->db, pVtab); p->pVtab = 0; } if( p->azModuleArg ){ @@ -124,6 +132,11 @@ void sqlite3VtabBeginParse( int iDb; /* The database the table is being created in */ Table *pTable; /* The new virtual table */ + if( sqlite3ThreadDataReadOnly()->useSharedData ){ + sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode"); + return; + } + sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); pTable = pParse->pNewTable; if( pTable==0 || pParse->nErr ) return; @@ -248,6 +261,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } + pSchema->db = pParse->db; pParse->pNewTable = 0; } } @@ -297,6 +311,10 @@ static int vtabCallConstructor( char *zErr = 0; char *zModuleName = sqlite3MPrintf("%s", pTab->zName); + if( !zModuleName ){ + return SQLITE_NOMEM; + } + assert( !db->pVTab ); assert( xConstruct ); @@ -457,6 +475,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ pTab->nCol = sParse.pNewTable->nCol; sParse.pNewTable->nCol = 0; sParse.pNewTable->aCol = 0; + db->pVTab = 0; } else { sqlite3Error(db, SQLITE_ERROR, zErr); sqliteFree(zErr); @@ -465,12 +484,11 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ sParse.declareVtab = 0; sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); - sqlite3DeleteTable(0, sParse.pNewTable); + sqlite3DeleteTable(sParse.pNewTable); sParse.pNewTable = 0; - db->pVTab = 0; assert( (rc&0xff)==rc ); - return rc; + return sqlite3ApiExit(db, rc); } /* @@ -518,7 +536,7 @@ static void callFinaliser(sqlite3 *db, int offset){ int (*x)(sqlite3_vtab *); x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset); if( x ) x(pVtab); - sqlite3VtabUnlock(pVtab); + sqlite3VtabUnlock(db, pVtab); } sqliteFree(db->aVTrans); db->nVTrans = 0; -- 2.40.0