mirror of
https://github.com/php/php-src.git
synced 2025-08-19 08:49:28 +02:00
Upgraded SQLite 3 to version 3.3.16
This commit is contained in:
parent
6a0efe0b7d
commit
111df261a5
21 changed files with 338 additions and 185 deletions
2
NEWS
2
NEWS
|
@ -1,6 +1,7 @@
|
||||||
PHP NEWS
|
PHP NEWS
|
||||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||
?? Apr 2007, PHP 5.2.2RC2
|
?? 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
|
- Fixed bug #41109 (recursiveiterator.inc says "implements" Iterator instead of
|
||||||
"extends"). (Marcus)
|
"extends"). (Marcus)
|
||||||
- Fixed bug #41093 (magic_quotes_gpc ignores first arrays keys). (Arpad, Ilia)
|
- 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
|
. libpq (PostgreSQL) to version 8.2.3
|
||||||
. libmysql (MySQL) to version 5.0.37
|
. libmysql (MySQL) to version 5.0.37
|
||||||
. openssl to version 0.9.8e
|
. openssl to version 0.9.8e
|
||||||
- Upgraded SQLite 3 to version 3.3.15 (Ilia)
|
|
||||||
- Upgraded PCRE to version 7.0 (Nuno)
|
- Upgraded PCRE to version 7.0 (Nuno)
|
||||||
- Updated timezone database to version 2007.3. (Derick)
|
- Updated timezone database to version 2007.3. (Derick)
|
||||||
- Improved FastCGI SAPI to support external pipe and socket servers on win32.
|
- Improved FastCGI SAPI to support external pipe and socket servers on win32.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
3.3.15
|
3.3.16
|
||||||
|
|
|
@ -1396,13 +1396,20 @@ static void zeroPage(MemPage *pPage, int flags){
|
||||||
/*
|
/*
|
||||||
** Get a page from the pager. Initialize the MemPage.pBt and
|
** Get a page from the pager. Initialize the MemPage.pBt and
|
||||||
** MemPage.aData elements if needed.
|
** 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;
|
int rc;
|
||||||
MemPage *pPage;
|
MemPage *pPage;
|
||||||
DbPage *pDbPage;
|
DbPage *pDbPage;
|
||||||
|
|
||||||
rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, clrFlag);
|
rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage);
|
pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage);
|
||||||
pPage->aData = sqlite3PagerGetData(pDbPage);
|
pPage->aData = sqlite3PagerGetData(pDbPage);
|
||||||
|
@ -1411,9 +1418,6 @@ static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage, int clrFlag){
|
||||||
pPage->pgno = pgno;
|
pPage->pgno = pgno;
|
||||||
pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
|
pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
|
||||||
*ppPage = pPage;
|
*ppPage = pPage;
|
||||||
if( clrFlag ){
|
|
||||||
sqlite3PagerDontRollback(pPage->pDbPage);
|
|
||||||
}
|
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3830,6 +3834,7 @@ static int allocateBtreePage(
|
||||||
put4byte(&aData[4], k-1);
|
put4byte(&aData[4], k-1);
|
||||||
rc = getPage(pBt, *pPgno, ppPage, 1);
|
rc = getPage(pBt, *pPgno, ppPage, 1);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
|
sqlite3PagerDontRollback((*ppPage)->pDbPage);
|
||||||
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
|
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
releasePage(*ppPage);
|
releasePage(*ppPage);
|
||||||
|
@ -3948,7 +3953,7 @@ static int freePage(MemPage *pPage){
|
||||||
put4byte(&pTrunk->aData[4], k+1);
|
put4byte(&pTrunk->aData[4], k+1);
|
||||||
put4byte(&pTrunk->aData[8+k*4], pPage->pgno);
|
put4byte(&pTrunk->aData[8+k*4], pPage->pgno);
|
||||||
#ifndef SQLITE_SECURE_DELETE
|
#ifndef SQLITE_SECURE_DELETE
|
||||||
sqlite3PagerDontWrite(pBt->pPager, pPage->pgno);
|
sqlite3PagerDontWrite(pPage->pDbPage);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
|
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) ){
|
if( ovflPgno==0 || ovflPgno>sqlite3PagerPagecount(pBt->pPager) ){
|
||||||
return SQLITE_CORRUPT_BKPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
rc = getPage(pBt, ovflPgno, &pOvfl, 0);
|
rc = getPage(pBt, ovflPgno, &pOvfl, nOvfl==0);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
if( nOvfl ){
|
if( nOvfl ){
|
||||||
ovflPgno = get4byte(pOvfl->aData);
|
ovflPgno = get4byte(pOvfl->aData);
|
||||||
|
@ -6561,18 +6566,31 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
||||||
rc = sqlite3PagerOverwrite(pBtTo->pPager, i, sqlite3PagerGetData(pDbPage));
|
rc = sqlite3PagerOverwrite(pBtTo->pPager, i, sqlite3PagerGetData(pDbPage));
|
||||||
sqlite3PagerUnref(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++){
|
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
|
||||||
DbPage *pDbPage;
|
DbPage *pDbPage;
|
||||||
if( i==iSkip ) continue;
|
if( i==iSkip ) continue;
|
||||||
rc = sqlite3PagerGet(pBtTo->pPager, i, &pDbPage);
|
rc = sqlite3PagerGet(pBtTo->pPager, i, &pDbPage);
|
||||||
if( rc ) break;
|
if( rc ) break;
|
||||||
rc = sqlite3PagerWrite(pDbPage);
|
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);
|
sqlite3PagerUnref(pDbPage);
|
||||||
sqlite3PagerDontWrite(pBtTo->pPager, i);
|
|
||||||
}
|
}
|
||||||
if( !rc && nPage<nToPage ){
|
if( !rc && nPage<nToPage ){
|
||||||
rc = sqlite3PagerTruncate(pBtTo->pPager, nPage);
|
rc = sqlite3PagerTruncate(pBtTo->pPager, nPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc ){
|
if( rc ){
|
||||||
sqlite3BtreeRollback(pTo);
|
sqlite3BtreeRollback(pTo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,18 +478,11 @@ static void sqliteResetColumnNames(Table *pTable){
|
||||||
** foreign keys from the sqlite.aFKey hash table. But it does destroy
|
** foreign keys from the sqlite.aFKey hash table. But it does destroy
|
||||||
** memory structures of the indices and foreign keys associated with
|
** memory structures of the indices and foreign keys associated with
|
||||||
** the table.
|
** 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;
|
Index *pIndex, *pNext;
|
||||||
FKey *pFKey, *pNextFKey;
|
FKey *pFKey, *pNextFKey;
|
||||||
|
|
||||||
db = 0;
|
|
||||||
|
|
||||||
if( pTable==0 ) return;
|
if( pTable==0 ) return;
|
||||||
|
|
||||||
/* Do not delete the table until the reference count reaches zero. */
|
/* 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
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||||
/* Delete all foreign keys associated with this table. The keys
|
/* 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){
|
for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
|
||||||
pNextFKey = pFKey->pNextFrom;
|
pNextFKey = pFKey->pNextFrom;
|
||||||
|
@ -561,7 +554,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sqlite3DeleteTable(db, p);
|
sqlite3DeleteTable(p);
|
||||||
}
|
}
|
||||||
db->flags |= SQLITE_InternChanges;
|
db->flags |= SQLITE_InternChanges;
|
||||||
}
|
}
|
||||||
|
@ -810,7 +803,7 @@ void sqlite3StartTable(
|
||||||
pTable->iPKey = -1;
|
pTable->iPKey = -1;
|
||||||
pTable->pSchema = db->aDb[iDb].pSchema;
|
pTable->pSchema = db->aDb[iDb].pSchema;
|
||||||
pTable->nRef = 1;
|
pTable->nRef = 1;
|
||||||
if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
|
if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable);
|
||||||
pParse->pNewTable = pTable;
|
pParse->pNewTable = pTable;
|
||||||
|
|
||||||
/* If this is the magic sqlite_sequence table used by autoincrement,
|
/* If this is the magic sqlite_sequence table used by autoincrement,
|
||||||
|
@ -1484,7 +1477,7 @@ void sqlite3EndTable(
|
||||||
p->aCol = pSelTab->aCol;
|
p->aCol = pSelTab->aCol;
|
||||||
pSelTab->nCol = 0;
|
pSelTab->nCol = 0;
|
||||||
pSelTab->aCol = 0;
|
pSelTab->aCol = 0;
|
||||||
sqlite3DeleteTable(0, pSelTab);
|
sqlite3DeleteTable(pSelTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1712,7 +1705,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||||
pTable->aCol = pSelTab->aCol;
|
pTable->aCol = pSelTab->aCol;
|
||||||
pSelTab->nCol = 0;
|
pSelTab->nCol = 0;
|
||||||
pSelTab->aCol = 0;
|
pSelTab->aCol = 0;
|
||||||
sqlite3DeleteTable(0, pSelTab);
|
sqlite3DeleteTable(pSelTab);
|
||||||
pTable->pSchema->flags |= DB_UnresetViews;
|
pTable->pSchema->flags |= DB_UnresetViews;
|
||||||
}else{
|
}else{
|
||||||
pTable->nCol = 0;
|
pTable->nCol = 0;
|
||||||
|
@ -2210,7 +2203,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||||
sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2);
|
sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2);
|
||||||
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort,
|
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort,
|
||||||
"indexed columns are not unique", P3_STATIC);
|
"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_IdxInsert, iIdx, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
|
sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
|
||||||
|
@ -2959,7 +2952,7 @@ void sqlite3SrcListDelete(SrcList *pList){
|
||||||
sqliteFree(pItem->zDatabase);
|
sqliteFree(pItem->zDatabase);
|
||||||
sqliteFree(pItem->zName);
|
sqliteFree(pItem->zName);
|
||||||
sqliteFree(pItem->zAlias);
|
sqliteFree(pItem->zAlias);
|
||||||
sqlite3DeleteTable(0, pItem->pTab);
|
sqlite3DeleteTable(pItem->pTab);
|
||||||
sqlite3SelectDelete(pItem->pSelect);
|
sqlite3SelectDelete(pItem->pSelect);
|
||||||
sqlite3ExprDelete(pItem->pOn);
|
sqlite3ExprDelete(pItem->pOn);
|
||||||
sqlite3IdListDelete(pItem->pUsing);
|
sqlite3IdListDelete(pItem->pUsing);
|
||||||
|
|
|
@ -344,7 +344,7 @@ void sqlite3SchemaFree(void *p){
|
||||||
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
|
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
|
||||||
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
||||||
Table *pTab = sqliteHashData(pElem);
|
Table *pTab = sqliteHashData(pElem);
|
||||||
sqlite3DeleteTable(0, pTab);
|
sqlite3DeleteTable(pTab);
|
||||||
}
|
}
|
||||||
sqlite3HashClear(&temp1);
|
sqlite3HashClear(&temp1);
|
||||||
pSchema->pSeqTab = 0;
|
pSchema->pSeqTab = 0;
|
||||||
|
|
|
@ -27,7 +27,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||||
struct SrcList_item *pItem;
|
struct SrcList_item *pItem;
|
||||||
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
|
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
|
||||||
pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
|
pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
|
||||||
sqlite3DeleteTable(pParse->db, pItem->pTab);
|
sqlite3DeleteTable(pItem->pTab);
|
||||||
pItem->pTab = pTab;
|
pItem->pTab = pTab;
|
||||||
if( pTab ){
|
if( pTab ){
|
||||||
pTab->nRef++;
|
pTab->nRef++;
|
||||||
|
|
|
@ -1420,7 +1420,9 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||||
int iParm = pExpr->iTable + (((int)affinity)<<16);
|
int iParm = pExpr->iTable + (((int)affinity)<<16);
|
||||||
ExprList *pEList;
|
ExprList *pEList;
|
||||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
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;
|
pEList = pExpr->pSelect->pEList;
|
||||||
if( pEList && pEList->nExpr>0 ){
|
if( pEList && pEList->nExpr>0 ){
|
||||||
keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
|
keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
|
||||||
|
@ -1491,7 +1493,9 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||||
}
|
}
|
||||||
sqlite3ExprDelete(pSel->pLimit);
|
sqlite3ExprDelete(pSel->pLimit);
|
||||||
pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,8 +655,8 @@ static void hexFunc(
|
||||||
const unsigned char *pBlob;
|
const unsigned char *pBlob;
|
||||||
char *zHex, *z;
|
char *zHex, *z;
|
||||||
assert( argc==1 );
|
assert( argc==1 );
|
||||||
pBlob = sqlite3_value_blob(argv[0]);
|
|
||||||
n = sqlite3_value_bytes(argv[0]);
|
n = sqlite3_value_bytes(argv[0]);
|
||||||
|
pBlob = sqlite3_value_blob(argv[0]);
|
||||||
z = zHex = sqlite3_malloc(n*2 + 1);
|
z = zHex = sqlite3_malloc(n*2 + 1);
|
||||||
if( zHex==0 ) return;
|
if( zHex==0 ) return;
|
||||||
for(i=0; i<n; i++, pBlob++){
|
for(i=0; i<n; i++, pBlob++){
|
||||||
|
|
|
@ -705,7 +705,7 @@ void sqlite3Insert(
|
||||||
VdbeOp *pOp;
|
VdbeOp *pOp;
|
||||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
|
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
|
||||||
pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
|
pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
|
||||||
if( pOp->opcode==OP_Null ){
|
if( pOp && pOp->opcode==OP_Null ){
|
||||||
appendFlag = 1;
|
appendFlag = 1;
|
||||||
pOp->opcode = OP_NewRowid;
|
pOp->opcode = OP_NewRowid;
|
||||||
pOp->p1 = base;
|
pOp->p1 = base;
|
||||||
|
@ -1374,10 +1374,10 @@ static int xferOptimization(
|
||||||
int addr1, addr2; /* Loop addresses */
|
int addr1, addr2; /* Loop addresses */
|
||||||
int emptyDestTest; /* Address of test for empty pDest */
|
int emptyDestTest; /* Address of test for empty pDest */
|
||||||
int emptySrcTest; /* Address of test for empty pSrc */
|
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 */
|
Vdbe *v; /* The VDBE we are building */
|
||||||
KeyInfo *pKey; /* Key information for an index */
|
KeyInfo *pKey; /* Key information for an index */
|
||||||
int counterMem; /* Memory register used by AUTOINC */
|
int counterMem; /* Memory register used by AUTOINC */
|
||||||
|
int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
|
||||||
|
|
||||||
if( pSelect==0 ){
|
if( pSelect==0 ){
|
||||||
return 0; /* Must be of the form INSERT INTO ... SELECT ... */
|
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){
|
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
||||||
|
if( pDestIdx->onError!=OE_None ){
|
||||||
|
destHasUniqueIdx = 1;
|
||||||
|
}
|
||||||
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
|
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
|
||||||
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
||||||
}
|
}
|
||||||
|
@ -1504,11 +1507,16 @@ static int xferOptimization(
|
||||||
iDest = pParse->nTab++;
|
iDest = pParse->nTab++;
|
||||||
counterMem = autoIncBegin(pParse, iDbDest, pDest);
|
counterMem = autoIncBegin(pParse, iDbDest, pDest);
|
||||||
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
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
|
/* If tables do not have an INTEGER PRIMARY KEY and there
|
||||||
** are indices to be copied and the destination is not empty,
|
** are indices to be copied and the destination is not empty,
|
||||||
** we have to disallow the transfer optimization because the
|
** we have to disallow the transfer optimization because the
|
||||||
** the rowids might change which will mess up indexing.
|
** 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);
|
addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iDest, 0);
|
||||||
emptyDestTest = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
emptyDestTest = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||||
|
@ -1518,11 +1526,6 @@ static int xferOptimization(
|
||||||
}
|
}
|
||||||
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
|
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
|
||||||
emptySrcTest = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
|
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 ){
|
if( pDest->iPKey>=0 ){
|
||||||
addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
|
addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||||
|
@ -1562,13 +1565,6 @@ static int xferOptimization(
|
||||||
(char*)pKey, P3_KEYINFO_HANDOFF);
|
(char*)pKey, P3_KEYINFO_HANDOFF);
|
||||||
addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
|
addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_RowKey, 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_IdxInsert, iDest, 1);
|
||||||
sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1+1);
|
sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1+1);
|
||||||
sqlite3VdbeJumpHere(v, addr1);
|
sqlite3VdbeJumpHere(v, addr1);
|
||||||
|
|
|
@ -127,8 +127,18 @@ int sqlite3_close(sqlite3 *db){
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If there are any outstanding VMs, return SQLITE_BUSY. */
|
|
||||||
sqlite3ResetInternalSchema(db, 0);
|
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 ){
|
if( db->pVdbe ){
|
||||||
sqlite3Error(db, SQLITE_BUSY,
|
sqlite3Error(db, SQLITE_BUSY,
|
||||||
"Unable to close due to unfinalised statements");
|
"Unable to close due to unfinalised statements");
|
||||||
|
@ -149,8 +159,6 @@ int sqlite3_close(sqlite3 *db){
|
||||||
return SQLITE_ERROR;
|
return SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3VtabRollback(db);
|
|
||||||
|
|
||||||
for(j=0; j<db->nDb; j++){
|
for(j=0; j<db->nDb; j++){
|
||||||
struct Db *pDb = &db->aDb[j];
|
struct Db *pDb = &db->aDb[j];
|
||||||
if( pDb->pBt ){
|
if( pDb->pBt ){
|
||||||
|
|
|
@ -97,6 +97,7 @@ int sqlite3_diskfull = 0;
|
||||||
|| (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \
|
|| (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \
|
||||||
{ local_ioerr(); CODE; }
|
{ local_ioerr(); CODE; }
|
||||||
static void local_ioerr(){
|
static void local_ioerr(){
|
||||||
|
IOTRACE(("IOERR\n"));
|
||||||
sqlite3_io_error_hit = 1;
|
sqlite3_io_error_hit = 1;
|
||||||
}
|
}
|
||||||
#define SimulateDiskfullError(CODE) \
|
#define SimulateDiskfullError(CODE) \
|
||||||
|
|
|
@ -408,6 +408,12 @@ static void winceDestroyLock(winFile *pFile){
|
||||||
UnmapViewOfFile(pFile->shared);
|
UnmapViewOfFile(pFile->shared);
|
||||||
CloseHandle(pFile->hShared);
|
CloseHandle(pFile->hShared);
|
||||||
|
|
||||||
|
if( pFile->zDeleteOnClose ){
|
||||||
|
DeleteFileW(pFile->zDeleteOnClose);
|
||||||
|
sqliteFree(pFile->zDeleteOnClose);
|
||||||
|
pFile->zDeleteOnClose = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Done with the mutex */
|
/* Done with the mutex */
|
||||||
winceMutexRelease(pFile->hMutex);
|
winceMutexRelease(pFile->hMutex);
|
||||||
CloseHandle(pFile->hMutex);
|
CloseHandle(pFile->hMutex);
|
||||||
|
@ -975,10 +981,6 @@ static int winClose(OsFile **pId){
|
||||||
}while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
|
}while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
|
||||||
#if OS_WINCE
|
#if OS_WINCE
|
||||||
winceDestroyLock(pFile);
|
winceDestroyLock(pFile);
|
||||||
if( pFile->zDeleteOnClose ){
|
|
||||||
DeleteFileW(pFile->zDeleteOnClose);
|
|
||||||
sqliteFree(pFile->zDeleteOnClose);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
OpenCounter(-1);
|
OpenCounter(-1);
|
||||||
sqliteFree(pFile);
|
sqliteFree(pFile);
|
||||||
|
|
|
@ -162,6 +162,7 @@ struct PgHdr {
|
||||||
u8 dirty; /* TRUE if we need to write back changes */
|
u8 dirty; /* TRUE if we need to write back changes */
|
||||||
u8 needSync; /* Sync journal before writing this page */
|
u8 needSync; /* Sync journal before writing this page */
|
||||||
u8 alwaysRollback; /* Disable DontRollback() for 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 */
|
short int nRef; /* Number of users of this page */
|
||||||
PgHdr *pDirty, *pPrevDirty; /* Dirty pages */
|
PgHdr *pDirty, *pPrevDirty; /* Dirty pages */
|
||||||
u32 notUsed; /* Buffer space */
|
u32 notUsed; /* Buffer space */
|
||||||
|
@ -293,19 +294,26 @@ struct Pager {
|
||||||
Pager *pNext; /* Linked list of pagers in this thread */
|
Pager *pNext; /* Linked list of pagers in this thread */
|
||||||
#endif
|
#endif
|
||||||
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
|
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 following global variables hold counters used for
|
||||||
** the argument
|
** testing purposes only. These variables do not exist in
|
||||||
|
** a non-testing build. These variables are not thread-safe.
|
||||||
*/
|
*/
|
||||||
#ifdef SQLITE_TEST
|
#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
|
#else
|
||||||
# define TEST_INCR(x)
|
# define PAGER_INCR(v)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Journal files begin with the following magic string. The data
|
** Journal files begin with the following magic string. The data
|
||||||
** was obtained from /dev/random. It is used only as a sanity check.
|
** 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;
|
PgHdr *pPg, *pNext;
|
||||||
if( pPager->errCode ) return;
|
if( pPager->errCode ) return;
|
||||||
for(pPg=pPager->pAll; pPg; pPg=pNext){
|
for(pPg=pPager->pAll; pPg; pPg=pNext){
|
||||||
|
IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno));
|
||||||
|
PAGER_INCR(sqlite3_pager_pgfree_count);
|
||||||
pNext = pPg->pNextAll;
|
pNext = pPg->pNextAll;
|
||||||
sqliteFree(pPg);
|
sqliteFree(pPg);
|
||||||
}
|
}
|
||||||
|
@ -1121,12 +1131,14 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
|
||||||
#ifdef SQLITE_CHECK_PAGES
|
#ifdef SQLITE_CHECK_PAGES
|
||||||
pPg->pageHash = pager_pagehash(pPg);
|
pPg->pageHash = pager_pagehash(pPg);
|
||||||
#endif
|
#endif
|
||||||
CODEC1(pPager, pData, pPg->pgno, 3);
|
/* If this was page 1, then restore the value of Pager.dbFileVers.
|
||||||
|
** Do this before any decoding. */
|
||||||
/* If this was page 1, then restore the value of Pager.iChangeCount */
|
|
||||||
if( pgno==1 ){
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1219,51 +1231,6 @@ delmaster_out:
|
||||||
return rc;
|
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);
|
static void pager_truncate_cache(Pager *pPager);
|
||||||
|
|
||||||
|
@ -2049,6 +2016,8 @@ static void pager_truncate_cache(Pager *pPager){
|
||||||
ppPg = &pPg->pNextAll;
|
ppPg = &pPg->pNextAll;
|
||||||
}else{
|
}else{
|
||||||
*ppPg = pPg->pNextAll;
|
*ppPg = pPg->pNextAll;
|
||||||
|
IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno));
|
||||||
|
PAGER_INCR(sqlite3_pager_pgfree_count);
|
||||||
unlinkPage(pPg);
|
unlinkPage(pPg);
|
||||||
makeClean(pPg);
|
makeClean(pPg);
|
||||||
sqliteFree(pPg);
|
sqliteFree(pPg);
|
||||||
|
@ -2470,9 +2439,13 @@ static int pager_write_pagelist(PgHdr *pList){
|
||||||
if( pList->pgno<=pPager->dbSize ){
|
if( pList->pgno<=pPager->dbSize ){
|
||||||
char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
|
char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
|
||||||
PAGERTRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
|
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);
|
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
|
#ifndef NDEBUG
|
||||||
else{
|
else{
|
||||||
|
@ -2674,6 +2647,8 @@ int sqlite3PagerReleaseMemory(int nReq){
|
||||||
pTmp->pNextAll = pPg->pNextAll;
|
pTmp->pNextAll = pPg->pNextAll;
|
||||||
}
|
}
|
||||||
nReleased += sqliteAllocSize(pPg);
|
nReleased += sqliteAllocSize(pPg);
|
||||||
|
IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno));
|
||||||
|
PAGER_INCR(sqlite3_pager_pgfree_count);
|
||||||
sqliteFree(pPg);
|
sqliteFree(pPg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2706,8 +2681,14 @@ static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
|
||||||
rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
|
rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
|
||||||
pPager->pageSize);
|
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);
|
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);
|
CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -2808,16 +2789,21 @@ static int pagerSharedLock(Pager *pPager){
|
||||||
if( pPager->pAll ){
|
if( pPager->pAll ){
|
||||||
/* The shared-lock has just been acquired on the database file
|
/* The shared-lock has just been acquired on the database file
|
||||||
** and there are already pages in the cache (from a previous
|
** and there are already pages in the cache (from a previous
|
||||||
** read or write transaction). If the value of the change-counter
|
** read or write transaction). Check to see if the database
|
||||||
** stored in Pager.iChangeCount matches that found on page 1 of
|
** has been modified. If the database has changed, flush the
|
||||||
** the database file, then no database changes have occured since
|
** cache.
|
||||||
** the cache was last valid and it is safe to retain the cached
|
**
|
||||||
** pages. Otherwise, if Pager.iChangeCount does not match the
|
** Database changes is detected by looking at 15 bytes beginning
|
||||||
** change-counter on page 1 of the file, the current cache contents
|
** at offset 24 into the file. The first 4 of these 16 bytes are
|
||||||
** must be discarded.
|
** 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];
|
char dbFileVers[sizeof(pPager->dbFileVers)];
|
||||||
u32 iChangeCounter = 0;
|
|
||||||
sqlite3PagerPagecount(pPager);
|
sqlite3PagerPagecount(pPager);
|
||||||
|
|
||||||
if( pPager->errCode ){
|
if( pPager->errCode ){
|
||||||
|
@ -2825,19 +2811,19 @@ static int pagerSharedLock(Pager *pPager){
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pPager->dbSize>0 ){
|
if( pPager->dbSize>0 ){
|
||||||
/* Read the 4-byte change counter directly from the file. */
|
|
||||||
rc = sqlite3OsSeek(pPager->fd, 24);
|
rc = sqlite3OsSeek(pPager->fd, 24);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
rc = sqlite3OsRead(pPager->fd, zC, 4);
|
rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers));
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
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);
|
pager_reset(pPager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2959,12 +2945,20 @@ pager_allocate_out:
|
||||||
** Since _lookup() never goes to disk, it never has to deal with locks
|
** Since _lookup() never goes to disk, it never has to deal with locks
|
||||||
** or journal files.
|
** or journal files.
|
||||||
**
|
**
|
||||||
** If clrFlag is false, the page contents are actually read from disk.
|
** If noContent is false, the page contents are actually read from disk.
|
||||||
** If clfFlag is true, it means the page is about to be erased and
|
** If noContent is true, it means that we do not care about the contents
|
||||||
** rewritten without first being read so there is no point it doing
|
** of the page at this time, so do not do a disk read. Just fill in the
|
||||||
** the disk I/O.
|
** 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;
|
PgHdr *pPg;
|
||||||
int rc;
|
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. */
|
/* The requested page is not in the page cache. */
|
||||||
int nMax;
|
int nMax;
|
||||||
int h;
|
int h;
|
||||||
TEST_INCR(pPager->nMiss);
|
PAGER_INCR(pPager->nMiss);
|
||||||
rc = pagerAllocatePage(pPager, &pPg);
|
rc = pagerAllocatePage(pPager, &pPg);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
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
|
/* Populate the page with data, either by reading from the database
|
||||||
** file, or by setting the entire page to zero.
|
** 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);
|
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
|
||||||
|
pPg->needRead = noContent && !pPager->alwaysRollback;
|
||||||
|
IOTRACE(("ZERO %p %d\n", pPager, pgno));
|
||||||
}else{
|
}else{
|
||||||
rc = readDbPage(pPager, pPg, pgno);
|
rc = readDbPage(pPager, pPg, pgno);
|
||||||
if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
|
if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
|
||||||
pPg->pgno = 0;
|
pPg->pgno = 0;
|
||||||
sqlite3PagerUnref(pPg);
|
sqlite3PagerUnref(pPg);
|
||||||
return rc;
|
return rc;
|
||||||
}else{
|
|
||||||
TEST_INCR(pPager->nRead);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3065,7 +3059,7 @@ int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag){
|
||||||
}else{
|
}else{
|
||||||
/* The requested page is in the page cache. */
|
/* The requested page is in the page cache. */
|
||||||
assert(pPager->nRef>0 || pgno==1);
|
assert(pPager->nRef>0 || pgno==1);
|
||||||
TEST_INCR(pPager->nHit);
|
PAGER_INCR(pPager->nHit);
|
||||||
page_ref(pPg);
|
page_ref(pPg);
|
||||||
}
|
}
|
||||||
*ppPage = pPg;
|
*ppPage = pPg;
|
||||||
|
@ -3365,6 +3359,23 @@ static int pager_write(PgHdr *pPg){
|
||||||
|
|
||||||
CHECK_PAGE(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
|
/* Mark the page as dirty. If the page has already been written
|
||||||
** to the journal then we can return right away.
|
** to the journal then we can return right away.
|
||||||
*/
|
*/
|
||||||
|
@ -3425,7 +3436,8 @@ static int pager_write(PgHdr *pPg){
|
||||||
put32bits(pData2, pPg->pgno);
|
put32bits(pData2, pPg->pgno);
|
||||||
rc = sqlite3OsWrite(pPager->jfd, pData2, szPg);
|
rc = sqlite3OsWrite(pPager->jfd, pData2, szPg);
|
||||||
IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
|
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;
|
pPager->journalOff += szPg;
|
||||||
PAGERTRACE4("JOURNAL %d page %d needSync=%d\n",
|
PAGERTRACE4("JOURNAL %d page %d needSync=%d\n",
|
||||||
PAGERID(pPager), pPg->pgno, pPg->needSync);
|
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
|
** 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.
|
** that page might be marked as dirty.
|
||||||
**
|
**
|
||||||
** The overlying software layer calls this routine when all of the data
|
** 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
|
** page contains critical data, we still need to be sure it gets
|
||||||
** rolled back in spite of the sqlite3PagerDontRollback() call.
|
** rolled back in spite of the sqlite3PagerDontRollback() call.
|
||||||
*/
|
*/
|
||||||
void sqlite3PagerDontWrite(Pager *pPager, Pgno pgno){
|
void sqlite3PagerDontWrite(DbPage *pDbPage){
|
||||||
PgHdr *pPg;
|
PgHdr *pPg = pDbPage;
|
||||||
|
Pager *pPager = pPg->pPager;
|
||||||
|
|
||||||
if( MEMDB ) return;
|
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;
|
pPg->alwaysRollback = 1;
|
||||||
if( pPg->dirty && !pPager->stmtInUse ){
|
if( pPg->dirty && !pPager->stmtInUse ){
|
||||||
assert( pPager->state>=PAGER_SHARED );
|
assert( pPager->state>=PAGER_SHARED );
|
||||||
|
@ -3650,8 +3660,8 @@ void sqlite3PagerDontWrite(Pager *pPager, Pgno pgno){
|
||||||
** corruption during the next transaction.
|
** corruption during the next transaction.
|
||||||
*/
|
*/
|
||||||
}else{
|
}else{
|
||||||
PAGERTRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager));
|
PAGERTRACE3("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager));
|
||||||
IOTRACE(("CLEAN %p %d\n", pPager, pgno))
|
IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
|
||||||
makeClean(pPg);
|
makeClean(pPg);
|
||||||
#ifdef SQLITE_CHECK_PAGES
|
#ifdef SQLITE_CHECK_PAGES
|
||||||
pPg->pageHash = pager_pagehash(pPg);
|
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
|
** 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
|
** means that the pager does not have to record the given page in the
|
||||||
** rollback journal.
|
** 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){
|
void sqlite3PagerDontRollback(DbPage *pPg){
|
||||||
Pager *pPager = pPg->pPager;
|
Pager *pPager = pPg->pPager;
|
||||||
|
@ -3676,6 +3691,7 @@ void sqlite3PagerDontRollback(DbPage *pPg){
|
||||||
assert( pPager->aInJournal!=0 );
|
assert( pPager->aInJournal!=0 );
|
||||||
pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
|
pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
|
||||||
pPg->inJournal = 1;
|
pPg->inJournal = 1;
|
||||||
|
pPg->needRead = 0;
|
||||||
if( pPager->stmtInUse ){
|
if( pPager->stmtInUse ){
|
||||||
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
|
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. */
|
/* Increment the value just read and write it back to byte 24. */
|
||||||
change_counter++;
|
change_counter++;
|
||||||
put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
|
put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
|
||||||
pPager->iChangeCount = change_counter;
|
|
||||||
|
|
||||||
/* Release the page reference. */
|
/* Release the page reference. */
|
||||||
sqlite3PagerUnref(pPgHdr);
|
sqlite3PagerUnref(pPgHdr);
|
||||||
|
|
|
@ -109,7 +109,7 @@ int sqlite3PagerStmtBegin(Pager*);
|
||||||
int sqlite3PagerStmtCommit(Pager*);
|
int sqlite3PagerStmtCommit(Pager*);
|
||||||
int sqlite3PagerStmtRollback(Pager*);
|
int sqlite3PagerStmtRollback(Pager*);
|
||||||
void sqlite3PagerDontRollback(DbPage*);
|
void sqlite3PagerDontRollback(DbPage*);
|
||||||
void sqlite3PagerDontWrite(Pager*, Pgno);
|
void sqlite3PagerDontWrite(DbPage*);
|
||||||
int sqlite3PagerRefcount(Pager*);
|
int sqlite3PagerRefcount(Pager*);
|
||||||
int *sqlite3PagerStats(Pager*);
|
int *sqlite3PagerStats(Pager*);
|
||||||
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
|
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
|
||||||
|
|
|
@ -551,6 +551,7 @@ static int selectInnerLoop(
|
||||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3);
|
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3);
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||||
|
p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr,(iParm>>16)&0xff);
|
||||||
if( pOrderBy ){
|
if( pOrderBy ){
|
||||||
/* At first glance you would think we could optimize out the
|
/* At first glance you would think we could optimize out the
|
||||||
** ORDER BY in this case since the order of entries in the set
|
** 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 */
|
** case the order does matter */
|
||||||
pushOntoSorter(pParse, pOrderBy, p);
|
pushOntoSorter(pParse, pOrderBy, p);
|
||||||
}else{
|
}else{
|
||||||
char affinity = (iParm>>16)&0xFF;
|
sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1);
|
||||||
affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, affinity);
|
|
||||||
sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1);
|
|
||||||
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
|
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
|
||||||
}
|
}
|
||||||
sqlite3VdbeJumpHere(v, addr2);
|
sqlite3VdbeJumpHere(v, addr2);
|
||||||
|
@ -721,7 +720,7 @@ static void generateSortTail(
|
||||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
|
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);
|
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1096,7 +1095,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
||||||
sqlite3Dequote(zName);
|
sqlite3Dequote(zName);
|
||||||
if( sqlite3MallocFailed() ){
|
if( sqlite3MallocFailed() ){
|
||||||
sqliteFree(zName);
|
sqliteFree(zName);
|
||||||
sqlite3DeleteTable(0, pTab);
|
sqlite3DeleteTable(pTab);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1400,8 +1399,11 @@ static int matchOrderbyToColumn(
|
||||||
}
|
}
|
||||||
pEList = pSelect->pEList;
|
pEList = pSelect->pEList;
|
||||||
for(i=0; i<pOrderBy->nExpr; i++){
|
for(i=0; i<pOrderBy->nExpr; i++){
|
||||||
|
struct ExprList_item *pItem;
|
||||||
Expr *pE = pOrderBy->a[i].pExpr;
|
Expr *pE = pOrderBy->a[i].pExpr;
|
||||||
int iCol = -1;
|
int iCol = -1;
|
||||||
|
char *zLabel;
|
||||||
|
|
||||||
if( pOrderBy->a[i].done ) continue;
|
if( pOrderBy->a[i].done ) continue;
|
||||||
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||||
if( iCol<=0 || iCol>pEList->nExpr ){
|
if( iCol<=0 || iCol>pEList->nExpr ){
|
||||||
|
@ -1414,20 +1416,23 @@ static int matchOrderbyToColumn(
|
||||||
if( !mustComplete ) continue;
|
if( !mustComplete ) continue;
|
||||||
iCol--;
|
iCol--;
|
||||||
}
|
}
|
||||||
for(j=0; iCol<0 && j<pEList->nExpr; j++){
|
if( iCol<0 && (zLabel = sqlite3NameFromToken(&pE->token))!=0 ){
|
||||||
if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){
|
for(j=0, pItem=pEList->a; j<pEList->nExpr; j++, pItem++){
|
||||||
char *zName, *zLabel;
|
char *zName;
|
||||||
zName = pEList->a[j].zName;
|
int isMatch;
|
||||||
zLabel = sqlite3NameFromToken(&pE->token);
|
if( pItem->zName ){
|
||||||
assert( zLabel!=0 );
|
zName = sqlite3StrDup(pItem->zName);
|
||||||
if( sqlite3StrICmp(zName, zLabel)==0 ){
|
}else{
|
||||||
iCol = j;
|
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 ){
|
if( iCol>=0 ){
|
||||||
pE->op = TK_COLUMN;
|
pE->op = TK_COLUMN;
|
||||||
|
@ -1435,8 +1440,7 @@ static int matchOrderbyToColumn(
|
||||||
pE->iTable = iTable;
|
pE->iTable = iTable;
|
||||||
pE->iAgg = -1;
|
pE->iAgg = -1;
|
||||||
pOrderBy->a[i].done = 1;
|
pOrderBy->a[i].done = 1;
|
||||||
}
|
}else if( mustComplete ){
|
||||||
if( iCol<0 && mustComplete ){
|
|
||||||
sqlite3ErrorMsg(pParse,
|
sqlite3ErrorMsg(pParse,
|
||||||
"ORDER BY term number %d does not match any result column", i+1);
|
"ORDER BY term number %d does not match any result column", i+1);
|
||||||
nErr++;
|
nErr++;
|
||||||
|
@ -2212,7 +2216,7 @@ static int flattenSubquery(
|
||||||
int nSubSrc = pSubSrc->nSrc;
|
int nSubSrc = pSubSrc->nSrc;
|
||||||
int jointype = pSubitem->jointype;
|
int jointype = pSubitem->jointype;
|
||||||
|
|
||||||
sqlite3DeleteTable(0, pSubitem->pTab);
|
sqlite3DeleteTable(pSubitem->pTab);
|
||||||
sqliteFree(pSubitem->zDatabase);
|
sqliteFree(pSubitem->zDatabase);
|
||||||
sqliteFree(pSubitem->zName);
|
sqliteFree(pSubitem->zName);
|
||||||
sqliteFree(pSubitem->zAlias);
|
sqliteFree(pSubitem->zAlias);
|
||||||
|
@ -2590,12 +2594,15 @@ int sqlite3SelectResolve(
|
||||||
*/
|
*/
|
||||||
sNC.pEList = p->pEList;
|
sNC.pEList = p->pEList;
|
||||||
if( sqlite3ExprResolveNames(&sNC, p->pWhere) ||
|
if( sqlite3ExprResolveNames(&sNC, p->pWhere) ||
|
||||||
sqlite3ExprResolveNames(&sNC, p->pHaving) ||
|
sqlite3ExprResolveNames(&sNC, p->pHaving) ){
|
||||||
processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") ||
|
|
||||||
processOrderGroupBy(&sNC, pGroupBy, "GROUP")
|
|
||||||
){
|
|
||||||
return SQLITE_ERROR;
|
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.
|
/* Make sure the GROUP BY clause does not contain aggregate functions.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -381,6 +381,14 @@ struct Db {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An instance of the following structure stores a database schema.
|
** 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 {
|
struct Schema {
|
||||||
int schema_cookie; /* Database schema version number for this file */
|
int schema_cookie; /* Database schema version number for this file */
|
||||||
|
@ -393,6 +401,9 @@ struct Schema {
|
||||||
u8 enc; /* Text encoding used by this database */
|
u8 enc; /* Text encoding used by this database */
|
||||||
u16 flags; /* Flags associated with this schema */
|
u16 flags; /* Flags associated with this schema */
|
||||||
int cache_size; /* Number of pages to use in the cache */
|
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 isAgg; /* True if this is an aggregate query */
|
||||||
u8 usesEphm; /* True if uses an OpenEphemeral opcode */
|
u8 usesEphm; /* True if uses an OpenEphemeral opcode */
|
||||||
u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */
|
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 */
|
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 */
|
||||||
|
@ -1631,7 +1643,7 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
void sqlite3DeleteTable(Table*);
|
||||||
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
||||||
void *sqlite3ArrayAllocate(void*,int,int,int*,int*,int*);
|
void *sqlite3ArrayAllocate(void*,int,int,int*,int*,int*);
|
||||||
IdList *sqlite3IdListAppend(IdList*, Token*);
|
IdList *sqlite3IdListAppend(IdList*, Token*);
|
||||||
|
@ -1889,7 +1901,7 @@ int sqlite3OpenTempDatabase(Parse *);
|
||||||
int sqlite3VtabCommit(sqlite3 *db);
|
int sqlite3VtabCommit(sqlite3 *db);
|
||||||
#endif
|
#endif
|
||||||
void sqlite3VtabLock(sqlite3_vtab*);
|
void sqlite3VtabLock(sqlite3_vtab*);
|
||||||
void sqlite3VtabUnlock(sqlite3_vtab*);
|
void sqlite3VtabUnlock(sqlite3*, sqlite3_vtab*);
|
||||||
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
|
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
|
||||||
void sqlite3VtabFinishParse(Parse*, Token*);
|
void sqlite3VtabFinishParse(Parse*, Token*);
|
||||||
void sqlite3VtabArgInit(Parse*);
|
void sqlite3VtabArgInit(Parse*);
|
||||||
|
|
|
@ -197,6 +197,57 @@ static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
|
||||||
return 0;
|
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
|
** 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_stack_used", (Tcl_CmdProc*)test_stack_used },
|
||||||
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
|
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
|
||||||
{ "printf", (Tcl_CmdProc*)test_printf },
|
{ "printf", (Tcl_CmdProc*)test_printf },
|
||||||
|
{ "sqlite3_io_trace", (Tcl_CmdProc*)test_io_trace },
|
||||||
};
|
};
|
||||||
static struct {
|
static struct {
|
||||||
char *zName;
|
char *zName;
|
||||||
|
@ -4338,6 +4390,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||||
extern int sqlite3_like_count;
|
extern int sqlite3_like_count;
|
||||||
extern int sqlite3_tsd_count;
|
extern int sqlite3_tsd_count;
|
||||||
extern int sqlite3_xferopt_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
|
#if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE
|
||||||
extern int threadsOverrideEachOthersLocks;
|
extern int threadsOverrideEachOthersLocks;
|
||||||
#endif
|
#endif
|
||||||
|
@ -4377,6 +4433,14 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||||
(char*)&sqlite3_tsd_count, TCL_LINK_INT);
|
(char*)&sqlite3_tsd_count, TCL_LINK_INT);
|
||||||
Tcl_LinkVar(interp, "sqlite3_xferopt_count",
|
Tcl_LinkVar(interp, "sqlite3_xferopt_count",
|
||||||
(char*)&sqlite3_xferopt_count, TCL_LINK_INT);
|
(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
|
#ifndef SQLITE_OMIT_UTF16
|
||||||
Tcl_LinkVar(interp, "unaligned_string_counter",
|
Tcl_LinkVar(interp, "unaligned_string_counter",
|
||||||
(char*)&unaligned_string_counter, TCL_LINK_INT);
|
(char*)&unaligned_string_counter, TCL_LINK_INT);
|
||||||
|
|
|
@ -495,7 +495,7 @@ abort_parse:
|
||||||
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
|
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
|
||||||
** will take responsibility for freeing the Table structure.
|
** will take responsibility for freeing the Table structure.
|
||||||
*/
|
*/
|
||||||
sqlite3DeleteTable(pParse->db, pParse->pNewTable);
|
sqlite3DeleteTable(pParse->pNewTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3DeleteTrigger(pParse->pNewTrigger);
|
sqlite3DeleteTrigger(pParse->pNewTrigger);
|
||||||
|
|
|
@ -2521,7 +2521,23 @@ case OP_VerifyCookie: { /* no-push */
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
|
if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
|
||||||
sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0);
|
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);
|
sqlite3ExpirePreparedStatements(db);
|
||||||
rc = SQLITE_SCHEMA;
|
rc = SQLITE_SCHEMA;
|
||||||
}
|
}
|
||||||
|
@ -4881,7 +4897,7 @@ case OP_VUpdate: { /* no-push */
|
||||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
sqlite3VtabLock(pVtab);
|
sqlite3VtabLock(pVtab);
|
||||||
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
||||||
sqlite3VtabUnlock(pVtab);
|
sqlite3VtabUnlock(db, pVtab);
|
||||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||||
if( pOp->p1 && rc==SQLITE_OK ){
|
if( pOp->p1 && rc==SQLITE_OK ){
|
||||||
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
||||||
|
|
|
@ -145,7 +145,6 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
||||||
VdbeOp *pOp;
|
VdbeOp *pOp;
|
||||||
|
|
||||||
i = p->nOp;
|
i = p->nOp;
|
||||||
p->nOp++;
|
|
||||||
assert( p->magic==VDBE_MAGIC_INIT );
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p->nOpAlloc<=i ){
|
if( p->nOpAlloc<=i ){
|
||||||
resizeOpArray(p, i+1);
|
resizeOpArray(p, i+1);
|
||||||
|
@ -153,6 +152,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p->nOp++;
|
||||||
pOp = &p->aOp[i];
|
pOp = &p->aOp[i];
|
||||||
pOp->opcode = op;
|
pOp->opcode = op;
|
||||||
pOp->p1 = p1;
|
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, ...){
|
void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
|
||||||
va_list ap;
|
va_list ap;
|
||||||
assert( p->nOp>0 );
|
assert( p->nOp>0 || p->aOp==0 );
|
||||||
assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0
|
assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 || sqlite3MallocFailed() );
|
||||||
|| sqlite3MallocFailed() );
|
|
||||||
va_start(ap, zFormat);
|
va_start(ap, zFormat);
|
||||||
sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
|
sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
@ -571,8 +570,8 @@ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
|
||||||
*/
|
*/
|
||||||
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
||||||
assert( p->magic==VDBE_MAGIC_INIT );
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
assert( addr>=0 && addr<p->nOp );
|
assert( (addr>=0 && addr<p->nOp) || sqlite3MallocFailed() );
|
||||||
return &p->aOp[addr];
|
return ((addr>=0 && addr<p->nOp)?(&p->aOp[addr]):0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|
||||||
|
|
|
@ -56,10 +56,18 @@ void sqlite3VtabLock(sqlite3_vtab *pVtab){
|
||||||
** Unlock a virtual table. When the last lock is removed,
|
** Unlock a virtual table. When the last lock is removed,
|
||||||
** disconnect the virtual table.
|
** disconnect the virtual table.
|
||||||
*/
|
*/
|
||||||
void sqlite3VtabUnlock(sqlite3_vtab *pVtab){
|
void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
|
||||||
pVtab->nRef--;
|
pVtab->nRef--;
|
||||||
|
assert(db);
|
||||||
|
assert(!sqlite3SafetyCheck(db));
|
||||||
if( pVtab->nRef==0 ){
|
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;
|
sqlite3_vtab *pVtab = p->pVtab;
|
||||||
if( pVtab ){
|
if( pVtab ){
|
||||||
assert( p->pMod && p->pMod->pModule );
|
assert( p->pMod && p->pMod->pModule );
|
||||||
sqlite3VtabUnlock(pVtab);
|
sqlite3VtabUnlock(p->pSchema->db, pVtab);
|
||||||
p->pVtab = 0;
|
p->pVtab = 0;
|
||||||
}
|
}
|
||||||
if( p->azModuleArg ){
|
if( p->azModuleArg ){
|
||||||
|
@ -124,6 +132,11 @@ void sqlite3VtabBeginParse(
|
||||||
int iDb; /* The database the table is being created in */
|
int iDb; /* The database the table is being created in */
|
||||||
Table *pTable; /* The new virtual table */
|
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);
|
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
|
||||||
pTable = pParse->pNewTable;
|
pTable = pParse->pNewTable;
|
||||||
if( pTable==0 || pParse->nErr ) return;
|
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() */
|
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
pSchema->db = pParse->db;
|
||||||
pParse->pNewTable = 0;
|
pParse->pNewTable = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,6 +311,10 @@ static int vtabCallConstructor(
|
||||||
char *zErr = 0;
|
char *zErr = 0;
|
||||||
char *zModuleName = sqlite3MPrintf("%s", pTab->zName);
|
char *zModuleName = sqlite3MPrintf("%s", pTab->zName);
|
||||||
|
|
||||||
|
if( !zModuleName ){
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
assert( !db->pVTab );
|
assert( !db->pVTab );
|
||||||
assert( xConstruct );
|
assert( xConstruct );
|
||||||
|
|
||||||
|
@ -457,6 +475,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||||
pTab->nCol = sParse.pNewTable->nCol;
|
pTab->nCol = sParse.pNewTable->nCol;
|
||||||
sParse.pNewTable->nCol = 0;
|
sParse.pNewTable->nCol = 0;
|
||||||
sParse.pNewTable->aCol = 0;
|
sParse.pNewTable->aCol = 0;
|
||||||
|
db->pVTab = 0;
|
||||||
} else {
|
} else {
|
||||||
sqlite3Error(db, SQLITE_ERROR, zErr);
|
sqlite3Error(db, SQLITE_ERROR, zErr);
|
||||||
sqliteFree(zErr);
|
sqliteFree(zErr);
|
||||||
|
@ -465,12 +484,11 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||||
sParse.declareVtab = 0;
|
sParse.declareVtab = 0;
|
||||||
|
|
||||||
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
|
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
|
||||||
sqlite3DeleteTable(0, sParse.pNewTable);
|
sqlite3DeleteTable(sParse.pNewTable);
|
||||||
sParse.pNewTable = 0;
|
sParse.pNewTable = 0;
|
||||||
db->pVTab = 0;
|
|
||||||
|
|
||||||
assert( (rc&0xff)==rc );
|
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 *);
|
int (*x)(sqlite3_vtab *);
|
||||||
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
|
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
|
||||||
if( x ) x(pVtab);
|
if( x ) x(pVtab);
|
||||||
sqlite3VtabUnlock(pVtab);
|
sqlite3VtabUnlock(db, pVtab);
|
||||||
}
|
}
|
||||||
sqliteFree(db->aVTrans);
|
sqliteFree(db->aVTrans);
|
||||||
db->nVTrans = 0;
|
db->nVTrans = 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue