1
0
Fork 0
mirror of https://github.com/DBD-SQLite/DBD-SQLite synced 2025-06-07 14:19:10 -04:00

DBD-SQLite: bumped up the bundled library to 3.6.12

This commit is contained in:
Kenichi Ishigaki 2009-03-31 15:31:13 +00:00
parent 735d55875f
commit ebc9d17ee9
54 changed files with 6121 additions and 5266 deletions

View file

@ -12,7 +12,7 @@
** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command.
**
** $Id: alter.c,v 1.53 2009/02/13 03:43:32 drh Exp $
** $Id: alter.c,v 1.55 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
@ -193,7 +193,7 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
*/
if( pTab->pSchema!=pTempSchema ){
sqlite3 *db = pParse->db;
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){
if( pTrig->pSchema==pTempSchema ){
if( !zWhere ){
zWhere = sqlite3MPrintf(db, "name=%Q", pTrig->name);
@ -232,7 +232,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
#ifndef SQLITE_OMIT_TRIGGER
/* Drop any table triggers from the internal schema. */
for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){
int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
assert( iTrigDb==iDb || iTrigDb==1 );
sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->name, 0);
@ -593,7 +593,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew;
pNew->nRef = 1;
pNew->db = db;
pNew->dbMem = pTab->dbMem;
pNew->nCol = pTab->nCol;
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;

View file

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code associated with the ANALYZE command.
**
** @(#) $Id: analyze.c,v 1.48 2009/02/13 16:59:53 drh Exp $
** @(#) $Id: analyze.c,v 1.51 2009/02/28 10:47:42 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_ANALYZE
#include "sqliteInt.h"
@ -74,8 +74,8 @@ static void openStatTable(
if( !createStat1 ){
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
}
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 3);
sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur, iRootPage, iDb);
sqlite3VdbeChangeP4(v, -1, (char *)3, P4_INT32);
sqlite3VdbeChangeP5(v, createStat1);
}
@ -117,7 +117,7 @@ static void analyzeOneTable(
/* Establish a read-lock on the table at the shared-cache level. */
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
iIdxCur = pParse->nTab;
iIdxCur = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
int regFields; /* Register block for building records */
@ -131,7 +131,6 @@ static void analyzeOneTable(
*/
assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) );
nCol = pIdx->nColumn;
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nCol+1);
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb,
(char *)pKey, P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
@ -189,7 +188,7 @@ static void analyzeOneTable(
** The result is a single row of the sqlite_stat1 table. The first
** two columns are the names of the table and index. The third column
** is a string composed of a list of integer statistics about the
** index. The first integer in the list is the total number of entires
** index. The first integer in the list is the total number of entries
** in the index. There is one additional integer in the list for each
** column of the table. This additional integer is a guess of how many
** rows of the table the index will select. If D is the count of distinct

View file

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.82 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: attach.c,v 1.83 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -488,11 +488,11 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
return 1;
}
if( sqlite3FixExprList(pFix, pExpr->pList) ){
return 1;
if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanOnly) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
}else{
if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
}
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
return 1;

View file

@ -12,7 +12,7 @@
** This file contains the implementation of the sqlite3_backup_XXX()
** API functions and the related features.
**
** $Id: backup.c,v 1.12 2009/02/16 17:55:47 shane Exp $
** $Id: backup.c,v 1.13 2009/03/16 13:19:36 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "btreeInt.h"
@ -292,10 +292,10 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int bCloseTrans = 0; /* True if src db requires unlocking */
/* If the source pager is currently in a write-transaction, return
** SQLITE_LOCKED immediately.
** SQLITE_BUSY immediately.
*/
if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){
rc = SQLITE_LOCKED;
rc = SQLITE_BUSY;
}else{
rc = SQLITE_OK;
}

View file

@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: btmutex.c,v 1.12 2008/11/17 19:18:55 danielk1977 Exp $
** $Id: btmutex.c,v 1.13 2009/03/05 04:20:32 shane Exp $
**
** This file contains code used to implement mutexes on Btree objects.
** This code really belongs in btree.c. But btree.c is getting too
@ -113,7 +113,7 @@ void sqlite3BtreeLeave(Btree *p){
/*
** Return true if the BtShared mutex is held on the btree.
**
** This routine makes no determination one why or another if the
** This routine makes no determination one way or another if the
** database connection mutex is held.
**
** This routine is used only from within assert() statements.

470
btree.c
View file

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.565 2009/02/04 01:49:30 shane Exp $
** $Id: btree.c,v 1.582 2009/03/30 18:50:05 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
@ -42,6 +42,8 @@ int sqlite3BtreeTrace=0; /* True to enable tracing */
** in shared cache. This variable has file scope during normal builds,
** but the test harness needs to access it so we make it global for
** test builds.
**
** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER.
*/
#ifdef SQLITE_TEST
BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
@ -68,31 +70,32 @@ int sqlite3_enable_shared_cache(int enable){
/*
** Forward declaration
*/
static int checkReadLocks(Btree*, Pgno, BtCursor*, i64);
static int checkForReadConflicts(Btree*, Pgno, BtCursor*, i64);
#ifdef SQLITE_OMIT_SHARED_CACHE
/*
** The functions queryTableLock(), lockTable() and unlockAllTables()
** The functions querySharedCacheTableLock(), setSharedCacheTableLock(),
** and clearAllSharedCacheTableLocks()
** manipulate entries in the BtShared.pLock linked list used to store
** shared-cache table level locks. If the library is compiled with the
** shared-cache feature disabled, then there is only ever one user
** of each BtShared structure and so this locking is not necessary.
** So define the lock related functions as no-ops.
*/
#define queryTableLock(a,b,c) SQLITE_OK
#define lockTable(a,b,c) SQLITE_OK
#define unlockAllTables(a)
#define querySharedCacheTableLock(a,b,c) SQLITE_OK
#define setSharedCacheTableLock(a,b,c) SQLITE_OK
#define clearAllSharedCacheTableLocks(a)
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** Query to see if btree handle p may obtain a lock of type eLock
** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
** SQLITE_OK if the lock may be obtained (by calling lockTable()), or
** SQLITE_LOCKED if not.
** SQLITE_OK if the lock may be obtained (by calling
** setSharedCacheTableLock()), or SQLITE_LOCKED if not.
*/
static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
BtShared *pBt = p->pBt;
BtLock *pIter;
@ -108,23 +111,26 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
/* If some other connection is holding an exclusive lock, the
** requested lock may not be obtained.
*/
if( pBt->pExclusive && pBt->pExclusive!=p ){
return SQLITE_LOCKED;
if( pBt->pWriter!=p && pBt->isExclusive ){
sqlite3ConnectionBlocked(p->db, pBt->pWriter->db);
return SQLITE_LOCKED_SHAREDCACHE;
}
/* This (along with lockTable()) is where the ReadUncommitted flag is
** dealt with. If the caller is querying for a read-lock and the flag is
** set, it is unconditionally granted - even if there are write-locks
/* This (along with setSharedCacheTableLock()) is where
** the ReadUncommitted flag is dealt with.
** If the caller is querying for a read-lock on any table
** other than the sqlite_master table (table 1) and if the ReadUncommitted
** flag is set, then the lock granted even if there are write-locks
** on the table. If a write-lock is requested, the ReadUncommitted flag
** is not considered.
**
** In function lockTable(), if a read-lock is demanded and the
** In function setSharedCacheTableLock(), if a read-lock is demanded and the
** ReadUncommitted flag is set, no entry is added to the locks list
** (BtShared.pLock).
**
** To summarize: If the ReadUncommitted flag is set, then read cursors do
** not create or respect table locks. The locking procedure for a
** write-cursor does not change.
** To summarize: If the ReadUncommitted flag is set, then read cursors
** on non-schema tables do not create or respect table locks. The locking
** procedure for a write-cursor does not change.
*/
if(
0==(p->db->flags&SQLITE_ReadUncommitted) ||
@ -134,7 +140,12 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
if( pIter->pBtree!=p && pIter->iTable==iTab &&
(pIter->eLock!=eLock || eLock!=READ_LOCK) ){
return SQLITE_LOCKED;
sqlite3ConnectionBlocked(p->db, pIter->pBtree->db);
if( eLock==WRITE_LOCK ){
assert( p==pBt->pWriter );
pBt->isPending = 1;
}
return SQLITE_LOCKED_SHAREDCACHE;
}
}
}
@ -151,7 +162,7 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
** SQLITE_OK is returned if the lock is added successfully. SQLITE_BUSY and
** SQLITE_NOMEM may also be returned.
*/
static int lockTable(Btree *p, Pgno iTable, u8 eLock){
static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
BtShared *pBt = p->pBt;
BtLock *pLock = 0;
BtLock *pIter;
@ -165,12 +176,13 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
return SQLITE_OK;
}
assert( SQLITE_OK==queryTableLock(p, iTable, eLock) );
assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) );
/* If the read-uncommitted flag is set and a read-lock is requested,
** return early without adding an entry to the BtShared.pLock list. See
** comment in function queryTableLock() for more info on handling
** the ReadUncommitted flag.
/* If the read-uncommitted flag is set and a read-lock is requested on
** a non-schema table, then the lock is always granted. Return early
** without adding an entry to the BtShared.pLock list. See
** comment in function querySharedCacheTableLock() for more info
** on handling the ReadUncommitted flag.
*/
if(
(p->db->flags&SQLITE_ReadUncommitted) &&
@ -217,10 +229,10 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** Release all the table locks (locks obtained via calls to the lockTable()
** procedure) held by Btree handle p.
** Release all the table locks (locks obtained via calls to
** the setSharedCacheTableLock() procedure) held by Btree handle p.
*/
static void unlockAllTables(Btree *p){
static void clearAllSharedCacheTableLocks(Btree *p){
BtShared *pBt = p->pBt;
BtLock **ppIter = &pBt->pLock;
@ -229,7 +241,7 @@ static void unlockAllTables(Btree *p){
while( *ppIter ){
BtLock *pLock = *ppIter;
assert( pBt->pExclusive==0 || pBt->pExclusive==pLock->pBtree );
assert( pBt->isExclusive==0 || pBt->pWriter==pLock->pBtree );
if( pLock->pBtree==p ){
*ppIter = pLock->pNext;
sqlite3_free(pLock);
@ -238,8 +250,22 @@ static void unlockAllTables(Btree *p){
}
}
if( pBt->pExclusive==p ){
pBt->pExclusive = 0;
assert( pBt->isPending==0 || pBt->pWriter );
if( pBt->pWriter==p ){
pBt->pWriter = 0;
pBt->isExclusive = 0;
pBt->isPending = 0;
}else if( pBt->nTransaction==2 ){
/* This function is called when connection p is concluding its
** transaction. If there currently exists a writer, and p is not
** that writer, then the number of locks held by connections other
** than the writer must be about to drop to zero. In this case
** set the isPending flag to 0.
**
** If there is not currently a writer, then BtShared.isPending must
** be zero already. So this next line is harmless in that case.
*/
pBt->isPending = 0;
}
}
#endif /* SQLITE_OMIT_SHARED_CACHE */
@ -830,7 +856,7 @@ static int defragmentPage(MemPage *pPage){
**
** If the page contains nBytes of free space but does not contain
** nBytes of contiguous free space, then this routine automatically
** calls defragementPage() to consolidate all free space before
** calls defragmentPage() to consolidate all free space before
** allocating the new chunk.
*/
static int allocateSpace(MemPage *pPage, int nByte){
@ -1279,6 +1305,12 @@ static void pageReinit(DbPage *pData){
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pPage->isInit = 0;
if( sqlite3PagerPageRefcount(pData)>0 ){
/* pPage might not be a btree page; it might be an overflow page
** or ptrmap page or a free page. In those cases, the following
** call to sqlite3BtreeInitPage() will likely return SQLITE_CORRUPT.
** But no harm is done by this. And it is very important that
** sqlite3BtreeInitPage() be called on every btree page so we make
** the call for every page that comes in for re-initing. */
sqlite3BtreeInitPage(pPage);
}
}
@ -1310,12 +1342,13 @@ int sqlite3BtreeOpen(
int flags, /* Options */
int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */
){
sqlite3_vfs *pVfs; /* The VFS to use for this btree */
BtShared *pBt = 0; /* Shared part of btree structure */
Btree *p; /* Handle to return */
int rc = SQLITE_OK;
u8 nReserve;
unsigned char zDbHeader[100];
sqlite3_vfs *pVfs; /* The VFS to use for this btree */
BtShared *pBt = 0; /* Shared part of btree structure */
Btree *p; /* Handle to return */
sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */
int rc = SQLITE_OK; /* Result code from this function */
u8 nReserve; /* Byte of unused space on each page */
unsigned char zDbHeader[100]; /* Database header content */
/* Set the variable isMemdb to true for an in-memory database, or
** false for a file-based database. This symbol is only required if
@ -1361,6 +1394,8 @@ int sqlite3BtreeOpen(
return SQLITE_NOMEM;
}
sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname);
mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
sqlite3_mutex_enter(mutexOpen);
mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
sqlite3_mutex_enter(mutexShared);
for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){
@ -1514,6 +1549,10 @@ btree_open_out:
sqlite3_free(p);
*ppBtree = 0;
}
if( mutexOpen ){
assert( sqlite3_mutex_held(mutexOpen) );
sqlite3_mutex_leave(mutexOpen);
}
return rc;
}
@ -1740,6 +1779,12 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){
int sqlite3BtreeGetPageSize(Btree *p){
return p->pBt->pageSize;
}
/*
** Return the number of bytes of space at the end of every page that
** are intentually left unused. This is the "reserved" space that is
** sometimes used by extensions.
*/
int sqlite3BtreeGetReserve(Btree *p){
int n;
sqlite3BtreeEnter(p);
@ -1774,13 +1819,14 @@ int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
#else
BtShared *pBt = p->pBt;
int rc = SQLITE_OK;
u8 av = autoVacuum ?1:0;
u8 av = (u8)autoVacuum;
sqlite3BtreeEnter(p);
if( pBt->pageSizeFixed && av!=pBt->autoVacuum ){
if( pBt->pageSizeFixed && (av ?1:0)!=pBt->autoVacuum ){
rc = SQLITE_READONLY;
}else{
pBt->autoVacuum = av;
pBt->autoVacuum = av ?1:0;
pBt->incrVacuum = av==2 ?1:0;
}
sqlite3BtreeLeave(p);
return rc;
@ -1965,7 +2011,6 @@ static void unlockBtreeIfUnused(BtShared *pBt){
releasePage(pBt->pPage1);
}
pBt->pPage1 = 0;
pBt->inStmt = 0;
}
}
@ -2047,6 +2092,7 @@ static int newDatabase(BtShared *pBt){
** proceed.
*/
int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
sqlite3 *pBlock = 0;
BtShared *pBt = p->pBt;
int rc = SQLITE_OK;
@ -2068,25 +2114,27 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
goto trans_begun;
}
#ifndef SQLITE_OMIT_SHARED_CACHE
/* If another database handle has already opened a write transaction
** on this shared-btree structure and a second write transaction is
** requested, return SQLITE_BUSY.
** requested, return SQLITE_LOCKED.
*/
if( pBt->inTransaction==TRANS_WRITE && wrflag ){
rc = SQLITE_BUSY;
goto trans_begun;
}
#ifndef SQLITE_OMIT_SHARED_CACHE
if( wrflag>1 ){
if( (wrflag && pBt->inTransaction==TRANS_WRITE) || pBt->isPending ){
pBlock = pBt->pWriter->db;
}else if( wrflag>1 ){
BtLock *pIter;
for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
if( pIter->pBtree!=p ){
rc = SQLITE_BUSY;
goto trans_begun;
pBlock = pIter->pBtree->db;
break;
}
}
}
if( pBlock ){
sqlite3ConnectionBlocked(p->db, pBlock);
rc = SQLITE_LOCKED_SHAREDCACHE;
goto trans_begun;
}
#endif
do {
@ -2107,9 +2155,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
}
if( rc==SQLITE_OK ){
if( wrflag ) pBt->inStmt = 0;
}else{
if( rc!=SQLITE_OK ){
unlockBtreeIfUnused(pBt);
}
}while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
@ -2124,9 +2170,10 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
pBt->inTransaction = p->inTrans;
}
#ifndef SQLITE_OMIT_SHARED_CACHE
if( wrflag>1 ){
assert( !pBt->pExclusive );
pBt->pExclusive = p;
if( wrflag ){
assert( !pBt->pWriter );
pBt->pWriter = p;
pBt->isExclusive = (u8)(wrflag>1);
}
#endif
}
@ -2433,6 +2480,18 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
if( nFin==0 ){
iLastPg--;
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
MemPage *pPg;
int rc = sqlite3BtreeGetPage(pBt, iLastPg, &pPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
if( rc!=SQLITE_OK ){
return rc;
}
}
iLastPg--;
}
sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
@ -2445,7 +2504,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
** It performs a single unit of work towards an incremental vacuum.
**
** If the incremental vacuum is finished after this function has run,
** SQLITE_DONE is returned. If it is not finished, but no error occured,
** SQLITE_DONE is returned. If it is not finished, but no error occurred,
** SQLITE_OK is returned. Otherwise an SQLite error code.
*/
int sqlite3BtreeIncrVacuum(Btree *p){
@ -2608,9 +2667,8 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){
return rc;
}
pBt->inTransaction = TRANS_READ;
pBt->inStmt = 0;
}
unlockAllTables(p);
clearAllSharedCacheTableLocks(p);
/* If the handle has any kind of transaction open, decrement the transaction
** count of the shared btree. If the transaction count reaches 0, set
@ -2723,7 +2781,7 @@ int sqlite3BtreeRollback(Btree *p){
rc = saveAllCursors(pBt, 0, 0);
#ifndef SQLITE_OMIT_SHARED_CACHE
if( rc!=SQLITE_OK ){
/* This is a horrible situation. An IO or malloc() error occured whilst
/* This is a horrible situation. An IO or malloc() error occurred whilst
** trying to save cursor positions. If this is an automatic rollback (as
** the result of a constraint, malloc() failure or IO error) then
** the cache may be internally inconsistent (not contain valid trees) so
@ -2734,7 +2792,7 @@ int sqlite3BtreeRollback(Btree *p){
}
#endif
btreeIntegrity(p);
unlockAllTables(p);
clearAllSharedCacheTableLocks(p);
if( p->inTrans==TRANS_WRITE ){
int rc2;
@ -2765,7 +2823,6 @@ int sqlite3BtreeRollback(Btree *p){
btreeClearHasContent(pBt);
p->inTrans = TRANS_NONE;
pBt->inStmt = 0;
unlockBtreeIfUnused(pBt);
btreeIntegrity(p);
@ -2774,29 +2831,33 @@ int sqlite3BtreeRollback(Btree *p){
}
/*
** Start a statement subtransaction. The subtransaction can
** can be rolled back independently of the main transaction.
** You must start a transaction before starting a subtransaction.
** The subtransaction is ended automatically if the main transaction
** commits or rolls back.
**
** Only one subtransaction may be active at a time. It is an error to try
** to start a new subtransaction if another subtransaction is already active.
** Start a statement subtransaction. The subtransaction can can be rolled
** back independently of the main transaction. You must start a transaction
** before starting a subtransaction. The subtransaction is ended automatically
** if the main transaction commits or rolls back.
**
** Statement subtransactions are used around individual SQL statements
** that are contained within a BEGIN...COMMIT block. If a constraint
** error occurs within the statement, the effect of that one statement
** can be rolled back without having to rollback the entire transaction.
**
** A statement sub-transaction is implemented as an anonymous savepoint. The
** value passed as the second parameter is the total number of savepoints,
** including the new anonymous savepoint, open on the B-Tree. i.e. if there
** are no active savepoints and no other statement-transactions open,
** iStatement is 1. This anonymous savepoint can be released or rolled back
** using the sqlite3BtreeSavepoint() function.
*/
int sqlite3BtreeBeginStmt(Btree *p){
int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
int rc;
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
pBt->db = p->db;
assert( p->inTrans==TRANS_WRITE );
assert( !pBt->inStmt );
assert( pBt->readOnly==0 );
if( NEVER(p->inTrans!=TRANS_WRITE || pBt->inStmt || pBt->readOnly) ){
assert( iStatement>0 );
assert( iStatement>p->db->nSavepoint );
if( NEVER(p->inTrans!=TRANS_WRITE || pBt->readOnly) ){
rc = SQLITE_INTERNAL;
}else{
assert( pBt->inTransaction==TRANS_WRITE );
@ -2805,55 +2866,7 @@ int sqlite3BtreeBeginStmt(Btree *p){
** SQL statements. It is illegal to open, release or rollback any
** such savepoints while the statement transaction savepoint is active.
*/
rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint+1);
pBt->inStmt = 1;
}
sqlite3BtreeLeave(p);
return rc;
}
/*
** Commit the statment subtransaction currently in progress. If no
** subtransaction is active, this is a no-op.
*/
int sqlite3BtreeCommitStmt(Btree *p){
int rc;
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
pBt->db = p->db;
assert( pBt->readOnly==0 );
if( pBt->inStmt ){
int iStmtpoint = p->db->nSavepoint;
rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint);
}else{
rc = SQLITE_OK;
}
pBt->inStmt = 0;
sqlite3BtreeLeave(p);
return rc;
}
/*
** Rollback the active statement subtransaction. If no subtransaction
** is active this routine is a no-op.
**
** All cursors will be invalidated by this operation. Any attempt
** to use a cursor that was open at the beginning of this operation
** will result in an error.
*/
int sqlite3BtreeRollbackStmt(Btree *p){
int rc = SQLITE_OK;
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
pBt->db = p->db;
assert( pBt->readOnly==0 );
if( pBt->inStmt ){
int iStmtpoint = p->db->nSavepoint;
rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_ROLLBACK, iStmtpoint);
if( rc==SQLITE_OK ){
rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint);
}
pBt->inStmt = 0;
rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
}
sqlite3BtreeLeave(p);
return rc;
@ -2875,7 +2888,6 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
int rc = SQLITE_OK;
if( p && p->inTrans==TRANS_WRITE ){
BtShared *pBt = p->pBt;
assert( pBt->inStmt==0 );
assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) );
sqlite3BtreeEnter(p);
@ -2937,8 +2949,10 @@ static int btreeCursor(
if( NEVER(pBt->readOnly) ){
return SQLITE_READONLY;
}
if( checkReadLocks(p, iTable, 0, 0) ){
return SQLITE_LOCKED;
rc = checkForReadConflicts(p, iTable, 0, 0);
if( rc!=SQLITE_OK ){
assert( rc==SQLITE_LOCKED_SHAREDCACHE );
return rc;
}
}
@ -2976,6 +2990,7 @@ static int btreeCursor(
}
pBt->pCursor = pCur;
pCur->eState = CURSOR_INVALID;
pCur->cachedRowid = 0;
return SQLITE_OK;
@ -2998,11 +3013,48 @@ int sqlite3BtreeCursor(
sqlite3BtreeLeave(p);
return rc;
}
int sqlite3BtreeCursorSize(){
/*
** Return the size of a BtCursor object in bytes.
**
** This interfaces is needed so that users of cursors can preallocate
** sufficient storage to hold a cursor. The BtCursor object is opaque
** to users so they cannot do the sizeof() themselves - they must call
** this routine.
*/
int sqlite3BtreeCursorSize(void){
return sizeof(BtCursor);
}
/*
** Set the cached rowid value of every cursor in the same database file
** as pCur and having the same root page number as pCur. The value is
** set to iRowid.
**
** Only positive rowid values are considered valid for this cache.
** The cache is initialized to zero, indicating an invalid cache.
** A btree will work fine with zero or negative rowids. We just cannot
** cache zero or negative rowids, which means tables that use zero or
** negative rowids might run a little slower. But in practice, zero
** or negative rowids are very uncommon so this should not be a problem.
*/
void sqlite3BtreeSetCachedRowid(BtCursor *pCur, sqlite3_int64 iRowid){
BtCursor *p;
for(p=pCur->pBt->pCursor; p; p=p->pNext){
if( p->pgnoRoot==pCur->pgnoRoot ) p->cachedRowid = iRowid;
}
assert( pCur->cachedRowid==iRowid );
}
/*
** Return the cached rowid for the given cursor. A negative or zero
** return value indicates that the rowid cache is invalid and should be
** ignored. If the rowid cache has never before been set, then a
** zero is returned.
*/
sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor *pCur){
return pCur->cachedRowid;
}
/*
** Close a cursor. The read lock on the database file is released
@ -3064,6 +3116,8 @@ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){
sqlite3_free(pCur->pKey);
}
/*
** Make sure the BtCursor* given in the argument has a valid
** BtCursor.info structure. If it is not already valid, call
@ -3501,7 +3555,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
** and data to fit on the local page and for there to be no overflow
** pages. When that is so, this routine can be used to access the
** key and data without making a copy. If the key and/or data spills
** onto overflow pages, then accessPayload() must be used to reassembly
** onto overflow pages, then accessPayload() must be used to reassemble
** the key/data and copy it into a preallocated buffer.
**
** The pointer returned by this routine looks directly into the cached
@ -4391,8 +4445,15 @@ static int allocateBtreePage(
** at the end of the file instead of one. The first allocated page
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno));
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
rc = sqlite3BtreeGetPage(pBt, *pPgno, &pPg, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
}
if( rc ) return rc;
(*pPgno)++;
if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ (*pPgno)++; }
}
@ -5913,9 +5974,9 @@ static int balance(BtCursor *pCur, int isInsert){
** is not in the ReadUncommmitted state, then this routine returns
** SQLITE_LOCKED.
**
** As well as cursors with wrFlag==0, cursors with wrFlag==1 and
** isIncrblobHandle==1 are also considered 'read' cursors. Incremental
** blob cursors are used for both reading and writing.
** As well as cursors with wrFlag==0, cursors with
** isIncrblobHandle==1 are also considered 'read' cursors because
** incremental blob cursors are used for both reading and writing.
**
** When pgnoRoot is the root page of an intkey table, this function is also
** responsible for invalidating incremental blob cursors when the table row
@ -5937,11 +5998,11 @@ static int balance(BtCursor *pCur, int isInsert){
** 3) If both pExclude and iRow are set to zero, no incremental blob
** cursors are invalidated.
*/
static int checkReadLocks(
Btree *pBtree,
Pgno pgnoRoot,
BtCursor *pExclude,
i64 iRow
static int checkForReadConflicts(
Btree *pBtree, /* The database file to check */
Pgno pgnoRoot, /* Look for read cursors on this btree */
BtCursor *pExclude, /* Ignore this cursor */
i64 iRow /* The rowid that might be changing */
){
BtCursor *p;
BtShared *pBt = pBtree->pBt;
@ -5965,9 +6026,10 @@ static int checkReadLocks(
#endif
){
sqlite3 *dbOther = p->pBtree->db;
if( dbOther==0 ||
(dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0) ){
return SQLITE_LOCKED;
assert(dbOther);
if( dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0 ){
sqlite3ConnectionBlocked(db, dbOther);
return SQLITE_LOCKED_SHAREDCACHE;
}
}
}
@ -6004,8 +6066,11 @@ int sqlite3BtreeInsert(
assert( pBt->inTransaction==TRANS_WRITE );
assert( !pBt->readOnly );
assert( pCur->wrFlag );
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur, nKey) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
rc = checkForReadConflicts(pCur->pBtree, pCur->pgnoRoot, pCur, nKey);
if( rc ){
/* The table pCur points to has a read lock */
assert( rc==SQLITE_LOCKED_SHAREDCACHE );
return rc;
}
if( pCur->eState==CURSOR_FAULT ){
return pCur->skip;
@ -6101,8 +6166,11 @@ int sqlite3BtreeDelete(BtCursor *pCur){
return SQLITE_ERROR; /* The cursor is not pointing to anything */
}
assert( pCur->wrFlag );
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur, pCur->info.nKey) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
rc = checkForReadConflicts(p, pCur->pgnoRoot, pCur, pCur->info.nKey);
if( rc!=SQLITE_OK ){
/* The table pCur points to has a read lock */
assert( rc==SQLITE_LOCKED_SHAREDCACHE );
return rc;
}
/* Restore the current cursor position (a no-op if the cursor is not in
@ -6487,7 +6555,7 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
sqlite3BtreeEnter(p);
pBt->db = p->db;
assert( p->inTrans==TRANS_WRITE );
if( (rc = checkReadLocks(p, iTable, 0, 1))!=SQLITE_OK ){
if( (rc = checkForReadConflicts(p, iTable, 0, 1))!=SQLITE_OK ){
/* nothing to do */
}else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
/* nothing to do */
@ -6533,7 +6601,8 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
** occur.
*/
if( pBt->pCursor ){
return SQLITE_LOCKED;
sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db);
return SQLITE_LOCKED_SHAREDCACHE;
}
rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
@ -6655,9 +6724,10 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
/* Reading a meta-data value requires a read-lock on page 1 (and hence
** the sqlite_master table. We grab this lock regardless of whether or
** not the SQLITE_ReadUncommitted flag is set (the table rooted at page
** 1 is treated as a special case by queryTableLock() and lockTable()).
** 1 is treated as a special case by querySharedCacheTableLock()
** and setSharedCacheTableLock()).
*/
rc = queryTableLock(p, 1, READ_LOCK);
rc = querySharedCacheTableLock(p, 1, READ_LOCK);
if( rc!=SQLITE_OK ){
sqlite3BtreeLeave(p);
return rc;
@ -6699,7 +6769,7 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
#endif
/* Grab the read-lock on page 1. */
rc = lockTable(p, 1, READ_LOCK);
rc = setSharedCacheTableLock(p, 1, READ_LOCK);
sqlite3BtreeLeave(p);
return rc;
}
@ -6750,6 +6820,75 @@ int sqlite3BtreeFlags(BtCursor *pCur){
return pPage->aData[pPage->hdrOffset];
}
#ifndef SQLITE_OMIT_BTREECOUNT
/*
** The first argument, pCur, is a cursor opened on some b-tree. Count the
** number of entries in the b-tree and write the result to *pnEntry.
**
** SQLITE_OK is returned if the operation is successfully executed.
** Otherwise, if an error is encountered (i.e. an IO error or database
** corruption) an SQLite error code is returned.
*/
int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
i64 nEntry = 0; /* Value to return in *pnEntry */
int rc; /* Return code */
rc = moveToRoot(pCur);
/* Unless an error occurs, the following loop runs one iteration for each
** page in the B-Tree structure (not including overflow pages).
*/
while( rc==SQLITE_OK ){
int iIdx; /* Index of child node in parent */
MemPage *pPage; /* Current page of the b-tree */
/* If this is a leaf page or the tree is not an int-key tree, then
** this page contains countable entries. Increment the entry counter
** accordingly.
*/
pPage = pCur->apPage[pCur->iPage];
if( pPage->leaf || !pPage->intKey ){
nEntry += pPage->nCell;
}
/* pPage is a leaf node. This loop navigates the cursor so that it
** points to the first interior cell that it points to the parent of
** the next page in the tree that has not yet been visited. The
** pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell
** of the page, or to the number of cells in the page if the next page
** to visit is the right-child of its parent.
**
** If all pages in the tree have been visited, return SQLITE_OK to the
** caller.
*/
if( pPage->leaf ){
do {
if( pCur->iPage==0 ){
/* All pages of the b-tree have been visited. Return successfully. */
*pnEntry = nEntry;
return SQLITE_OK;
}
sqlite3BtreeMoveToParent(pCur);
}while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
pCur->aiIdx[pCur->iPage]++;
pPage = pCur->apPage[pCur->iPage];
}
/* Descend to the child node of the cell that the cursor currently
** points at. This is the right-child if (iIdx==pPage->nCell).
*/
iIdx = pCur->aiIdx[pCur->iPage];
if( iIdx==pPage->nCell ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
}else{
rc = moveToChild(pCur, get4byte(findCell(pPage, iIdx)));
}
}
/* An error has occurred. Return an error code. */
return rc;
}
#endif
/*
** Return the pager associated with a BTree. This routine is used for
@ -6986,7 +7125,9 @@ static int checkTreePage(
sz = info.nData;
if( !pPage->intKey ) sz += (int)info.nKey;
assert( sz==info.nPayload );
if( sz>info.nLocal ){
if( (sz>info.nLocal)
&& (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize])
){
int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4);
Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
#ifndef SQLITE_OMIT_AUTOVACUUM
@ -7248,14 +7389,6 @@ int sqlite3BtreeIsInTrans(Btree *p){
return (p && (p->inTrans==TRANS_WRITE));
}
/*
** Return non-zero if a statement transaction is active.
*/
int sqlite3BtreeIsInStmt(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
return ALWAYS(p->pBt) && p->pBt->inStmt;
}
/*
** Return non-zero if a read (or write) transaction is active.
*/
@ -7303,14 +7436,16 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
}
/*
** Return true if another user of the same shared btree as the argument
** handle holds an exclusive lock on the sqlite_master table.
** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
** btree as the argument handle holds an exclusive lock on the
** sqlite_master table. Otherwise SQLITE_OK.
*/
int sqlite3BtreeSchemaLocked(Btree *p){
int rc;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
rc = (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK);
rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE );
sqlite3BtreeLeave(p);
return rc;
}
@ -7329,9 +7464,9 @@ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
assert( READ_LOCK+1==WRITE_LOCK );
assert( isWriteLock==0 || isWriteLock==1 );
sqlite3BtreeEnter(p);
rc = queryTableLock(p, iTab, lockType);
rc = querySharedCacheTableLock(p, iTab, lockType);
if( rc==SQLITE_OK ){
rc = lockTable(p, iTab, lockType);
rc = setSharedCacheTableLock(p, iTab, lockType);
}
sqlite3BtreeLeave(p);
}
@ -7348,6 +7483,8 @@ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
** to change the length of the data stored.
*/
int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
int rc;
assert( cursorHoldsMutex(pCsr) );
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
assert(pCsr->isIncrblobHandle);
@ -7368,8 +7505,11 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
}
assert( !pCsr->pBt->readOnly
&& pCsr->pBt->inTransaction==TRANS_WRITE );
if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr, 0) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
rc = checkForReadConflicts(pCsr->pBtree, pCsr->pgnoRoot, pCsr, 0);
if( rc!=SQLITE_OK ){
/* The table pCur points to has a read lock */
assert( rc==SQLITE_LOCKED_SHAREDCACHE );
return rc;
}
if( pCsr->eState==CURSOR_INVALID || !pCsr->apPage[pCsr->iPage]->intKey ){
return SQLITE_ERROR;

13
btree.h
View file

@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.108 2009/02/03 16:51:25 danielk1977 Exp $
** @(#) $Id: btree.h,v 1.111 2009/03/18 10:33:01 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@ -91,12 +91,9 @@ int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
int sqlite3BtreeCommitPhaseTwo(Btree*);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*);
int sqlite3BtreeCommitStmt(Btree*);
int sqlite3BtreeRollbackStmt(Btree*);
int sqlite3BtreeBeginStmt(Btree*,int);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeIsInBackup(Btree*);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
@ -165,6 +162,8 @@ const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64);
sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor*);
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);
@ -173,6 +172,10 @@ int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeCacheOverflow(BtCursor *);
void sqlite3BtreeClearCursor(BtCursor *);
#ifndef SQLITE_OMIT_BTREECOUNT
int sqlite3BtreeCount(BtCursor *, i64 *);
#endif
#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
void sqlite3BtreeCursorList(Btree*);

View file

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btreeInt.h,v 1.42 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: btreeInt.h,v 1.46 2009/03/20 14:18:52 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@ -205,11 +205,6 @@
*/
#include "sqliteInt.h"
/* Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
#define ROUND8(x) ((x+7)&~7)
/* The following value is the maximum cell size assuming a maximum page
** size give above.
@ -356,13 +351,30 @@ struct Btree {
** may not be modified once it is initially set as long as nRef>0.
** The pSchema field may be set once under BtShared.mutex and
** thereafter is unchanged as long as nRef>0.
**
** isPending:
**
** If a BtShared client fails to obtain a write-lock on a database
** table (because there exists one or more read-locks on the table),
** the shared-cache enters 'pending-lock' state and isPending is
** set to true.
**
** The shared-cache leaves the 'pending lock' state when either of
** the following occur:
**
** 1) The current writer (BtShared.pWriter) concludes its transaction, OR
** 2) The number of locks held by other connections drops to zero.
**
** while in the 'pending-lock' state, no connection may start a new
** transaction.
**
** This feature is included to help prevent writer-starvation.
*/
struct BtShared {
Pager *pPager; /* The page cache */
sqlite3 *db; /* Database connection currently using this Btree */
BtCursor *pCursor; /* A list of all open cursors */
MemPage *pPage1; /* First page of the database */
u8 inStmt; /* True if we are in a statement subtransaction */
u8 readOnly; /* True if the underlying file is readonly */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
#ifndef SQLITE_OMIT_AUTOVACUUM
@ -385,7 +397,9 @@ struct BtShared {
int nRef; /* Number of references to this structure */
BtShared *pNext; /* Next on a list of sharable BtShared structs */
BtLock *pLock; /* List of locks held on this shared-btree struct */
Btree *pExclusive; /* Btree with an EXCLUSIVE lock on the whole db */
Btree *pWriter; /* Btree with currently open write transaction */
u8 isExclusive; /* True if pWriter has an EXCLUSIVE lock on the db */
u8 isPending; /* If waiting for read-locks to clear */
#endif
u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
};
@ -438,6 +452,7 @@ struct BtCursor {
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
Pgno pgnoRoot; /* The root page of this tree */
sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */
u8 atLast; /* Cursor pointing to the last entry */

190
build.c
View file

@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
** $Id: build.c,v 1.518 2009/02/13 03:43:32 drh Exp $
** $Id: build.c,v 1.527 2009/03/31 03:41:57 shane Exp $
*/
#include "sqliteInt.h"
@ -178,19 +178,6 @@ void sqlite3FinishCoding(Parse *pParse){
codeTableLocks(pParse);
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
}
#ifndef SQLITE_OMIT_TRACE
if( !db->init.busy ){
/* Change the P4 argument of the first opcode (which will always be
** an OP_Trace) to be the complete text of the current SQL statement.
*/
VdbeOp *pOp = sqlite3VdbeGetOp(v, 0);
if( pOp && pOp->opcode==OP_Trace ){
sqlite3VdbeChangeP4(v, 0, pParse->zSql,
(int)(pParse->zTail - pParse->zSql));
}
}
#endif /* SQLITE_OMIT_TRACE */
}
@ -202,8 +189,8 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeTrace(v, trace);
#endif
assert( pParse->disableColCache==0 ); /* Disables and re-enables match */
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
pParse->nTab+3, pParse->explain);
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
pParse->nTab, pParse->explain);
pParse->rc = SQLITE_DONE;
pParse->colNamesSet = 0;
}else if( pParse->rc==SQLITE_OK ){
@ -352,7 +339,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
** Reclaim the memory used by an index
*/
static void freeIndex(Index *p){
sqlite3 *db = p->pTable->db;
sqlite3 *db = p->pTable->dbMem;
sqlite3DbFree(db, p->zColAff);
sqlite3DbFree(db, p);
}
@ -480,7 +467,7 @@ void sqlite3CommitInternalChanges(sqlite3 *db){
static void sqliteResetColumnNames(Table *pTable){
int i;
Column *pCol;
sqlite3 *db = pTable->db;
sqlite3 *db = pTable->dbMem;
assert( pTable!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
@ -511,7 +498,7 @@ void sqlite3DeleteTable(Table *pTable){
sqlite3 *db;
if( pTable==0 ) return;
db = pTable->db;
db = pTable->dbMem;
/* Do not delete the table until the reference count reaches zero. */
pTable->nRef--;
@ -616,8 +603,11 @@ char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
void sqlite3OpenMasterTable(Parse *p, int iDb){
Vdbe *v = sqlite3GetVdbe(p);
sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5);/* sqlite_master has 5 columns */
sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
sqlite3VdbeChangeP4(v, -1, (char *)5, P4_INT32); /* 5 column table */
if( p->nTab==0 ){
p->nTab = 1;
}
}
/*
@ -846,7 +836,7 @@ void sqlite3StartTable(
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
pTable->db = db;
pTable->dbMem = db->lookaside.bEnabled ? db : 0;
if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable);
pParse->pNewTable = pTable;
@ -901,9 +891,10 @@ void sqlite3StartTable(
** The record created does not contain anything yet. It will be replaced
** by the real entry in code generated at sqlite3EndTable().
**
** The rowid for the new entry is left on the top of the stack.
** The rowid value is needed by the code that sqlite3EndTable will
** generate.
** The rowid for the new entry is left in register pParse->regRowid.
** The root page number of the new table is left in reg pParse->regRoot.
** The rowid and root page number values are needed by the code that
** sqlite3EndTable will generate.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
if( isView || isVirtual ){
@ -1116,12 +1107,14 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
Expr *pCopy;
/* A copy of pExpr is used instead of the original, as pExpr contains
** tokens that point to volatile memory. The 'span' of the expression
** is required by pragma table_info.
*/
sqlite3ExprDelete(db, pCol->pDflt);
pCol->pDflt = pCopy = sqlite3ExprDup(db, pExpr);
if( pCopy ){
sqlite3TokenCopy(db, &pCopy->span, &pExpr->span);
}
pCol->pDflt = sqlite3ExprDup(
db, pExpr, EXPRDUP_REDUCE|EXPRDUP_DISTINCTSPAN
);
}
}
sqlite3ExprDelete(db, pExpr);
@ -1217,7 +1210,7 @@ void sqlite3AddCheckConstraint(
** to malloced space and not the (ephemeral) text of the CREATE TABLE
** statement */
pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck,
sqlite3ExprDup(db, pCheckExpr));
sqlite3ExprDup(db, pCheckExpr, 0));
}
#endif
sqlite3ExprDelete(db, pCheckExpr);
@ -1340,18 +1333,100 @@ static int identLength(const char *z){
}
/*
** Write an identifier onto the end of the given string. Add
** quote characters as needed.
** This function is a wrapper around sqlite3GetToken() used by
** isValidDimension(). This function differs from sqlite3GetToken() in
** that:
**
** * Whitespace is ignored, and
** * The output variable *peToken is set to 0 if the end of the
** nul-terminated input string is reached.
*/
static void identPut(char *z, int *pIdx, char *zSignedIdent){
static int getTokenNoSpace(unsigned char *z, int *peToken){
int n = 0;
while( sqlite3Isspace(z[n]) ) n++;
if( !z[n] ){
*peToken = 0;
return 0;
}
return n + sqlite3GetToken(&z[n], peToken);
}
/*
** Parameter z points to a nul-terminated string. Return true if, when
** whitespace is ignored, the contents of this string matches one of
** the following patterns:
**
** ""
** "(number)"
** "(number,number)"
*/
static int isValidDimension(unsigned char *z){
int eToken;
int n = 0;
n += getTokenNoSpace(&z[n], &eToken);
if( eToken ){
if( eToken!=TK_LP ) return 0;
n += getTokenNoSpace(&z[n], &eToken);
if( eToken==TK_PLUS || eToken==TK_MINUS ){
n += getTokenNoSpace(&z[n], &eToken);
}
if( eToken!=TK_INTEGER && eToken!=TK_FLOAT ) return 0;
n += getTokenNoSpace(&z[n], &eToken);
if( eToken==TK_COMMA ){
n += getTokenNoSpace(&z[n], &eToken);
if( eToken==TK_PLUS || eToken==TK_MINUS ){
n += getTokenNoSpace(&z[n], &eToken);
}
if( eToken!=TK_INTEGER && eToken!=TK_FLOAT ) return 0;
n += getTokenNoSpace(&z[n], &eToken);
}
if( eToken!=TK_RP ) return 0;
getTokenNoSpace(&z[n], &eToken);
}
if( eToken ) return 0;
return 1;
}
/*
** The first parameter is a pointer to an output buffer. The second
** parameter is a pointer to an integer that contains the offset at
** which to write into the output buffer. This function copies the
** nul-terminated string pointed to by the third parameter, zSignedIdent,
** to the specified offset in the buffer and updates *pIdx to refer
** to the first byte after the last byte written before returning.
**
** If the string zSignedIdent consists entirely of alpha-numeric
** characters, does not begin with a digit and is not an SQL keyword,
** then it is copied to the output buffer exactly as it is. Otherwise,
** it is quoted using double-quotes.
*/
static void identPut(char *z, int *pIdx, char *zSignedIdent, int isTypename){
unsigned char *zIdent = (unsigned char*)zSignedIdent;
int i, j, needQuote;
i = *pIdx;
for(j=0; zIdent[j]; j++){
if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
}
needQuote = zIdent[j]!=0 || sqlite3Isdigit(zIdent[0])
|| sqlite3KeywordCode(zIdent, j)!=TK_ID;
needQuote = sqlite3Isdigit(zIdent[0]) || sqlite3KeywordCode(zIdent, j)!=TK_ID;
if( !needQuote ){
if( isTypename ){
/* If this is a type-name, allow a little more flexibility. In SQLite,
** a type-name is specified as:
**
** ids [ids] [(number [, number])]
**
** where "ids" is either a quoted string or a simple identifier (in the
** above notation, [] means optional). It is a bit tricky to check
** for all cases, but it is good to avoid unnecessarily quoting common
** typenames like VARCHAR(10).
*/
needQuote = !isValidDimension(&zIdent[j]);
}else{
needQuote = zIdent[j];
}
}
if( needQuote ) z[i++] = '"';
for(j=0; zIdent[j]; j++){
z[i++] = zIdent[j];
@ -1377,7 +1452,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
n += identLength(pCol->zName);
z = pCol->zType;
if( z ){
n += (sqlite3Strlen30(z) + 1);
n += identLength(z);
}
}
n += identLength(p->zName);
@ -1398,18 +1473,17 @@ static char *createTableStmt(sqlite3 *db, Table *p){
}
sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
k = sqlite3Strlen30(zStmt);
identPut(zStmt, &k, p->zName);
identPut(zStmt, &k, p->zName, 0);
zStmt[k++] = '(';
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
sqlite3_snprintf(n-k, &zStmt[k], zSep);
k += sqlite3Strlen30(&zStmt[k]);
zSep = zSep2;
identPut(zStmt, &k, pCol->zName);
identPut(zStmt, &k, pCol->zName, 0);
if( (z = pCol->zType)!=0 ){
zStmt[k++] = ' ';
assert( (int)(sqlite3Strlen30(z)+k+1)<=n );
sqlite3_snprintf(n-k, &zStmt[k], "%s", z);
k += sqlite3Strlen30(z);
identPut(zStmt, &k, z, 1);
}
}
sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
@ -1489,8 +1563,7 @@ void sqlite3EndTable(
}
/* If not initializing, then create a record for the new table
** in the SQLITE_MASTER table of the database. The record number
** for the new table entry should already be on the stack.
** in the SQLITE_MASTER table of the database.
**
** If this is a TEMPORARY table, write the entry into the auxiliary
** file instead of into the main database file.
@ -1507,9 +1580,8 @@ void sqlite3EndTable(
sqlite3VdbeAddOp1(v, OP_Close, 0);
/* Create the rootpage for the new table and push it onto the stack.
** A view has no rootpage, so just push a zero onto the stack for
** views. Initialize zType at the same time.
/*
** Initialize zType for the new view or table.
*/
if( p->pSelect==0 ){
/* A regular table */
@ -1525,7 +1597,7 @@ void sqlite3EndTable(
/* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
** statement to populate the new table. The root-page number for the
** new table is on the top of the vdbe stack.
** new table is in register pParse->regRoot.
**
** Once the SELECT has been coded by sqlite3Select(), it is in a
** suitable state to query for the column names and types to be used
@ -1540,7 +1612,7 @@ void sqlite3EndTable(
SelectDest dest;
Table *pSelTab;
assert(pParse->nTab==0);
assert(pParse->nTab==1);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, 1);
pParse->nTab = 2;
@ -1571,9 +1643,7 @@ void sqlite3EndTable(
/* A slot for the record has already been allocated in the
** SQLITE_MASTER table. We just need to update that slot with all
** the information we've collected. The rowid for the preallocated
** slot is the 2nd item on the stack. The top of the stack is the
** root page for the new table (or a 0 if this is a view).
** the information we've collected.
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s "
@ -1701,7 +1771,7 @@ void sqlite3CreateView(
** allocated rather than point to the input string - which means that
** they will persist after the current sqlite3_exec() call returns.
*/
p->pSelect = sqlite3SelectDup(db, pSelect);
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
sqlite3SelectDelete(db, pSelect);
if( db->mallocFailed ){
return;
@ -1783,11 +1853,13 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** statement that defines the view.
*/
assert( pTable->pSelect );
pSel = sqlite3SelectDup(db, pTable->pSelect);
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
u8 enableLookaside = db->lookaside.bEnabled;
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
db->lookaside.bEnabled = 0;
#ifndef SQLITE_OMIT_AUTHORIZATION
xAuth = db->xAuth;
db->xAuth = 0;
@ -1796,6 +1868,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#else
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
#endif
db->lookaside.bEnabled = enableLookaside;
pParse->nTab = n;
if( pSelTab ){
assert( pTable->aCol==0 );
@ -1892,8 +1965,8 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
** location iTable. The following code modifies the sqlite_master table to
** reflect this.
**
** The "#%d" in the SQL is a special constant that means whatever value
** is on the top of the stack. See sqlite3RegisterExpr().
** The "#NNN" in the SQL is a special constant that means whatever value
** is in register NNN. See sqlite3RegisterExpr().
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
@ -2068,7 +2141,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
** is generated to remove entries from sqlite_master and/or
** sqlite_temp_master if required.
*/
pTrigger = pTab->pTrigger;
pTrigger = sqlite3TriggerList(pParse, pTab);
while( pTrigger ){
assert( pTrigger->pSchema==pTab->pSchema ||
pTrigger->pSchema==db->aDb[1].pSchema );
@ -2277,8 +2350,8 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
*/
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
Table *pTab = pIndex->pTable; /* The table that is indexed */
int iTab = pParse->nTab; /* Btree cursor used for pTab */
int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */
int iTab = pParse->nTab++; /* Btree cursor used for pTab */
int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
int addr1; /* Address of top of loop */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
@ -2773,7 +2846,8 @@ void sqlite3CreateIndex(
/* Clean up before exiting */
exit_create_index:
if( pIndex ){
freeIndex(pIndex);
sqlite3_free(pIndex->zColAff);
sqlite3DbFree(db, pIndex);
}
sqlite3ExprListDelete(db, pList);
sqlite3SrcListDelete(db, pTblName);

View file

@ -13,7 +13,7 @@
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
**
** $Id: callback.c,v 1.35 2009/01/31 22:28:49 drh Exp $
** $Id: callback.c,v 1.37 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
@ -175,7 +175,7 @@ static CollSeq *findCollSeqEntry(
pColl[0].zName[nName] = 0;
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl);
/* If a malloc() failure occured in sqlite3HashInsert(), it will
/* If a malloc() failure occurred in sqlite3HashInsert(), it will
** return the pColl pointer to be deleted (because it wasn't added
** to the hash table).
*/
@ -423,6 +423,7 @@ void sqlite3SchemaFree(void *p){
sqlite3HashInit(&pSchema->tblHash, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
assert( pTab->dbMem==0 );
sqlite3DeleteTable(pTab);
}
sqlite3HashClear(&temp1);

View file

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
** $Id: delete.c,v 1.191 2008/12/23 23:56:22 drh Exp $
** $Id: delete.c,v 1.198 2009/03/05 03:48:07 shane Exp $
*/
#include "sqliteInt.h"
@ -77,8 +77,8 @@ void sqlite3OpenTable(
v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb);
sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(pTab->nCol), P4_INT32);
VdbeComment((v, "%s", pTab->zName));
}
@ -99,12 +99,12 @@ void sqlite3MaterializeView(
Select *pDup;
sqlite3 *db = pParse->db;
pDup = sqlite3SelectDup(db, pView->pSelect);
pDup = sqlite3SelectDup(db, pView->pSelect, 0);
if( pWhere ){
SrcList *pFrom;
Token viewName;
pWhere = sqlite3ExprDup(db, pWhere);
pWhere = sqlite3ExprDup(db, pWhere, 0);
viewName.z = (u8*)pView->zName;
viewName.n = (unsigned int)sqlite3Strlen30((const char*)viewName.z);
pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName, pDup, 0,0);
@ -174,14 +174,15 @@ Expr *sqlite3LimitWhere(
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc);
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
if( pSelectSrc == 0 ) {
sqlite3ExprListDelete(pParse->db, pEList);
goto limit_where_cleanup_2;
}
/* generate the SELECT expression tree. */
pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,pOrderBy,0,pLimit,pOffset);
pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,
pOrderBy,0,pLimit,pOffset);
if( pSelect == 0 ) return 0;
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
@ -190,7 +191,8 @@ Expr *sqlite3LimitWhere(
pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
if( pInClause == 0 ) goto limit_where_cleanup_1;
pInClause->pSelect = pSelect;
pInClause->x.pSelect = pSelect;
pInClause->flags |= EP_xIsSelect;
sqlite3ExprSetHeight(pParse, pInClause);
return pInClause;
@ -238,7 +240,7 @@ void sqlite3DeleteFrom(
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
int triggers_exist = 0; /* True if any triggers exist */
Trigger *pTrigger; /* List of table triggers, if required */
#endif
int iBeginAfterTrigger = 0; /* Address of after trigger program */
int iEndAfterTrigger = 0; /* Exit of after trigger program */
@ -265,10 +267,10 @@ void sqlite3DeleteFrom(
** deleted from is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pTab, TK_DELETE, 0);
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define pTrigger 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
@ -276,7 +278,7 @@ void sqlite3DeleteFrom(
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
goto delete_from_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@ -287,7 +289,7 @@ void sqlite3DeleteFrom(
if( rcauth==SQLITE_DENY ){
goto delete_from_cleanup;
}
assert(!isView || triggers_exist);
assert(!isView || pTrigger);
/* If pTab is really a view, make sure it has been initialized.
*/
@ -297,7 +299,7 @@ void sqlite3DeleteFrom(
/* Allocate a cursor used to store the old.* data for a trigger.
*/
if( triggers_exist ){
if( pTrigger ){
oldIdx = pParse->nTab++;
}
@ -322,21 +324,21 @@ void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
sqlite3BeginWriteOperation(pParse, (pTrigger?1:0), iDb);
if( triggers_exist ){
if( pTrigger ){
int orconf = ((pParse->trigStack)?pParse->trigStack->orconf:OE_Default);
int iGoto = sqlite3VdbeAddOp0(v, OP_Goto);
addr = sqlite3VdbeMakeLabel(v);
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
-1, oldIdx, orconf, addr, &old_col_mask, 0);
(void)sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0,
TRIGGER_BEFORE, pTab, -1, oldIdx, orconf, addr, &old_col_mask, 0);
iEndBeforeTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
oldIdx, orconf, addr, &old_col_mask, 0);
(void)sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0,
TRIGGER_AFTER, pTab, -1, oldIdx, orconf, addr, &old_col_mask, 0);
iEndAfterTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, iGoto);
@ -373,7 +375,7 @@ void sqlite3DeleteFrom(
** It is easier just to erase the whole table. Note, however, that
** this means that the row change count will be incorrect.
*/
if( rcauth==SQLITE_OK && pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){
if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab) ){
assert( !isView );
sqlite3VdbeAddOp3(v, OP_Clear, pTab->tnum, iDb, memCnt);
if( !pParse->nested ){
@ -405,9 +407,8 @@ void sqlite3DeleteFrom(
/* Open the pseudo-table used to store OLD if there are triggers.
*/
if( triggers_exist ){
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp1(v, OP_OpenPseudo, oldIdx);
if( pTrigger ){
sqlite3VdbeAddOp3(v, OP_OpenPseudo, oldIdx, 0, pTab->nCol);
}
/* Delete every item whose key was written to the list during the
@ -426,12 +427,12 @@ void sqlite3DeleteFrom(
/* This is the beginning of the delete loop. If a trigger encounters
** an IGNORE constraint, it jumps back to here.
*/
if( triggers_exist ){
if( pTrigger ){
sqlite3VdbeResolveLabel(v, addr);
}
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
if( triggers_exist ){
if( pTrigger ){
int iData = ++pParse->nMem; /* For storing row data of OLD table */
/* If the record is no longer present in the table, jump to the
@ -469,7 +470,7 @@ void sqlite3DeleteFrom(
/* If there are row triggers, close all cursors then invoke
** the AFTER triggers
*/
if( triggers_exist ){
if( pTrigger ){
/* Jump back and run the AFTER triggers */
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);

465
expr.c
View file

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.411 2009/02/04 03:59:25 shane Exp $
** $Id: expr.c,v 1.424 2009/03/25 16:51:43 drh Exp $
*/
#include "sqliteInt.h"
@ -35,7 +35,8 @@
char sqlite3ExprAffinity(Expr *pExpr){
int op = pExpr->op;
if( op==TK_SELECT ){
return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
assert( pExpr->flags&EP_xIsSelect );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
@ -155,11 +156,9 @@ static char comparisonAffinity(Expr *pExpr){
aff = sqlite3ExprAffinity(pExpr->pLeft);
if( pExpr->pRight ){
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
}
else if( pExpr->pSelect ){
aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
}
else if( !aff ){
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
}else if( !aff ){
aff = SQLITE_AFF_NONE;
}
return aff;
@ -345,8 +344,11 @@ static void exprSetHeight(Expr *p){
int nHeight = 0;
heightOfExpr(p->pLeft, &nHeight);
heightOfExpr(p->pRight, &nHeight);
heightOfExprList(p->pList, &nHeight);
heightOfSelect(p->pSelect, &nHeight);
if( ExprHasProperty(p, EP_xIsSelect) ){
heightOfSelect(p->x.pSelect, &nHeight);
}else{
heightOfExprList(p->x.pList, &nHeight);
}
p->nHeight = nHeight + 1;
}
@ -402,8 +404,24 @@ Expr *sqlite3Expr(
pNew->iAgg = -1;
pNew->span.z = (u8*)"";
if( pToken ){
int c;
assert( pToken->dyn==0 );
pNew->span = pNew->token = *pToken;
pNew->span = *pToken;
/* The pToken->z value is read-only. But the new expression
** node created here might be passed to sqlite3DequoteExpr() which
** will attempt to modify pNew->token.z. Hence, if the token
** is quoted, make a copy now so that DequoteExpr() will change
** the copy rather than the original text.
*/
if( pToken->n>=2
&& ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
sqlite3TokenCopy(db, &pNew->token, pToken);
}else{
pNew->token = *pToken;
pNew->flags |= EP_Dequoted;
VVA_ONLY( pNew->vvaFlags |= EVVA_ReadOnlyToken; )
}
}else if( pLeft ){
if( pRight ){
if( pRight->span.dyn==0 && pLeft->span.dyn==0 ){
@ -492,7 +510,10 @@ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
assert( pLeft!=0 );
if( pExpr ){
pExpr->span.z = pLeft->z;
pExpr->span.n = pRight->n + (pRight->z - pLeft->z);
/* The following assert() may fail when this is called
** via sqlite3PExpr()/sqlite3Expr() from addWhereTerm(). */
/* assert(pRight->z >= pLeft->z); */
pExpr->span.n = pRight->n + (unsigned)(pRight->z - pLeft->z);
}
}
@ -506,15 +527,15 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
assert( pToken );
pNew = sqlite3DbMallocZero(db, sizeof(Expr) );
if( pNew==0 ){
sqlite3ExprListDelete(db, pList); /* Avoid leaking memory when malloc fails */
sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
return 0;
}
pNew->op = TK_FUNCTION;
pNew->pList = pList;
pNew->x.pList = pList;
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
assert( pToken->dyn==0 );
pNew->token = *pToken;
pNew->span = pNew->token;
pNew->span = *pToken;
sqlite3TokenCopy(db, &pNew->token, pToken);
sqlite3ExprSetHeight(pParse, pNew);
return pNew;
}
@ -607,12 +628,22 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
** Substructure is deleted.
*/
void sqlite3ExprClear(sqlite3 *db, Expr *p){
if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
if( p->token.dyn ) sqlite3DbFree(db, (char*)p->token.z);
sqlite3ExprDelete(db, p->pLeft);
sqlite3ExprDelete(db, p->pRight);
sqlite3ExprListDelete(db, p->pList);
sqlite3SelectDelete(db, p->pSelect);
if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanOnly) ){
if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
if( ExprHasProperty(p, EP_Reduced) ){
if( p->pLeft ) sqlite3ExprClear(db, p->pLeft);
if( p->pRight ) sqlite3ExprClear(db, p->pRight);
}else{
sqlite3ExprDelete(db, p->pLeft);
sqlite3ExprDelete(db, p->pRight);
}
if( ExprHasProperty(p, EP_xIsSelect) ){
sqlite3SelectDelete(db, p->x.pSelect);
}else{
sqlite3ExprListDelete(db, p->x.pList);
}
}
}
/*
@ -628,15 +659,195 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
** The Expr.token field might be a string literal that is quoted.
** If so, remove the quotation marks.
*/
void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
if( ExprHasAnyProperty(p, EP_Dequoted) ){
return;
void sqlite3DequoteExpr(Expr *p){
if( !ExprHasAnyProperty(p, EP_Dequoted) ){
ExprSetProperty(p, EP_Dequoted);
assert( (p->vvaFlags & EVVA_ReadOnlyToken)==0 );
sqlite3Dequote((char*)p->token.z);
}
ExprSetProperty(p, EP_Dequoted);
if( p->token.dyn==0 ){
sqlite3TokenCopy(db, &p->token, &p->token);
}
/*
** Return the number of bytes allocated for the expression structure
** passed as the first argument. This is always one of EXPR_FULLSIZE,
** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
*/
static int exprStructSize(Expr *p){
if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE;
if( ExprHasProperty(p, EP_SpanOnly) ) return EXPR_SPANONLYSIZE;
if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE;
return EXPR_FULLSIZE;
}
/*
** sqlite3ExprDup() has been called to create a copy of expression p with
** the EXPRDUP_XXX flags passed as the second argument. This function
** returns the space required for the copy of the Expr structure only.
** This is always one of EXPR_FULLSIZE, EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
*/
static int dupedExprStructSize(Expr *p, int flags){
int nSize;
if( 0==(flags&EXPRDUP_REDUCE) ){
nSize = EXPR_FULLSIZE;
}else if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
nSize = EXPR_REDUCEDSIZE;
}else if( flags&(EXPRDUP_SPAN|EXPRDUP_DISTINCTSPAN) ){
nSize = EXPR_SPANONLYSIZE;
}else{
nSize = EXPR_TOKENONLYSIZE;
}
sqlite3Dequote((char*)p->token.z);
return nSize;
}
/*
** sqlite3ExprDup() has been called to create a copy of expression p with
** the EXPRDUP_XXX passed as the second argument. This function returns
** the space in bytes required to store the copy of the Expr structure
** and the copies of the Expr.token.z and Expr.span.z (if applicable)
** string buffers.
*/
static int dupedExprNodeSize(Expr *p, int flags){
int nByte = dupedExprStructSize(p, flags) + (p->token.z ? p->token.n + 1 : 0);
if( (flags&EXPRDUP_DISTINCTSPAN)
|| (flags&EXPRDUP_SPAN && (p->token.z!=p->span.z || p->token.n!=p->span.n))
){
nByte += p->span.n;
}
return ROUND8(nByte);
}
/*
** Return the number of bytes required to create a duplicate of the
** expression passed as the first argument. The second argument is a
** mask containing EXPRDUP_XXX flags.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.token, if any. If the
** EXPRDUP_SPAN flag is set, then space to create a copy of the buffer
** refered to by Expr.span is also included.
**
** If the EXPRDUP_REDUCE flag is set, then the return value includes
** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
** and Expr.pRight variables (but not for any structures pointed to or
** descended from the Expr.x.pList or Expr.x.pSelect variables).
*/
static int dupedExprSize(Expr *p, int flags){
int nByte = 0;
if( p ){
nByte = dupedExprNodeSize(p, flags);
if( flags&EXPRDUP_REDUCE ){
int f = flags&(~(EXPRDUP_SPAN|EXPRDUP_DISTINCTSPAN));
nByte += dupedExprSize(p->pLeft, f) + dupedExprSize(p->pRight, f);
}
}
return nByte;
}
/*
** This function is similar to sqlite3ExprDup(), except that if pzBuffer
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
** to store the copy of expression p, the copies of p->token and p->span
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
** if any. Before returning, *pzBuffer is set to the first byte passed the
** portion of the buffer copied into by this function.
*/
static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
Expr *pNew = 0; /* Value to return */
if( p ){
const int isRequireDistinctSpan = (flags&EXPRDUP_DISTINCTSPAN);
const int isRequireSpan = (flags&(EXPRDUP_SPAN|EXPRDUP_DISTINCTSPAN));
const int isReduced = (flags&EXPRDUP_REDUCE);
u8 *zAlloc;
assert( pzBuffer==0 || isReduced );
/* Figure out where to write the new Expr structure. */
if( pzBuffer ){
zAlloc = *pzBuffer;
}else{
zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
}
pNew = (Expr *)zAlloc;
if( pNew ){
/* Set nNewSize to the size allocated for the structure pointed to
** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
** by the copy of the p->token.z string (if any).
*/
const int nNewSize = dupedExprStructSize(p, flags);
const int nToken = (p->token.z ? p->token.n + 1 : 0);
if( isReduced ){
assert( ExprHasProperty(p, EP_Reduced)==0 );
memcpy(zAlloc, p, nNewSize);
}else{
int nSize = exprStructSize(p);
memcpy(zAlloc, p, nSize);
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
/* Set the EP_Reduced and EP_TokenOnly flags appropriately. */
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_SpanOnly);
switch( nNewSize ){
case EXPR_REDUCEDSIZE: pNew->flags |= EP_Reduced; break;
case EXPR_TOKENONLYSIZE: pNew->flags |= EP_TokenOnly; break;
case EXPR_SPANONLYSIZE: pNew->flags |= EP_SpanOnly; break;
}
/* Copy the p->token string, if any. */
if( nToken ){
unsigned char *zToken = &zAlloc[nNewSize];
memcpy(zToken, p->token.z, nToken-1);
zToken[nToken-1] = '\0';
pNew->token.dyn = 0;
pNew->token.z = zToken;
}
if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
/* Fill in the pNew->span token, if required. */
if( isRequireSpan ){
if( isRequireDistinctSpan
|| p->token.z!=p->span.z || p->token.n!=p->span.n
){
pNew->span.z = &zAlloc[nNewSize+nToken];
memcpy((char *)pNew->span.z, p->span.z, p->span.n);
pNew->span.dyn = 0;
}else{
pNew->span.z = pNew->token.z;
pNew->span.n = pNew->token.n;
}
}else{
pNew->span.z = 0;
pNew->span.n = 0;
}
}
if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_SpanOnly)) ){
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
if( ExprHasProperty(p, EP_xIsSelect) ){
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
}else{
pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
}
}
/* Fill in pNew->pLeft and pNew->pRight. */
if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly|EP_SpanOnly) ){
zAlloc += dupedExprNodeSize(p, flags);
if( ExprHasProperty(pNew, EP_Reduced) ){
pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
}
if( pzBuffer ){
*pzBuffer = zAlloc;
}
}else if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanOnly) ){
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
}
}
}
return pNew;
}
/*
@ -650,27 +861,21 @@ void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
** by subsequent calls to sqlite*ListAppend() routines.
**
** Any tables that the SrcList might point to are not duplicated.
**
** The flags parameter contains a combination of the EXPRDUP_XXX flags. If
** the EXPRDUP_SPAN flag is set in the argument parameter, then the
** Expr.span field of the input expression is copied. If EXPRDUP_SPAN is
** clear, then the Expr.span field of the returned expression structure
** is zeroed.
**
** If the EXPRDUP_REDUCE flag is set, then the structure returned is a
** truncated version of the usual Expr structure that will be stored as
** part of the in-memory representation of the database schema.
*/
Expr *sqlite3ExprDup(sqlite3 *db, Expr *p){
Expr *pNew;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
memcpy(pNew, p, sizeof(*pNew));
if( p->token.z!=0 ){
pNew->token.z = (u8*)sqlite3DbStrNDup(db, (char*)p->token.z, p->token.n);
pNew->token.dyn = 1;
}else{
assert( pNew->token.z==0 );
}
pNew->span.z = 0;
pNew->pLeft = sqlite3ExprDup(db, p->pLeft);
pNew->pRight = sqlite3ExprDup(db, p->pRight);
pNew->pList = sqlite3ExprListDup(db, p->pList);
pNew->pSelect = sqlite3SelectDup(db, p->pSelect);
return pNew;
Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
return exprDup(db, p, flags, 0);
}
void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
void sqlite3TokenCopy(sqlite3 *db, Token *pTo, const Token *pFrom){
if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z);
if( pFrom->z ){
pTo->n = pFrom->n;
@ -680,7 +885,7 @@ void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
pTo->z = 0;
}
}
ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
@ -696,17 +901,9 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
}
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
Expr *pNewExpr, *pOldExpr;
pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr = pOldItem->pExpr);
if( pOldExpr->span.z!=0 && pNewExpr ){
/* Always make a copy of the span for top-level expressions in the
** expression list. The logic in SELECT processing that determines
** the names of columns in the result set needs this information */
sqlite3TokenCopy(db, &pNewExpr->span, &pOldExpr->span);
}
assert( pNewExpr==0 || pNewExpr->span.z!=0
|| pOldExpr->span.z==0
|| db->mallocFailed );
Expr *pNewExpr;
Expr *pOldExpr = pOldItem->pExpr;
pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr, flags);
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pItem->sortOrder = pOldItem->sortOrder;
pItem->done = 0;
@ -724,7 +921,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|| !defined(SQLITE_OMIT_SUBQUERY)
SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
SrcList *pNew;
int i;
int nByte;
@ -750,8 +947,8 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
if( pTab ){
pTab->nRef++;
}
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect);
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn);
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
pNewItem->colUsed = pOldItem->colUsed;
}
@ -777,21 +974,24 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
}
return pNew;
}
Select *sqlite3SelectDup(sqlite3 *db, Select *p){
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
Select *pNew;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
pNew->pEList = sqlite3ExprListDup(db, p->pEList);
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc);
pNew->pWhere = sqlite3ExprDup(db, p->pWhere);
pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy);
pNew->pHaving = sqlite3ExprDup(db, p->pHaving);
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy);
/* Always make a copy of the span for top-level expressions in the
** expression list. The logic in SELECT processing that determines
** the names of columns in the result set needs this information */
pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags|EXPRDUP_SPAN);
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
pNew->op = p->op;
pNew->pPrior = sqlite3SelectDup(db, p->pPrior);
pNew->pLimit = sqlite3ExprDup(db, p->pLimit);
pNew->pOffset = sqlite3ExprDup(db, p->pOffset);
pNew->pPrior = sqlite3SelectDup(db, p->pPrior, flags);
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
pNew->iLimit = 0;
pNew->iOffset = 0;
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
@ -802,7 +1002,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p){
return pNew;
}
#else
Select *sqlite3SelectDup(sqlite3 *db, Select *p){
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
assert( p==0 );
return 0;
}
@ -1143,7 +1343,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
** If this is the case, it may be possible to use an existing table
** or index instead of generating an epheremal table.
*/
p = pX->pSelect;
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
if( isCandidateForInOpt(p) ){
sqlite3 *db = pParse->db;
Index *pIdx;
@ -1202,7 +1402,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pIdx->nColumn);
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
pKey,P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
@ -1222,7 +1421,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
eType = IN_INDEX_EPH;
if( prNotFound ){
*prNotFound = rMayHaveNull = ++pParse->nMem;
}else if( pX->pLeft->iColumn<0 && pX->pSelect==0 ){
}else if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID;
}
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
@ -1311,7 +1510,7 @@ void sqlite3CodeSubselect(
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
if( pExpr->pSelect ){
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
**
** Generate code to write the results of the select into the temporary
@ -1324,15 +1523,15 @@ void sqlite3CodeSubselect(
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affinity = (u8)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
if( sqlite3Select(pParse, pExpr->pSelect, &dest) ){
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
return;
}
pEList = pExpr->pSelect->pEList;
pEList = pExpr->x.pSelect->pEList;
if( pEList && pEList->nExpr>0 ){
keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
pEList->a[0].pExpr);
}
}else if( pExpr->pList ){
}else if( pExpr->x.pList ){
/* Case 2: expr IN (exprlist)
**
** For each expression, build an index key from the evaluation and
@ -1341,7 +1540,7 @@ void sqlite3CodeSubselect(
** a column, use numeric affinity.
*/
int i;
ExprList *pList = pExpr->pList;
ExprList *pList = pExpr->x.pList;
struct ExprList_item *pItem;
int r1, r2, r3;
@ -1401,7 +1600,8 @@ void sqlite3CodeSubselect(
Select *pSel;
SelectDest dest;
pSel = pExpr->pSelect;
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
pSel = pExpr->x.pSelect;
sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
if( pExpr->op==TK_SELECT ){
dest.eDest = SRT_Mem;
@ -1795,7 +1995,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
break;
}
case TK_STRING: {
sqlite3DequoteExpr(db, pExpr);
sqlite3DequoteExpr(pExpr);
sqlite3VdbeAddOp4(v,OP_String8, 0, target, 0,
(char*)pExpr->token.z, pExpr->token.n);
break;
@ -1821,9 +2021,26 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
#endif
case TK_VARIABLE: {
sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iTable, target);
if( pExpr->token.n>1 ){
sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);
int iPrior;
VdbeOp *pOp;
if( pExpr->token.n<=1
&& (iPrior = sqlite3VdbeCurrentAddr(v)-1)>=0
&& (pOp = sqlite3VdbeGetOp(v, iPrior))->opcode==OP_Variable
&& pOp->p1+pOp->p3==pExpr->iTable
&& pOp->p2+pOp->p3==target
&& pOp->p4.z==0
){
/* If the previous instruction was a copy of the previous unnamed
** parameter into the previous register, then simply increment the
** repeat count on the prior instruction rather than making a new
** instruction.
*/
pOp->p3++;
}else{
sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iTable, target, 1);
if( pExpr->token.n>1 ){
sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);
}
}
break;
}
@ -1985,7 +2202,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pList = pExpr->pList;
ExprList *pList = (
ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanOnly) ? 0 : pExpr->x.pList
);
int nExpr = pList ? pList->nExpr : 0;
FuncDef *pDef;
int nId;
@ -1995,6 +2214,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
u8 enc = ENC(db);
CollSeq *pColl = 0;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
testcase( op==TK_CONST_FUNC );
testcase( op==TK_FUNCTION );
zId = (char*)pExpr->token.z;
@ -2162,7 +2382,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
*/
case TK_BETWEEN: {
Expr *pLeft = pExpr->pLeft;
struct ExprList_item *pLItem = pExpr->pList->a;
struct ExprList_item *pLItem = pExpr->x.pList->a;
Expr *pRight = pLItem->pExpr;
codeCompareOperands(pParse, pLeft, &r1, &regFree1,
@ -2222,10 +2442,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
Expr *pX; /* The X expression */
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
assert(pExpr->pList);
assert((pExpr->pList->nExpr % 2) == 0);
assert(pExpr->pList->nExpr > 0);
pEList = pExpr->pList;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
assert((pExpr->x.pList->nExpr % 2) == 0);
assert(pExpr->x.pList->nExpr > 0);
pEList = pExpr->x.pList;
aListelem = pEList->a;
nExpr = pEList->nExpr;
endLabel = sqlite3VdbeMakeLabel(v);
@ -2273,15 +2493,15 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
"RAISE() may only be used within a trigger-program");
return 0;
}
if( pExpr->iColumn!=OE_Ignore ){
assert( pExpr->iColumn==OE_Rollback ||
pExpr->iColumn == OE_Abort ||
pExpr->iColumn == OE_Fail );
sqlite3DequoteExpr(db, pExpr);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, 0,
if( pExpr->affinity!=OE_Ignore ){
assert( pExpr->affinity==OE_Rollback ||
pExpr->affinity == OE_Abort ||
pExpr->affinity == OE_Fail );
sqlite3DequoteExpr(pExpr);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->affinity, 0,
(char*)pExpr->token.z, pExpr->token.n);
} else {
assert( pExpr->iColumn == OE_Ignore );
assert( pExpr->affinity == OE_Ignore );
sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
VdbeComment((v, "raise(IGNORE)"));
@ -2438,7 +2658,8 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
** Mark them this way to avoid generated unneeded OP_SCopy
** instructions.
*/
ExprList *pList = pExpr->pList;
ExprList *pList = pExpr->x.pList;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
if( pList ){
int i = pList->nExpr;
struct ExprList_item *pItem = pList->a;
@ -2614,16 +2835,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Expr compRight;
Expr exprX;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
exprX = *pExpr->pLeft;
exprAnd.op = TK_AND;
exprAnd.pLeft = &compLeft;
exprAnd.pRight = &compRight;
compLeft.op = TK_GE;
compLeft.pLeft = &exprX;
compLeft.pRight = pExpr->pList->a[0].pExpr;
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
compRight.op = TK_LE;
compRight.pLeft = &exprX;
compRight.pRight = pExpr->pList->a[1].pExpr;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
testcase( regFree1==0 );
exprX.op = TK_REGISTER;
@ -2765,16 +2987,17 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Expr compRight;
Expr exprX;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
exprX = *pExpr->pLeft;
exprAnd.op = TK_AND;
exprAnd.pLeft = &compLeft;
exprAnd.pRight = &compRight;
compLeft.op = TK_GE;
compLeft.pLeft = &exprX;
compLeft.pRight = pExpr->pList->a[0].pExpr;
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
compRight.op = TK_LE;
compRight.pLeft = &exprX;
compRight.pRight = pExpr->pList->a[1].pExpr;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
testcase( regFree1==0 );
exprX.op = TK_REGISTER;
@ -2813,22 +3036,25 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( pA==0||pB==0 ){
return pB==pA;
}
if( pA->op!=pB->op ) return 0;
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
if( pA->pList ){
if( pB->pList==0 ) return 0;
if( pA->pList->nExpr!=pB->pList->nExpr ) return 0;
for(i=0; i<pA->pList->nExpr; i++){
if( !sqlite3ExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){
return 0;
}
}
}else if( pB->pList ){
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
return 0;
}
if( pA->pSelect || pB->pSelect ) return 0;
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
if( pA->op!=pB->op ) return 0;
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
if( pA->x.pList && pB->x.pList ){
if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 0;
for(i=0; i<pA->x.pList->nExpr; i++){
Expr *pExprA = pA->x.pList->a[i].pExpr;
Expr *pExprB = pB->x.pList->a[i].pExpr;
if( !sqlite3ExprCompare(pExprA, pExprB) ) return 0;
}
}else if( pA->x.pList || pB->x.pList ){
return 0;
}
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
if( pA->op!=TK_COLUMN && pA->token.z ){
if( pB->token.z==0 ) return 0;
@ -2976,12 +3202,13 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db);
i = addAggInfoFunc(pParse->db, pAggInfo);
if( i>=0 ){
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
pItem->pExpr = pExpr;
pItem->iMem = ++pParse->nMem;
pItem->pFunc = sqlite3FindFunction(pParse->db,
(char*)pExpr->token.z, pExpr->token.n,
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
}else{

4
fts3.c
View file

@ -6410,7 +6410,7 @@ static void optimizeFunc(sqlite3_context *pContext,
i++;
}
/* If we managed to succesfully read them all, optimize them. */
/* If we managed to successfully read them all, optimize them. */
if( rc==SQLITE_DONE ){
assert( i==nReaders );
rc = optimizeInternal(v, readers, nReaders, &writer);
@ -7001,7 +7001,7 @@ int sqlite3Fts3Init(sqlite3 *db){
);
}
/* An error has occured. Delete the hash table and return the error code. */
/* An error has occurred. Delete the hash table and return the error code. */
assert( rc!=SQLITE_OK );
if( pHash ){
sqlite3Fts3HashClear(pHash);

View file

@ -212,8 +212,6 @@ static int getNextString(
if( ii==0 ){
memset(p, 0, nByte);
p->pPhrase = (Fts3Phrase *)&p[1];
p->eType = FTSQUERY_PHRASE;
p->pPhrase->iColumn = pParse->iDefaultCol;
}
p->pPhrase = (Fts3Phrase *)&p[1];
p->pPhrase->nToken = ii+1;
@ -237,19 +235,25 @@ static int getNextString(
char *zNew;
int nNew = 0;
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
nByte += (p->pPhrase->nToken-1) * sizeof(struct PhraseToken);
nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(struct PhraseToken);
p = fts3ReallocOrFree(p, nByte + nTemp);
if( !p ){
goto no_mem;
}
if( zTemp ){
zNew = &(((char *)p)[nByte]);
memcpy(zNew, zTemp, nTemp);
}else{
memset(p, 0, nByte+nTemp);
}
p->pPhrase = (Fts3Phrase *)&p[1];
zNew = &(((char *)p)[nByte]);
memcpy(zNew, zTemp, nTemp);
for(jj=0; jj<p->pPhrase->nToken; jj++){
p->pPhrase->aToken[jj].z = &zNew[nNew];
nNew += p->pPhrase->aToken[jj].n;
}
sqlite3_free(zTemp);
p->eType = FTSQUERY_PHRASE;
p->pPhrase->iColumn = pParse->iDefaultCol;
rc = SQLITE_OK;
}

20
func.c
View file

@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.222 2009/02/04 03:59:25 shane Exp $
** $Id: func.c,v 1.225 2009/03/27 15:26:03 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -1305,9 +1305,9 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
}else{
pInfo = (struct compareInfo*)&likeInfoNorm;
}
sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
sqlite3CreateFunc(db, "like", 2, SQLITE_ANY, pInfo, likeFunc, 0, 0);
sqlite3CreateFunc(db, "like", 3, SQLITE_ANY, pInfo, likeFunc, 0, 0);
sqlite3CreateFunc(db, "glob", 2, SQLITE_ANY,
(struct compareInfo*)&globInfo, likeFunc, 0,0);
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
setLikeOptFlag(db, "like",
@ -1323,12 +1323,13 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
if( pExpr->op!=TK_FUNCTION || !pExpr->pList ){
return 0;
}
if( pExpr->pList->nExpr!=2 ){
if( pExpr->op!=TK_FUNCTION
|| !pExpr->x.pList
|| pExpr->x.pList->nExpr!=2
){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
SQLITE_UTF8, 0);
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
@ -1412,7 +1413,8 @@ void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
AGGREGATE(count, 0, 0, 0, countStep, countFinalize ),
/* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */
{0,SQLITE_UTF8,SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0},
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),

View file

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.256 2008/12/10 21:19:57 drh Exp $
** $Id: insert.c,v 1.260 2009/02/28 10:47:42 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -168,7 +168,7 @@ static int autoIncBegin(
if( pTab->tabFlags & TF_Autoincrement ){
Vdbe *v = pParse->pVdbe;
Db *pDb = &pParse->db->aDb[iDb];
int iCur = pParse->nTab;
int iCur = pParse->nTab++;
int addr; /* Address of the top of the loop */
assert( v );
pParse->nMem++; /* Holds name of table */
@ -217,7 +217,7 @@ static void autoIncEnd(
int memId /* Memory cell holding the maximum rowid */
){
if( pTab->tabFlags & TF_Autoincrement ){
int iCur = pParse->nTab;
int iCur = pParse->nTab++;
Vdbe *v = pParse->pVdbe;
Db *pDb = &pParse->db->aDb[iDb];
int j1;
@ -401,7 +401,8 @@ void sqlite3Insert(
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to insert into a view */
int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
Trigger *pTrigger; /* List of triggers on pTab, if required */
int tmask; /* Mask of trigger times */
#endif
db = pParse->db;
@ -431,22 +432,24 @@ void sqlite3Insert(
** inserted into is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pTab, TK_INSERT, 0);
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define pTrigger 0
# define tmask 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
/* Ensure that:
* (a) the table is not read-only,
* (b) that if it is a view then ON INSERT triggers exist
*/
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
goto insert_cleanup;
}
assert( pTab!=0 );
@ -464,10 +467,10 @@ void sqlite3Insert(
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto insert_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, iDb);
sqlite3BeginWriteOperation(pParse, pSelect || pTrigger, iDb);
/* if there are row triggers, allocate a temp table for new.* references. */
if( triggers_exist ){
if( pTrigger ){
newIdx = pParse->nTab++;
}
@ -482,7 +485,7 @@ void sqlite3Insert(
** This is the 2nd template.
*/
if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
assert( !triggers_exist );
assert( !pTrigger );
assert( pList==0 );
goto insert_cleanup;
}
@ -557,7 +560,7 @@ void sqlite3Insert(
** of the tables being read by the SELECT statement. Also use a
** temp table in the case of row triggers.
*/
if( triggers_exist || readsTable(v, addrSelect, iDb, pTab) ){
if( pTrigger || readsTable(v, addrSelect, iDb, pTab) ){
useTempTable = 1;
}
@ -676,9 +679,8 @@ void sqlite3Insert(
/* Open the temp table for FOR EACH ROW triggers
*/
if( triggers_exist ){
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
if( pTrigger ){
sqlite3VdbeAddOp3(v, OP_OpenPseudo, newIdx, 0, pTab->nCol);
}
/* Initialize the count of rows to be inserted
@ -745,7 +747,7 @@ void sqlite3Insert(
/* Run the BEFORE and INSTEAD OF triggers, if there are any
*/
endOfLoop = sqlite3VdbeMakeLabel(v);
if( triggers_exist & TRIGGER_BEFORE ){
if( tmask & TRIGGER_BEFORE ){
int regTrigRowid;
int regCols;
int regRec;
@ -813,8 +815,8 @@ void sqlite3Insert(
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
/* Fire BEFORE or INSTEAD OF triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab,
newIdx, -1, onError, endOfLoop, 0, 0) ){
if( sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
pTab, newIdx, -1, onError, endOfLoop, 0, 0) ){
goto insert_cleanup;
}
}
@ -936,7 +938,7 @@ void sqlite3Insert(
regIns,
aRegIdx,
0,
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
(tmask&TRIGGER_AFTER) ? newIdx : -1,
appendFlag
);
}
@ -948,10 +950,10 @@ void sqlite3Insert(
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
if( triggers_exist ){
if( pTrigger ){
/* Code AFTER triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
newIdx, -1, onError, endOfLoop, 0, 0) ){
if( sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
pTab, newIdx, -1, onError, endOfLoop, 0, 0) ){
goto insert_cleanup;
}
}
@ -1125,7 +1127,6 @@ void sqlite3GenerateConstraintChecks(
if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
onError = OE_Abort;
}
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i);
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace );
switch( onError ){
@ -1133,22 +1134,24 @@ void sqlite3GenerateConstraintChecks(
case OE_Abort:
case OE_Fail: {
char *zMsg;
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError);
j1 = sqlite3VdbeAddOp3(v, OP_HaltIfNull,
SQLITE_CONSTRAINT, onError, regData+i);
zMsg = sqlite3MPrintf(pParse->db, "%s.%s may not be NULL",
pTab->zName, pTab->aCol[i].zName);
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
break;
}
case OE_Ignore: {
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
sqlite3VdbeAddOp2(v, OP_IsNull, regData+i, ignoreDest);
break;
}
case OE_Replace: {
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i);
sqlite3VdbeJumpHere(v, j1);
break;
}
}
sqlite3VdbeJumpHere(v, j1);
}
/* Test all CHECK constraints
@ -1530,7 +1533,7 @@ static int xferOptimization(
if( pSelect==0 ){
return 0; /* Must be of the form INSERT INTO ... SELECT ... */
}
if( pDest->pTrigger ){
if( sqlite3TriggerList(pParse, pDest) ){
return 0; /* tab1 must not have triggers */
}
#ifndef SQLITE_OMIT_VIRTUALTABLE

View file

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: legacy.c,v 1.31 2009/01/20 16:53:40 danielk1977 Exp $
** $Id: legacy.c,v 1.32 2009/03/19 18:51:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -101,7 +101,7 @@ int sqlite3_exec(
}
if( xCallback(pArg, nCol, azVals, azCols) ){
rc = SQLITE_ABORT;
sqlite3_finalize(pStmt);
sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
sqlite3Error(db, SQLITE_ABORT, 0);
goto exec_out;
@ -109,7 +109,7 @@ int sqlite3_exec(
}
if( rc!=SQLITE_ROW ){
rc = sqlite3_finalize(pStmt);
rc = sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
if( rc!=SQLITE_SCHEMA ){
nRetry = 0;
@ -125,7 +125,7 @@ int sqlite3_exec(
}
exec_out:
if( pStmt ) sqlite3_finalize(pStmt);
if( pStmt ) sqlite3VdbeFinalize((Vdbe *)pStmt);
sqlite3DbFree(db, azCols);
rc = sqlite3ApiExit(db, rc);

85
main.c
View file

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.528 2009/02/05 16:31:46 drh Exp $
** $Id: main.c,v 1.534 2009/03/23 04:33:32 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -404,12 +404,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
sz = 0;
pStart = 0;
}else if( pBuf==0 ){
sz = (sz + 7)&~7;
sz = ROUND8(sz);
sqlite3BeginBenignMalloc();
pStart = sqlite3Malloc( sz*cnt );
sqlite3EndBenignMalloc();
}else{
sz = sz&~7;
sz = ROUNDDOWN8(sz);
pStart = pBuf;
}
db->lookaside.pStart = pStart;
@ -560,6 +560,7 @@ void sqlite3CloseSavepoints(sqlite3 *db){
sqlite3DbFree(db, pTmp);
}
db->nSavepoint = 0;
db->nStatement = 0;
db->isTransactionSavepoint = 0;
}
@ -629,6 +630,12 @@ int sqlite3_close(sqlite3 *db){
}
}
sqlite3ResetInternalSchema(db, 0);
/* Tell the code in notify.c that the connection no longer holds any
** locks and does not require any further unlock-notify callbacks.
*/
sqlite3ConnectionClosed(db);
assert( db->nDb<=2 );
assert( db->aDb==db->aDbStatic );
for(j=0; j<ArraySize(db->aFunc.a); j++){
@ -1238,15 +1245,15 @@ const char *sqlite3_errmsg(sqlite3 *db){
if( !sqlite3SafetyCheckSickOrOk(db) ){
return sqlite3ErrStr(SQLITE_MISUSE);
}
if( db->mallocFailed ){
return sqlite3ErrStr(SQLITE_NOMEM);
}
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
z = (char*)sqlite3_value_text(db->pErr);
assert( !db->mallocFailed );
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
if( db->mallocFailed ){
z = sqlite3ErrStr(SQLITE_NOMEM);
}else{
z = (char*)sqlite3_value_text(db->pErr);
assert( !db->mallocFailed );
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
}
}
sqlite3_mutex_leave(db->mutex);
return z;
@ -1258,46 +1265,42 @@ const char *sqlite3_errmsg(sqlite3 *db){
** error.
*/
const void *sqlite3_errmsg16(sqlite3 *db){
/* Because all the characters in the string are in the unicode
** range 0x00-0xFF, if we pad the big-endian string with a
** zero byte, we can obtain the little-endian string with
** &big_endian[1].
*/
static const char outOfMemBe[] = {
0, 'o', 0, 'u', 0, 't', 0, ' ',
0, 'o', 0, 'f', 0, ' ',
0, 'm', 0, 'e', 0, 'm', 0, 'o', 0, 'r', 0, 'y', 0, 0, 0
static const u16 outOfMem[] = {
'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0
};
static const char misuseBe [] = {
0, 'l', 0, 'i', 0, 'b', 0, 'r', 0, 'a', 0, 'r', 0, 'y', 0, ' ',
0, 'r', 0, 'o', 0, 'u', 0, 't', 0, 'i', 0, 'n', 0, 'e', 0, ' ',
0, 'c', 0, 'a', 0, 'l', 0, 'l', 0, 'e', 0, 'd', 0, ' ',
0, 'o', 0, 'u', 0, 't', 0, ' ',
0, 'o', 0, 'f', 0, ' ',
0, 's', 0, 'e', 0, 'q', 0, 'u', 0, 'e', 0, 'n', 0, 'c', 0, 'e', 0, 0, 0
static const u16 misuse[] = {
'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ',
'r', 'o', 'u', 't', 'i', 'n', 'e', ' ',
'c', 'a', 'l', 'l', 'e', 'd', ' ',
'o', 'u', 't', ' ',
'o', 'f', ' ',
's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0
};
const void *z;
if( !db ){
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
return (void *)outOfMem;
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
return (void *)misuse;
}
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
SQLITE_UTF8, SQLITE_STATIC);
if( db->mallocFailed ){
z = (void *)outOfMem;
}else{
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
SQLITE_UTF8, SQLITE_STATIC);
z = sqlite3_value_text16(db->pErr);
}
/* A malloc() may have failed within the call to sqlite3_value_text16()
** above. If this is the case, then the db->mallocFailed flag needs to
** be cleared before returning. Do this directly, instead of via
** sqlite3ApiExit(), to avoid setting the database handle error message.
*/
db->mallocFailed = 0;
}
/* A malloc() may have failed within the call to sqlite3_value_text16()
** above. If this is the case, then the db->mallocFailed flag needs to
** be cleared before returning. Do this directly, instead of via
** sqlite3ApiExit(), to avoid setting the database handle error message.
*/
db->mallocFailed = 0;
sqlite3_mutex_leave(db->mutex);
return z;
}
@ -1940,7 +1943,6 @@ int sqlite3_table_column_metadata(
(void)sqlite3SafetyOn(db);
sqlite3BtreeEnterAll(db);
rc = sqlite3Init(db, &zErrMsg);
sqlite3BtreeLeaveAll(db);
if( SQLITE_OK!=rc ){
goto error_out;
}
@ -1996,6 +1998,7 @@ int sqlite3_table_column_metadata(
}
error_out:
sqlite3BtreeLeaveAll(db);
(void)sqlite3SafetyOff(db);
/* Whether the function call succeeded or failed, set the output parameters

104
malloc.c
View file

@ -12,7 +12,7 @@
**
** Memory allocation functions used throughout sqlite.
**
** $Id: malloc.c,v 1.56 2009/02/17 18:37:29 drh Exp $
** $Id: malloc.c,v 1.61 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@ -121,7 +121,7 @@ int sqlite3MallocInit(void){
if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
&& sqlite3GlobalConfig.nScratch>=0 ){
int i;
sqlite3GlobalConfig.szScratch = (sqlite3GlobalConfig.szScratch - 4) & ~7;
sqlite3GlobalConfig.szScratch = ROUNDDOWN8(sqlite3GlobalConfig.szScratch-4);
mem0.aScratchFree = (u32*)&((char*)sqlite3GlobalConfig.pScratch)
[sqlite3GlobalConfig.szScratch*sqlite3GlobalConfig.nScratch];
for(i=0; i<sqlite3GlobalConfig.nScratch; i++){ mem0.aScratchFree[i] = i; }
@ -134,7 +134,7 @@ int sqlite3MallocInit(void){
&& sqlite3GlobalConfig.nPage>=1 ){
int i;
int overhead;
int sz = sqlite3GlobalConfig.szPage & ~7;
int sz = ROUNDDOWN8(sqlite3GlobalConfig.szPage);
int n = sqlite3GlobalConfig.nPage;
overhead = (4*n + sz - 1)/sz;
sqlite3GlobalConfig.nPage -= overhead;
@ -407,95 +407,6 @@ void sqlite3ScratchFree(void *p){
}
}
/*
** Allocate memory to be used by the page cache. Make use of the
** memory buffer provided by SQLITE_CONFIG_PAGECACHE if there is one
** and that memory is of the right size and is not completely
** consumed. Otherwise, failover to sqlite3Malloc().
*/
#if 0
void *sqlite3PageMalloc(int n){
void *p;
assert( n>0 );
assert( (n & (n-1))==0 );
assert( n>=512 && n<=32768 );
if( sqlite3GlobalConfig.szPage<n ){
goto page_overflow;
}else{
sqlite3_mutex_enter(mem0.mutex);
if( mem0.nPageFree==0 ){
sqlite3_mutex_leave(mem0.mutex);
goto page_overflow;
}else{
int i;
i = mem0.aPageFree[--mem0.nPageFree];
sqlite3_mutex_leave(mem0.mutex);
i *= sqlite3GlobalConfig.szPage;
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, n);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
p = (void*)&((char*)sqlite3GlobalConfig.pPage)[i];
}
}
return p;
page_overflow:
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, n);
n = mallocWithAlarm(n, &p);
if( p ) sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, n);
sqlite3_mutex_leave(mem0.mutex);
}else{
p = sqlite3GlobalConfig.m.xMalloc(n);
}
return p;
}
void sqlite3PageFree(void *p){
if( p ){
if( sqlite3GlobalConfig.pPage==0
|| p<sqlite3GlobalConfig.pPage
|| p>=(void*)mem0.aPageFree ){
/* In this case, the page allocation was obtained from a regular
** call to sqlite3_mem_methods.xMalloc() (a page-cache-memory
** "overflow"). Free the block with sqlite3_mem_methods.xFree().
*/
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3GlobalConfig.m.xFree(p);
}
}else{
/* The page allocation was allocated from the sqlite3GlobalConfig.pPage
** buffer. In this case all that is add the index of the page in
** the sqlite3GlobalConfig.pPage array to the set of free indexes stored
** in the mem0.aPageFree[] array.
*/
int i;
i = (u8 *)p - (u8 *)sqlite3GlobalConfig.pPage;
i /= sqlite3GlobalConfig.szPage;
assert( i>=0 && i<sqlite3GlobalConfig.nPage );
sqlite3_mutex_enter(mem0.mutex);
assert( mem0.nPageFree<sqlite3GlobalConfig.nPage );
mem0.aPageFree[mem0.nPageFree++] = i;
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
sqlite3_mutex_leave(mem0.mutex);
#if !defined(NDEBUG) && 0
/* Assert that a duplicate was not just inserted into aPageFree[]. */
for(i=0; i<mem0.nPageFree-1; i++){
assert( mem0.aPageFree[i]!=mem0.aPageFree[mem0.nPageFree-1] );
}
#endif
}
}
}
#endif
/*
** TRUE if p is a lookaside memory allocation from db
*/
@ -515,6 +426,7 @@ int sqlite3MallocSize(void *p){
return sqlite3GlobalConfig.m.xSize(p);
}
int sqlite3DbMallocSize(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( p==0 ){
return 0;
}else if( isLookaside(db, p) ){
@ -544,6 +456,7 @@ void sqlite3_free(void *p){
** connection.
*/
void sqlite3DbFree(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( isLookaside(db, p) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
pBuf->pNext = db->lookaside.pFree;
@ -652,6 +565,7 @@ void *sqlite3DbMallocZero(sqlite3 *db, int n){
*/
void *sqlite3DbMallocRaw(sqlite3 *db, int n){
void *p;
assert( db==0 || sqlite3_mutex_held(db->mutex) );
#ifndef SQLITE_OMIT_LOOKASIDE
if( db ){
LookasideSlot *pBuf;
@ -686,6 +600,8 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){
*/
void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
void *pNew = 0;
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
if( db->mallocFailed==0 ){
if( p==0 ){
return sqlite3DbMallocRaw(db, n);
@ -780,10 +696,10 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat, ...){
** sqlite3_realloc.
**
** The returned value is normally a copy of the second argument to this
** function. However, if a malloc() failure has occured since the previous
** function. However, if a malloc() failure has occurred since the previous
** invocation SQLITE_NOMEM is returned instead.
**
** If the first argument, db, is not NULL and a malloc() error has occured,
** If the first argument, db, is not NULL and a malloc() error has occurred,
** then the connection error-code (the value returned by sqlite3_errcode())
** is set to SQLITE_NOMEM.
*/

8
mem1.c
View file

@ -17,7 +17,7 @@
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
**
** $Id: mem1.c,v 1.29 2008/12/10 21:19:57 drh Exp $
** $Id: mem1.c,v 1.30 2009/03/23 04:33:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -39,7 +39,7 @@
static void *sqlite3MemMalloc(int nByte){
sqlite3_int64 *p;
assert( nByte>0 );
nByte = (nByte+7)&~7;
nByte = ROUND8(nByte);
p = malloc( nByte+8 );
if( p ){
p[0] = nByte;
@ -76,7 +76,7 @@ static void sqlite3MemFree(void *pPrior){
static void *sqlite3MemRealloc(void *pPrior, int nByte){
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 && nByte>0 );
nByte = (nByte+7)&~7;
nByte = ROUND8(nByte);
p = (sqlite3_int64*)pPrior;
p--;
p = realloc(p, nByte+8 );
@ -103,7 +103,7 @@ static int sqlite3MemSize(void *pPrior){
** Round up a request size to the next valid allocation size.
*/
static int sqlite3MemRoundup(int n){
return (n+7) & ~7;
return ROUND8(n);
}
/*

13
mem2.c
View file

@ -19,7 +19,7 @@
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
**
** $Id: mem2.c,v 1.43 2009/02/05 03:00:06 shane Exp $
** $Id: mem2.c,v 1.45 2009/03/23 04:33:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -128,7 +128,7 @@ static struct {
** Adjust memory usage statistics
*/
static void adjustStats(int iSize, int increment){
int i = ((iSize+7)&~7)/8;
int i = ROUND8(iSize)/8;
if( i>NCSIZE-1 ){
i = NCSIZE - 1;
}
@ -159,7 +159,7 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
p = (struct MemBlockHdr*)pAllocation;
p--;
assert( p->iForeGuard==(int)FOREGUARD );
nReserve = (p->iSize+7)&~7;
nReserve = ROUND8(p->iSize);
pInt = (int*)pAllocation;
pU8 = (u8*)pAllocation;
assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD );
@ -209,7 +209,7 @@ static void sqlite3MemShutdown(void *NotUsed){
** Round up a request size to the next valid allocation size.
*/
static int sqlite3MemRoundup(int n){
return (n+7) & ~7;
return ROUND8(n);
}
/*
@ -225,7 +225,7 @@ static void *sqlite3MemMalloc(int nByte){
int nReserve;
sqlite3_mutex_enter(mem.mutex);
assert( mem.disallow==0 );
nReserve = (nByte+7)&~7;
nReserve = ROUND8(nByte);
totalSize = nReserve + sizeof(*pHdr) + sizeof(int) +
mem.nBacktrace*sizeof(void*) + mem.nTitle;
p = malloc(totalSize);
@ -248,6 +248,7 @@ static void *sqlite3MemMalloc(int nByte){
void *aAddr[40];
pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
assert(pBt[0]);
if( mem.xBacktrace ){
mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
}
@ -371,7 +372,7 @@ void sqlite3MemdebugSettitle(const char *zTitle){
if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1;
memcpy(mem.zTitle, zTitle, n);
mem.zTitle[n] = 0;
mem.nTitle = (n+7)&~7;
mem.nTitle = ROUND8(n);
sqlite3_mutex_leave(mem.mutex);
}

309
notify.c Normal file
View file

@ -0,0 +1,309 @@
/*
** 2009 March 3
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains the implementation of the sqlite3_unlock_notify()
** API method and its associated functionality.
**
** $Id: notify.c,v 1.2 2009/03/25 16:51:43 drh Exp $
*/
#include "sqliteInt.h"
#include "btreeInt.h"
/* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/*
** Public interfaces:
**
** sqlite3ConnectionBlocked()
** sqlite3ConnectionUnlocked()
** sqlite3ConnectionClosed()
** sqlite3_unlock_notify()
*/
#define assertMutexHeld() \
assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
/*
** Head of a linked list of all sqlite3 objects created by this process
** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
** is not NULL. This variable may only accessed while the STATIC_MASTER
** mutex is held.
*/
static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
#ifndef NDEBUG
/*
** This function is a complex assert() that verifies the following
** properties of the blocked connections list:
**
** 1) Each entry in the list has a non-NULL value for either
** pUnlockConnection or pBlockingConnection, or both.
**
** 2) All entries in the list that share a common value for
** xUnlockNotify are grouped together.
**
** 3) If the argument db is not NULL, then none of the entries in the
** blocked connections list have pUnlockConnection or pBlockingConnection
** set to db. This is used when closing connection db.
*/
static void checkListProperties(sqlite3 *db){
sqlite3 *p;
for(p=sqlite3BlockedList; p; p=p->pNextBlocked){
int seen = 0;
sqlite3 *p2;
/* Verify property (1) */
assert( p->pUnlockConnection || p->pBlockingConnection );
/* Verify property (2) */
for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){
if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1;
assert( p2->xUnlockNotify==p->xUnlockNotify || !seen );
assert( db==0 || p->pUnlockConnection!=db );
assert( db==0 || p->pBlockingConnection!=db );
}
}
}
#else
# define checkListProperties(x)
#endif
/*
** Remove connection db from the blocked connections list. If connection
** db is not currently a part of the list, this function is a no-op.
*/
static void removeFromBlockedList(sqlite3 *db){
sqlite3 **pp;
assertMutexHeld();
for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){
if( *pp==db ){
*pp = (*pp)->pNextBlocked;
break;
}
}
}
/*
** Add connection db to the blocked connections list. It is assumed
** that it is not already a part of the list.
*/
static void addToBlockedList(sqlite3 *db){
sqlite3 **pp;
assertMutexHeld();
for(
pp=&sqlite3BlockedList;
*pp && (*pp)->xUnlockNotify!=db->xUnlockNotify;
pp=&(*pp)->pNextBlocked
);
db->pNextBlocked = *pp;
*pp = db;
}
/*
** Obtain the STATIC_MASTER mutex.
*/
static void enterMutex(){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
checkListProperties(0);
}
/*
** Release the STATIC_MASTER mutex.
*/
static void leaveMutex(){
assertMutexHeld();
checkListProperties(0);
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
/*
** Register an unlock-notify callback.
*/
int sqlite3_unlock_notify(
sqlite3 *db,
void (*xNotify)(void **, int),
void *pArg
){
int rc = SQLITE_OK;
sqlite3_mutex_enter(db->mutex);
enterMutex();
if( 0==db->pBlockingConnection ){
/* The blocking transaction has been concluded. Or there never was a
** blocking transaction. In either case, invoke the notify callback
** immediately.
*/
xNotify(&pArg, 1);
}else{
sqlite3 *p;
for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection);
if( p ){
rc = SQLITE_LOCKED; /* Deadlock detected. */
}else{
db->pUnlockConnection = db->pBlockingConnection;
db->xUnlockNotify = xNotify;
db->pUnlockArg = pArg;
removeFromBlockedList(db);
addToBlockedList(db);
}
}
leaveMutex();
assert( !db->mallocFailed );
sqlite3Error(db, rc, (rc?"database is deadlocked":0));
sqlite3_mutex_leave(db->mutex);
return rc;
}
/*
** This function is called while stepping or preparing a statement
** associated with connection db. The operation will return SQLITE_LOCKED
** to the user because it requires a lock that will not be available
** until connection pBlocker concludes its current transaction.
*/
void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){
enterMutex();
if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){
addToBlockedList(db);
}
db->pBlockingConnection = pBlocker;
leaveMutex();
}
/*
** The transaction opened by database db has just finished. Locks held
** by database connection db have been released.
**
** This function loops through each entry in the blocked connections
** list and does the following:
**
** 1) If the sqlite3.pBlockingConnection member of a list entry is
** set to db, then set pBlockingConnection=0.
**
** 2) If the sqlite3.pUnlockConnection member of a list entry is
** set to db, then invoke the configured unlock-notify callback and
** set pUnlockConnection=0.
**
** 3) If the two steps above mean that pBlockingConnection==0 and
** pUnlockConnection==0, remove the entry from the blocked connections
** list.
*/
void sqlite3ConnectionUnlocked(sqlite3 *db){
void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */
int nArg = 0; /* Number of entries in aArg[] */
sqlite3 **pp; /* Iterator variable */
void *aStatic[16];
void **aArg = aStatic;
void **aDyn = 0;
enterMutex(); /* Enter STATIC_MASTER mutex */
/* This loop runs once for each entry in the blocked-connections list. */
for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
sqlite3 *p = *pp;
/* Step 1. */
if( p->pBlockingConnection==db ){
p->pBlockingConnection = 0;
}
/* Step 2. */
if( p->pUnlockConnection==db ){
assert( p->xUnlockNotify );
if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){
xUnlockNotify(aArg, nArg);
nArg = 0;
}
sqlite3BeginBenignMalloc();
assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) );
assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn );
if( (!aDyn && nArg==(int)ArraySize(aStatic))
|| (aDyn && nArg==(int)(sqlite3DbMallocSize(db, aDyn)/sizeof(void*)))
){
/* The aArg[] array needs to grow. */
void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2);
if( pNew ){
memcpy(pNew, aArg, nArg*sizeof(void *));
sqlite3_free(aDyn);
aDyn = aArg = pNew;
}else{
/* This occurs when the array of context pointers that need to
** be passed to the unlock-notify callback is larger than the
** aStatic[] array allocated on the stack and the attempt to
** allocate a larger array from the heap has failed.
**
** This is a difficult situation to handle. Returning an error
** code to the caller is insufficient, as even if an error code
** is returned the transaction on connection db will still be
** closed and the unlock-notify callbacks on blocked connections
** will go unissued. This might cause the application to wait
** indefinitely for an unlock-notify callback that will never
** arrive.
**
** Instead, invoke the unlock-notify callback with the context
** array already accumulated. We can then clear the array and
** begin accumulating any further context pointers without
** requiring any dynamic allocation. This is sub-optimal because
** it means that instead of one callback with a large array of
** context pointers the application will receive two or more
** callbacks with smaller arrays of context pointers, which will
** reduce the applications ability to prioritize multiple
** connections. But it is the best that can be done under the
** circumstances.
*/
xUnlockNotify(aArg, nArg);
nArg = 0;
}
}
sqlite3EndBenignMalloc();
aArg[nArg++] = p->pUnlockArg;
xUnlockNotify = p->xUnlockNotify;
p->pUnlockConnection = 0;
p->xUnlockNotify = 0;
p->pUnlockArg = 0;
}
/* Step 3. */
if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){
/* Remove connection p from the blocked connections list. */
*pp = p->pNextBlocked;
p->pNextBlocked = 0;
}else{
pp = &p->pNextBlocked;
}
}
if( nArg!=0 ){
xUnlockNotify(aArg, nArg);
}
sqlite3_free(aDyn);
leaveMutex(); /* Leave STATIC_MASTER mutex */
}
/*
** This is called when the database connection passed as an argument is
** being closed. The connection is removed from the blocked list.
*/
void sqlite3ConnectionClosed(sqlite3 *db){
sqlite3ConnectionUnlocked(db);
enterMutex();
removeFromBlockedList(db);
checkListProperties(db);
leaveMutex();
}
#endif

202
opcodes.h
View file

@ -16,7 +16,7 @@
#define OP_RowKey 14
#define OP_IsUnique 15
#define OP_SetNumColumns 16
#define OP_Eq 73 /* same as TK_EQ */
#define OP_Eq 74 /* same as TK_EQ */
#define OP_VUpdate 17
#define OP_Expire 18
#define OP_NullRow 20
@ -43,103 +43,103 @@
#define OP_IdxDelete 41
#define OP_Sort 42
#define OP_ResetCount 43
#define OP_NotNull 71 /* same as TK_NOTNULL */
#define OP_Ge 77 /* same as TK_GE */
#define OP_Remainder 87 /* same as TK_REM */
#define OP_Divide 86 /* same as TK_SLASH */
#define OP_Integer 44
#define OP_Explain 45
#define OP_IncrVacuum 46
#define OP_AggStep 47
#define OP_CreateIndex 48
#define OP_NewRowid 49
#define OP_And 66 /* same as TK_AND */
#define OP_ShiftLeft 81 /* same as TK_LSHIFT */
#define OP_Count 44
#define OP_NotNull 72 /* same as TK_NOTNULL */
#define OP_Ge 78 /* same as TK_GE */
#define OP_Remainder 88 /* same as TK_REM */
#define OP_Divide 87 /* same as TK_SLASH */
#define OP_Integer 45
#define OP_Explain 46
#define OP_IncrVacuum 47
#define OP_AggStep 48
#define OP_CreateIndex 49
#define OP_NewRowid 50
#define OP_And 67 /* same as TK_AND */
#define OP_ShiftLeft 82 /* same as TK_LSHIFT */
#define OP_Real 130 /* same as TK_FLOAT */
#define OP_Return 50
#define OP_Trace 51
#define OP_IfPos 52
#define OP_IdxLT 53
#define OP_Rewind 54
#define OP_SeekGe 55
#define OP_Affinity 56
#define OP_Gt 74 /* same as TK_GT */
#define OP_AddImm 57
#define OP_Subtract 84 /* same as TK_MINUS */
#define OP_Null 58
#define OP_VColumn 59
#define OP_Clear 60
#define OP_IsNull 70 /* same as TK_ISNULL */
#define OP_If 61
#define OP_Permutation 62
#define OP_Return 51
#define OP_Trace 52
#define OP_IfPos 53
#define OP_IdxLT 54
#define OP_Rewind 55
#define OP_SeekGe 56
#define OP_Affinity 57
#define OP_Gt 75 /* same as TK_GT */
#define OP_AddImm 58
#define OP_Subtract 85 /* same as TK_MINUS */
#define OP_Null 59
#define OP_VColumn 60
#define OP_Clear 61
#define OP_IsNull 71 /* same as TK_ISNULL */
#define OP_If 62
#define OP_Permutation 63
#define OP_ToBlob 142 /* same as TK_TO_BLOB */
#define OP_RealAffinity 63
#define OP_Yield 64
#define OP_AggFinal 67
#define OP_IfZero 68
#define OP_Last 69
#define OP_Rowid 78
#define OP_Sequence 89
#define OP_NotFound 90
#define OP_SeekGt 91
#define OP_MakeRecord 94
#define OP_RealAffinity 64
#define OP_HaltIfNull 65
#define OP_Yield 68
#define OP_AggFinal 69
#define OP_IfZero 70
#define OP_Last 79
#define OP_Rowid 90
#define OP_Sequence 91
#define OP_NotFound 92
#define OP_SeekGt 95
#define OP_MakeRecord 96
#define OP_ToText 141 /* same as TK_TO_TEXT */
#define OP_BitAnd 79 /* same as TK_BITAND */
#define OP_Add 83 /* same as TK_PLUS */
#define OP_ResultRow 95
#define OP_String 96
#define OP_Goto 97
#define OP_Noop 98
#define OP_VCreate 99
#define OP_RowSetRead 100
#define OP_DropTable 101
#define OP_IdxRowid 102
#define OP_Insert 103
#define OP_Column 104
#define OP_BitAnd 80 /* same as TK_BITAND */
#define OP_Add 84 /* same as TK_PLUS */
#define OP_ResultRow 97
#define OP_String 98
#define OP_Goto 99
#define OP_Noop 100
#define OP_VCreate 101
#define OP_RowSetRead 102
#define OP_DropTable 103
#define OP_IdxRowid 104
#define OP_Insert 105
#define OP_Column 106
#define OP_Not 19 /* same as TK_NOT */
#define OP_Compare 105
#define OP_Le 75 /* same as TK_LE */
#define OP_BitOr 80 /* same as TK_BITOR */
#define OP_Multiply 85 /* same as TK_STAR */
#define OP_String8 93 /* same as TK_STRING */
#define OP_VOpen 106
#define OP_CreateTable 107
#define OP_Found 108
#define OP_Seek 109
#define OP_Close 110
#define OP_Savepoint 111
#define OP_Statement 112
#define OP_IfNot 113
#define OP_Compare 107
#define OP_Le 76 /* same as TK_LE */
#define OP_BitOr 81 /* same as TK_BITOR */
#define OP_Multiply 86 /* same as TK_STAR */
#define OP_String8 94 /* same as TK_STRING */
#define OP_VOpen 108
#define OP_CreateTable 109
#define OP_Found 110
#define OP_Seek 111
#define OP_Close 112
#define OP_Savepoint 113
#define OP_Statement 114
#define OP_IfNot 115
#define OP_ToInt 144 /* same as TK_TO_INT */
#define OP_VBegin 114
#define OP_MemMax 115
#define OP_Next 116
#define OP_Prev 117
#define OP_SeekLe 118
#define OP_Lt 76 /* same as TK_LT */
#define OP_Ne 72 /* same as TK_NE */
#define OP_MustBeInt 119
#define OP_ShiftRight 82 /* same as TK_RSHIFT */
#define OP_CollSeq 120
#define OP_Gosub 121
#define OP_ContextPush 122
#define OP_ParseSchema 123
#define OP_Destroy 124
#define OP_IdxGE 125
#define OP_ReadCookie 126
#define OP_BitNot 92 /* same as TK_BITNOT */
#define OP_Or 65 /* same as TK_OR */
#define OP_Jump 127
#define OP_VBegin 116
#define OP_MemMax 117
#define OP_Next 118
#define OP_Prev 119
#define OP_SeekLe 120
#define OP_Lt 77 /* same as TK_LT */
#define OP_Ne 73 /* same as TK_NE */
#define OP_MustBeInt 121
#define OP_ShiftRight 83 /* same as TK_RSHIFT */
#define OP_CollSeq 122
#define OP_Gosub 123
#define OP_ContextPush 124
#define OP_ParseSchema 125
#define OP_Destroy 126
#define OP_IdxGE 127
#define OP_ReadCookie 128
#define OP_BitNot 93 /* same as TK_BITNOT */
#define OP_Or 66 /* same as TK_OR */
#define OP_Jump 129
#define OP_ToReal 145 /* same as TK_TO_REAL */
#define OP_ToNumeric 143 /* same as TK_TO_NUMERIC*/
#define OP_Function 128
#define OP_Concat 88 /* same as TK_CONCAT */
#define OP_SCopy 129
#define OP_Int64 131
#define OP_Function 131
#define OP_Concat 89 /* same as TK_CONCAT */
#define OP_SCopy 132
#define OP_Int64 133
/* The following opcode values are never used */
#define OP_NotUsed_132 132
#define OP_NotUsed_133 133
#define OP_NotUsed_134 134
#define OP_NotUsed_135 135
#define OP_NotUsed_136 136
@ -164,18 +164,18 @@
/* 8 */ 0x08, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x11,\
/* 16 */ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,\
/* 24 */ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x11,\
/* 32 */ 0x10, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00, 0x08,\
/* 40 */ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\
/* 48 */ 0x02, 0x02, 0x04, 0x00, 0x05, 0x11, 0x01, 0x11,\
/* 56 */ 0x00, 0x04, 0x02, 0x00, 0x00, 0x05, 0x00, 0x04,\
/* 64 */ 0x04, 0x2c, 0x2c, 0x00, 0x05, 0x01, 0x05, 0x05,\
/* 72 */ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x02, 0x2c,\
/* 32 */ 0x10, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x08,\
/* 40 */ 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x00, 0x01,\
/* 48 */ 0x00, 0x02, 0x02, 0x04, 0x00, 0x05, 0x11, 0x01,\
/* 56 */ 0x11, 0x00, 0x04, 0x02, 0x00, 0x00, 0x05, 0x00,\
/* 64 */ 0x04, 0x10, 0x2c, 0x2c, 0x04, 0x00, 0x05, 0x05,\
/* 72 */ 0x05, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x01,\
/* 80 */ 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,\
/* 88 */ 0x2c, 0x02, 0x11, 0x11, 0x04, 0x02, 0x00, 0x00,\
/* 96 */ 0x02, 0x01, 0x00, 0x00, 0x21, 0x00, 0x02, 0x00,\
/* 104 */ 0x00, 0x00, 0x00, 0x02, 0x11, 0x08, 0x00, 0x00,\
/* 112 */ 0x00, 0x05, 0x00, 0x0c, 0x01, 0x01, 0x11, 0x05,\
/* 120 */ 0x00, 0x01, 0x00, 0x00, 0x02, 0x11, 0x02, 0x01,\
/* 128 */ 0x00, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\
/* 88 */ 0x2c, 0x2c, 0x02, 0x02, 0x11, 0x04, 0x02, 0x11,\
/* 96 */ 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x21, 0x00,\
/* 104 */ 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x11, 0x08,\
/* 112 */ 0x00, 0x00, 0x00, 0x05, 0x00, 0x0c, 0x01, 0x01,\
/* 120 */ 0x11, 0x05, 0x00, 0x01, 0x00, 0x00, 0x02, 0x11,\
/* 128 */ 0x02, 0x01, 0x02, 0x00, 0x04, 0x02, 0x00, 0x00,\
/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,\
/* 144 */ 0x04, 0x04,}

7
os.c
View file

@ -13,7 +13,7 @@
** This file contains OS interface code that is common to all
** architectures.
**
** $Id: os.c,v 1.125 2008/12/08 18:19:18 drh Exp $
** $Id: os.c,v 1.126 2009/03/25 14:24:42 drh Exp $
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
@ -112,8 +112,11 @@ int sqlite3OsOpen(
int flags,
int *pFlagsOut
){
int rc;
DO_OS_MALLOC_TEST;
return pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut);
rc = pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return pVfs->xDelete(pVfs, zPath, dirSync);

View file

@ -17,7 +17,7 @@
** This file should be #included by the os_*.c files only. It is not a
** general purpose header file.
**
** $Id: os_common.h,v 1.37 2008/05/29 20:22:37 shane Exp $
** $Id: os_common.h,v 1.38 2009/02/24 18:40:50 danielk1977 Exp $
*/
#ifndef _OS_COMMON_H_
#define _OS_COMMON_H_
@ -31,15 +31,6 @@
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
/*
* When testing, this global variable stores the location of the
* pending-byte in the database file.
*/
#ifdef SQLITE_TEST
unsigned int sqlite3_pending_byte = 0x40000000;
#endif
#ifdef SQLITE_DEBUG
int sqlite3OSTrace = 0;
#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)

View file

@ -43,7 +43,7 @@
** * Definitions of sqlite3_vfs objects for all locking methods
** plus implementations of sqlite3_os_init() and sqlite3_os_end().
**
** $Id: os_unix.c,v 1.241 2009/02/09 17:34:07 drh Exp $
** $Id: os_unix.c,v 1.248 2009/03/30 07:39:35 danielk1977 Exp $
*/
#include "sqliteInt.h"
#if SQLITE_OS_UNIX /* This file is used on unix only */
@ -1454,11 +1454,12 @@ static int unixUnlock(sqlite3_file *id, int locktype){
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
goto end_unlock;
goto end_unlock;
}
}
if( locktype==NO_LOCK ){
struct unixOpenCnt *pOpen;
int rc2 = SQLITE_OK;
/* Decrement the shared lock counter. Release the lock using an
** OS call only when all threads in this same process have released
@ -1480,8 +1481,8 @@ static int unixUnlock(sqlite3_file *id, int locktype){
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
pLock->cnt = 1;
goto end_unlock;
pLock->locktype = NO_LOCK;
pFile->locktype = NO_LOCK;
}
}
@ -1489,30 +1490,31 @@ static int unixUnlock(sqlite3_file *id, int locktype){
** count reaches zero, close any other file descriptors whose close
** was deferred because of outstanding locks.
*/
if( rc==SQLITE_OK ){
pOpen = pFile->pOpen;
pOpen->nLock--;
assert( pOpen->nLock>=0 );
if( pOpen->nLock==0 && pOpen->nPending>0 ){
int i;
for(i=0; i<pOpen->nPending; i++){
/* close pending fds, but if closing fails don't free the array
** assign -1 to the successfully closed descriptors and record the
** error. The next attempt to unlock will try again. */
if( pOpen->aPending[i] < 0 ) continue;
if( close(pOpen->aPending[i]) ){
pFile->lastErrno = errno;
rc = SQLITE_IOERR_CLOSE;
}else{
pOpen->aPending[i] = -1;
}
}
if( rc==SQLITE_OK ){
sqlite3_free(pOpen->aPending);
pOpen->nPending = 0;
pOpen->aPending = 0;
pOpen = pFile->pOpen;
pOpen->nLock--;
assert( pOpen->nLock>=0 );
if( pOpen->nLock==0 && pOpen->nPending>0 ){
int i;
for(i=0; i<pOpen->nPending; i++){
/* close pending fds, but if closing fails don't free the array
** assign -1 to the successfully closed descriptors and record the
** error. The next attempt to unlock will try again. */
if( pOpen->aPending[i] < 0 ) continue;
if( close(pOpen->aPending[i]) ){
pFile->lastErrno = errno;
rc2 = SQLITE_IOERR_CLOSE;
}else{
pOpen->aPending[i] = -1;
}
}
if( rc2==SQLITE_OK ){
sqlite3_free(pOpen->aPending);
pOpen->nPending = 0;
pOpen->aPending = 0;
}
}
if( rc==SQLITE_OK ){
rc = rc2;
}
}
@ -2824,10 +2826,12 @@ int sqlite3_fullsync_count = 0;
#endif
/*
** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined.
** Otherwise use fsync() in its place.
** We do not trust systems to provide a working fdatasync(). Some do.
** Others do no. To be safe, we will stick with the (slower) fsync().
** If you know that your system does support fdatasync() correctly,
** then simply compile with -Dfdatasync=fdatasync
*/
#ifndef HAVE_FDATASYNC
#if !defined(fdatasync) && !defined(__linux__)
# define fdatasync fsync
#endif
@ -2853,6 +2857,19 @@ int sqlite3_fullsync_count = 0;
** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
** or power failure will likely corrupt the database file.
**
** SQLite sets the dataOnly flag if the size of the file is unchanged.
** The idea behind dataOnly is that it should only write the file content
** to disk, not the inode. We only set dataOnly if the file size is
** unchanged since the file size is part of the inode. However,
** Ted Ts'o tells us that fdatasync() will also write the inode if the
** file size has changed. The only real difference between fdatasync()
** and fsync(), Ted tells us, is that fdatasync() will not flush the
** inode if the mtime or owner or other inode attributes have changed.
** We only care about the file size, not the other file attributes, so
** as far as SQLite is concerned, an fdatasync() is always adequate.
** So, we always use fdatasync() if it is available, regardless of
** the value of the dataOnly flag.
*/
static int full_fsync(int fd, int fullSync, int dataOnly){
int rc;
@ -2869,6 +2886,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
UNUSED_PARAMETER(dataOnly);
#else
UNUSED_PARAMETER(fullSync);
UNUSED_PARAMETER(dataOnly);
#endif
/* Record the number of times that we do a normal fsync() and
@ -2902,16 +2920,12 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
if( rc ) rc = fsync(fd);
#else
if( dataOnly ){
rc = fdatasync(fd);
rc = fdatasync(fd);
#if OS_VXWORKS
if( rc==-1 && errno==ENOTSUP ){
rc = fsync(fd);
}
#endif
}else{
if( rc==-1 && errno==ENOTSUP ){
rc = fsync(fd);
}
#endif /* OS_VXWORKS */
#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */
if( OS_VXWORKS && rc!= -1 ){
@ -3984,16 +3998,18 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
sp.tv_sec = microseconds / 1000000;
sp.tv_nsec = (microseconds % 1000000) * 1000;
nanosleep(&sp, NULL);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
usleep(microseconds);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#else
int seconds = (microseconds+999999)/1000000;
sleep(seconds);
UNUSED_PARAMETER(NotUsed);
return seconds*1000000;
#endif
UNUSED_PARAMETER(NotUsed);
}
/*

178
os_win.c
View file

@ -12,7 +12,7 @@
**
** This file contains code that is specific to windows.
**
** $Id: os_win.c,v 1.148 2009/02/05 03:16:21 shane Exp $
** $Id: os_win.c,v 1.153 2009/03/31 03:41:57 shane Exp $
*/
#include "sqliteInt.h"
#if SQLITE_OS_WIN /* This file is used for windows only */
@ -75,6 +75,7 @@
*/
#if SQLITE_OS_WINCE
# define AreFileApisANSI() 1
# define GetDiskFreeSpaceW() 0
#endif
/*
@ -101,6 +102,7 @@ struct winFile {
unsigned char locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
DWORD lastErrno; /* The Windows errno from the last I/O error */
DWORD sectorSize; /* Sector size of the device file is on */
#if SQLITE_OS_WINCE
WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
HANDLE hMutex; /* Mutex used to control access to shared lock */
@ -110,6 +112,13 @@ struct winFile {
#endif
};
/*
** Forward prototypes.
*/
static int getSectorSize(
sqlite3_vfs *pVfs,
const char *zRelative /* UTF-8 file name */
);
/*
** The following variable is (normally) set once and never changes
@ -135,7 +144,7 @@ static int sqlite3_os_type = 0;
**
** Here is an interesting observation: Win95, Win98, and WinME lack
** the LockFileEx() API. But we can still statically link against that
** API as long as we don't call it win running Win95/98/ME. A call to
** API as long as we don't call it when running Win95/98/ME. A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
@ -610,6 +619,8 @@ static BOOL winceLockFileEx(
static int winClose(sqlite3_file *id){
int rc, cnt = 0;
winFile *pFile = (winFile*)id;
assert( id!=0 );
OSTRACE2("CLOSE %d\n", pFile->h);
do{
rc = CloseHandle(pFile->h);
@ -654,9 +665,10 @@ static int winRead(
LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(offset & 0xffffffff);
DWORD rc;
DWORD got;
winFile *pFile = (winFile*)id;
DWORD error;
DWORD got;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype);
@ -691,9 +703,10 @@ static int winWrite(
LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(offset & 0xffffffff);
DWORD rc;
DWORD wrote = 0;
winFile *pFile = (winFile*)id;
DWORD error;
DWORD wrote = 0;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
@ -723,26 +736,26 @@ static int winWrite(
** Truncate an open file to a specified size
*/
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
DWORD rc;
LONG upperBits = (LONG)((nByte>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(nByte & 0xffffffff);
DWORD rc;
winFile *pFile = (winFile*)id;
DWORD error = NO_ERROR;
DWORD error;
assert( id!=0 );
OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte);
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( INVALID_SET_FILE_POINTER == rc ){
error = GetLastError();
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
return SQLITE_IOERR_TRUNCATE;
}
if( error == NO_ERROR ){
/* SetEndOfFile will fail if nByte is negative */
if( SetEndOfFile(pFile->h) ){
return SQLITE_OK;
}
error = GetLastError();
/* SetEndOfFile will fail if nByte is negative */
if( !SetEndOfFile(pFile->h) ){
pFile->lastErrno = GetLastError();
return SQLITE_IOERR_TRUNCATE;
}
pFile->lastErrno = error;
return SQLITE_IOERR_TRUNCATE;
return SQLITE_OK;
}
#ifdef SQLITE_TEST
@ -760,6 +773,8 @@ int sqlite3_fullsync_count = 0;
static int winSync(sqlite3_file *id, int flags){
#ifndef SQLITE_NO_SYNC
winFile *pFile = (winFile*)id;
assert( id!=0 );
OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype);
#else
UNUSED_PARAMETER(id);
@ -791,9 +806,12 @@ static int winSync(sqlite3_file *id, int flags){
** Determine the current size of a file in bytes
*/
static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
DWORD upperBits;
DWORD lowerBits;
winFile *pFile = (winFile*)id;
DWORD upperBits, lowerBits;
DWORD error;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_FSTAT);
lowerBits = GetFileSize(pFile->h, &upperBits);
if( (lowerBits == INVALID_FILE_SIZE)
@ -897,7 +915,7 @@ static int winLock(sqlite3_file *id, int locktype){
winFile *pFile = (winFile*)id;
DWORD error = NO_ERROR;
assert( pFile!=0 );
assert( id!=0 );
OSTRACE5("LOCK %d %d was %d(%d)\n",
pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
@ -1015,7 +1033,8 @@ static int winLock(sqlite3_file *id, int locktype){
static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
int rc;
winFile *pFile = (winFile*)id;
assert( pFile!=0 );
assert( id!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
@ -1100,8 +1119,8 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
** same for both.
*/
static int winSectorSize(sqlite3_file *id){
UNUSED_PARAMETER(id);
return SQLITE_DEFAULT_SECTOR_SIZE;
assert( id!=0 );
return (int)(((winFile*)id)->sectorSize);
}
/*
@ -1245,7 +1264,6 @@ static int getLastErrorMsg(int nBuf, char *zBuf){
return 0;
}
/*
** Open a file.
*/
@ -1269,6 +1287,7 @@ static int winOpen(
const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
char zTmpname[MAX_PATH+1]; /* Buffer used to create temp filename */
assert( id!=0 );
UNUSED_PARAMETER(pVfs);
/* If the second argument to this function is NULL, generate a
@ -1348,7 +1367,7 @@ static int winOpen(
if( h==INVALID_HANDLE_VALUE ){
free(zConverted);
if( flags & SQLITE_OPEN_READWRITE ){
return winOpen(0, zName, id,
return winOpen(pVfs, zName, id,
((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
}else{
return SQLITE_CANTOPEN;
@ -1365,6 +1384,7 @@ static int winOpen(
pFile->pMethod = &winIoMethod;
pFile->h = h;
pFile->lastErrno = NO_ERROR;
pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE
if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
(SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
@ -1556,6 +1576,73 @@ static int winFullPathname(
#endif
}
/*
** Get the sector size of the device used to store
** file.
*/
static int getSectorSize(
sqlite3_vfs *pVfs,
const char *zRelative /* UTF-8 file name */
){
DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
char zFullpath[MAX_PATH+1];
int rc;
DWORD dwRet = 0;
/*
** We need to get the full path name of the file
** to get the drive letter to look up the sector
** size.
*/
rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath);
if( rc == SQLITE_OK )
{
void *zConverted = convertUtf8Filename(zFullpath);
if( zConverted ){
if( isNT() ){
int i;
/* trim path to just drive reference */
WCHAR *p = zConverted;
for(i=0;i<MAX_PATH;i++){
if( p[i] == '\\' ){
i++;
p[i] = '\0';
break;
}
}
dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted,
NULL,
&bytesPerSector,
NULL,
NULL);
#if SQLITE_OS_WINCE==0
}else{
int i;
/* trim path to just drive reference */
CHAR *p = (CHAR *)zConverted;
for(i=0;i<MAX_PATH;i++){
if( p[i] == '\\' ){
i++;
p[i] = '\0';
break;
}
}
dwRet = GetDiskFreeSpaceA((CHAR*)zConverted,
NULL,
&bytesPerSector,
NULL,
NULL);
#endif
}
free(zConverted);
}
if( !dwRet ){
bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
}
}
return (int) bytesPerSector;
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
@ -1677,7 +1764,21 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
/* FILETIME structure is a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
sqlite3_int64 timeW, timeF;
sqlite3_int64 timeW; /* Whole days */
sqlite3_int64 timeF; /* Fractional Days */
/* Number of 100-nanosecond intervals in a single day */
static const sqlite3_int64 ntuPerDay =
10000000*(sqlite3_int64)86400;
/* Number of 100-nanosecond intervals in half of a day */
static const sqlite3_int64 ntuPerHalfDay =
10000000*(sqlite3_int64)43200;
/* 2^32 - to avoid use of LL and warnings in gcc */
static const sqlite3_int64 max32BitValue =
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
#if SQLITE_OS_WINCE
SYSTEMTIME time;
GetSystemTime(&time);
@ -1689,25 +1790,14 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
GetSystemTimeAsFileTime( &ft );
#endif
UNUSED_PARAMETER(pVfs);
#if defined(_MSC_VER)
timeW = (((sqlite3_int64)ft.dwHighDateTime)*4294967296) + ft.dwLowDateTime;
timeF = timeW % 864000000000; /* fractional days (100-nanoseconds) */
timeW = timeW / 864000000000; /* whole days */
timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
timeF = timeF + 432000000000; /* add half a day (from 2305813.5) */
timeW = timeW + (timeF / 864000000000); /* add whole day if half day made one */
timeF = timeF % 864000000000; /* compute new fractional days */
*prNow = (double)timeW + ((double)timeF / (double)864000000000);
#else
timeW = (((sqlite3_int64)ft.dwHighDateTime)*4294967296LL) + ft.dwLowDateTime;
timeF = timeW % 864000000000LL; /* fractional days (100-nanoseconds) */
timeW = timeW / 864000000000LL; /* whole days */
timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
timeF = timeF + 432000000000LL; /* add half a day (from 2305813.5) */
timeW = timeW + (timeF / 864000000000LL); /* add whole day if half day made one */
timeF = timeF % 864000000000LL; /* compute new fractional days */
*prNow = (double)timeW + ((double)timeF / (double)864000000000LL);
#endif
timeW = (((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime;
timeF = timeW % ntuPerDay; /* fractional days (100-nanoseconds) */
timeW = timeW / ntuPerDay; /* whole days */
timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
timeF = timeF + ntuPerHalfDay; /* add half a day (from 2305813.5) */
timeW = timeW + (timeF/ntuPerDay); /* add whole day if half day made one */
timeF = timeF % ntuPerDay; /* compute new fractional days */
*prNow = (double)timeW + ((double)timeF / (double)ntuPerDay);
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
*prNow = ((double)sqlite3_current_time + (double)43200) / (double)86400 + (double)2440587;
@ -1723,7 +1813,7 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
** function, SQLite calls this function with zBuf pointing to
** a buffer of nBuf bytes. The OS layer should populate the
** buffer with a nul-terminated UTF-8 encoded error message
** describing the last IO error to have occured within the calling
** describing the last IO error to have occurred within the calling
** thread.
**
** If the error message is too large for the supplied buffer,

101
pager.c
View file

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.570 2009/02/17 17:56:30 danielk1977 Exp $
** @(#) $Id: pager.c,v 1.576 2009/03/31 02:54:40 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
@ -99,12 +99,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
#define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */
#define PAGER_SYNCED 5
/*
** This macro rounds values up so that if the value is an address it
** is guaranteed to be an address that is aligned to an 8-byte boundary.
*/
#define FORCE_ALIGNMENT(X) (((X)+7)&~7)
/*
** A macro used for invoking the codec if there is one
*/
@ -762,7 +756,7 @@ static int writeJournalHdr(Pager *pPager){
** A faster alternative is to write 0xFFFFFFFF to the nRec field. When
** reading the journal this value tells SQLite to assume that the
** rest of the journal file contains valid page records. This assumption
** is dangerous, as if a failure occured whilst writing to the journal
** is dangerous, as if a failure occurred whilst writing to the journal
** file it may contain some garbage data. There are two scenarios
** where this risk can be ignored:
**
@ -1143,7 +1137,7 @@ static void pager_unlock(Pager *pPager){
/*
** This function should be called when an IOERR, CORRUPT or FULL error
** may have occured. The first argument is a pointer to the pager
** may have occurred. The first argument is a pointer to the pager
** structure, the second the error-code about to be returned by a pager
** API function. The value returned is a copy of the second argument
** to this function.
@ -1156,7 +1150,7 @@ static void pager_unlock(Pager *pPager){
** A persistent error indicates that the contents of the pager-cache
** cannot be trusted. This state can be cleared by completely discarding
** the contents of the pager-cache. If a transaction was active when
** the persistent error occured, then the rollback journal may need
** the persistent error occurred, then the rollback journal may need
** to be replayed to restore the contents of the database file (as if
** it were a hot-journal).
*/
@ -1505,6 +1499,7 @@ static int pager_playback_one_page(
** Do not attempt to write if database file has never been opened.
*/
pPg = pager_lookup(pPager, pgno);
assert( pPg || !MEMDB );
PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData),
(isMainJrnl?"main-journal":"sub-journal")
@ -2054,7 +2049,7 @@ end_playback:
);
/* If this playback is happening automatically as a result of an IO or
** malloc error that occured after the change-counter was updated but
** malloc error that occurred after the change-counter was updated but
** before the transaction was committed, then the change-counter
** modification may just have been reverted. If this happens in exclusive
** mode, then subsequent transactions performed by the connection will not
@ -3268,7 +3263,7 @@ int sqlite3PagerOpen(
testcase( rc!=SQLITE_OK );
}
/* If an error occured in either of the blocks above, free the
/* If an error occurred in either of the blocks above, free the
** Pager structure and close the file.
*/
if( rc!=SQLITE_OK ){
@ -3279,7 +3274,7 @@ int sqlite3PagerOpen(
}
/* Initialize the PCache object. */
nExtra = FORCE_ALIGNMENT(nExtra);
nExtra = ROUND8(nExtra);
sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
!memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
@ -3335,11 +3330,12 @@ int sqlite3PagerOpen(
** PAGER_SHARED state. It tests if there is a hot journal present in
** the file-system for the given pager. A hot journal is one that
** needs to be played back. According to this function, a hot-journal
** file exists if the following three criteria are met:
** file exists if the following criteria are met:
**
** * The journal file exists in the file system, and
** * No process holds a RESERVED or greater lock on the database file, and
** * The database file itself is greater than 0 bytes in size.
** * The database file itself is greater than 0 bytes in size, and
** * The first byte of the journal file exists and is not 0x00.
**
** If the current size of the database file is 0 but a journal file
** exists, that is probably an old journal left over from a prior
@ -3347,14 +3343,12 @@ int sqlite3PagerOpen(
** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
** is returned.
**
** This routine does not open the journal file to examine its
** content. Hence, the journal might contain the name of a master
** journal file that has been deleted, and hence not be hot. Or
** the header of the journal might be zeroed out. This routine
** does not discover these cases of a non-hot journal - if the
** journal file exists and is not empty this routine assumes it
** is hot. The pager_playback() routine will discover that the
** journal file is not really hot and will no-op.
** This routine does not check if there is a master journal filename
** at the end of the file. If there is, and that master journal file
** does not exist, then the journal file is not really hot. In this
** case this routine will return a false-positive. The pager_playback()
** routine will discover that the journal file is not really hot and
** will not roll it back.
**
** If a hot-journal file is found to exist, *pExists is set to 1 and
** SQLITE_OK returned. If no hot-journal file is present, *pExists is
@ -3365,29 +3359,52 @@ int sqlite3PagerOpen(
static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3_vfs * const pVfs = pPager->pVfs;
int rc; /* Return code */
int exists = 0; /* True if a journal file is present */
int locked = 0; /* True if some process holds a RESERVED lock */
int exists; /* True if a journal file is present */
assert( pPager!=0 );
assert( pPager->useJournal );
assert( isOpen(pPager->fd) );
assert( !isOpen(pPager->jfd) );
*pExists = 0;
rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
if( rc==SQLITE_OK && exists ){
int locked; /* True if some process holds a RESERVED lock */
rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
if( rc==SQLITE_OK && !locked ){
int nPage;
/* Check the size of the database file. If it consists of 0 pages,
** then delete the journal file. See the header comment above for
** the reasoning here.
*/
rc = sqlite3PagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK ){
if( nPage==0 ){
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
if( nPage==0 ){
rc = sqlite3OsDelete(pVfs, pPager->zJournal, 0);
}else{
*pExists = 1;
/* The journal file exists and no other connection has a reserved
** or greater lock on the database file. Now check that there is
** at least one non-zero bytes at the start of the journal file.
** If there is, then we consider this journal to be hot. If not,
** it can be ignored.
*/
int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
if( rc==SQLITE_OK ){
u8 first = 0;
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
sqlite3OsClose(pPager->jfd);
*pExists = (first!=0);
}
}
}
}
}
return rc;
}
@ -3413,10 +3430,13 @@ static int readDbPage(PgHdr *pPg){
if( !isOpen(pPager->fd) ){
assert( pPager->tempFile );
memset(pPg->pData, 0, pPager->pageSize);
return SQLITE_IOERR_SHORT_READ;
return SQLITE_OK;
}
iOffset = (pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
if( pgno==1 ){
u8 *dbFileVers = &((u8*)pPg->pData)[24];
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
@ -3800,7 +3820,7 @@ int sqlite3PagerAcquire(
}else{
assert( pPg->pPager==pPager );
rc = readDbPage(pPg);
if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
if( rc!=SQLITE_OK ){
pagerDropPage(pPg);
return rc;
}
@ -3933,7 +3953,7 @@ static int pager_open_journal(Pager *pPager){
sqlite3MemJournalOpen(pPager->jfd);
}else{
const int flags = /* VFS flags to open journal file */
SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE|
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
(pPager->tempFile ?
(SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
(SQLITE_OPEN_MAIN_JOURNAL)
@ -4135,7 +4155,7 @@ static int pager_write(PgHdr *pPg){
pPager->needSync = 1;
}
/* An error has occured writing to the journal file. The
/* An error has occurred writing to the journal file. The
** transaction will be rolled back by the layer above.
*/
if( rc!=SQLITE_OK ){
@ -4851,7 +4871,7 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE.
** If it is SAVEPOINT_RELEASE, then release and destroy the savepoint with
** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes
** that have occured since the specified savepoint was created.
** that have occurred since the specified savepoint was created.
**
** The savepoint to rollback or release is identified by parameter
** iSavepoint. A value of 0 means to operate on the outermost savepoint
@ -4997,6 +5017,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
PgHdr *pPgOld; /* The page being overwritten. */
Pgno needSyncPgno = 0; /* Old value of pPg->pgno, if sync is required */
int rc; /* Return code */
Pgno origPgno; /* The original page number */
assert( pPg->nRef>0 );
@ -5055,6 +5076,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
}
origPgno = pPg->pgno;
sqlite3PcacheMove(pPg, pgno);
if( pPgOld ){
sqlite3PcacheDrop(pPgOld);
@ -5097,6 +5119,19 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
sqlite3PagerUnref(pPgHdr);
}
/*
** For an in-memory database, make sure the original page continues
** to exist, in case the transaction needs to roll back. We allocate
** the page now, instead of at rollback, because we can better deal
** with an out-of-memory error now. Ticket #3761.
*/
if( MEMDB ){
DbPage *pNew;
rc = sqlite3PagerAcquire(pPager, origPgno, &pNew, 1);
if( rc!=SQLITE_OK ) return rc;
sqlite3PagerUnref(pNew);
}
return SQLITE_OK;
}
#endif

4079
parse.c

File diff suppressed because it is too large Load diff

192
parse.h
View file

@ -13,8 +13,8 @@
#define TK_SAVEPOINT 13
#define TK_RELEASE 14
#define TK_TO 15
#define TK_CREATE 16
#define TK_TABLE 17
#define TK_TABLE 16
#define TK_CREATE 17
#define TK_IF 18
#define TK_NOT 19
#define TK_EXISTS 20
@ -24,100 +24,100 @@
#define TK_AS 24
#define TK_COMMA 25
#define TK_ID 26
#define TK_ABORT 27
#define TK_AFTER 28
#define TK_ANALYZE 29
#define TK_ASC 30
#define TK_ATTACH 31
#define TK_BEFORE 32
#define TK_BY 33
#define TK_CASCADE 34
#define TK_CAST 35
#define TK_COLUMNKW 36
#define TK_CONFLICT 37
#define TK_DATABASE 38
#define TK_DESC 39
#define TK_DETACH 40
#define TK_EACH 41
#define TK_FAIL 42
#define TK_FOR 43
#define TK_IGNORE 44
#define TK_INITIALLY 45
#define TK_INSTEAD 46
#define TK_LIKE_KW 47
#define TK_MATCH 48
#define TK_KEY 49
#define TK_OF 50
#define TK_OFFSET 51
#define TK_PRAGMA 52
#define TK_RAISE 53
#define TK_REPLACE 54
#define TK_RESTRICT 55
#define TK_ROW 56
#define TK_TRIGGER 57
#define TK_VACUUM 58
#define TK_VIEW 59
#define TK_VIRTUAL 60
#define TK_REINDEX 61
#define TK_RENAME 62
#define TK_CTIME_KW 63
#define TK_ANY 64
#define TK_OR 65
#define TK_AND 66
#define TK_IS 67
#define TK_BETWEEN 68
#define TK_IN 69
#define TK_ISNULL 70
#define TK_NOTNULL 71
#define TK_NE 72
#define TK_EQ 73
#define TK_GT 74
#define TK_LE 75
#define TK_LT 76
#define TK_GE 77
#define TK_ESCAPE 78
#define TK_BITAND 79
#define TK_BITOR 80
#define TK_LSHIFT 81
#define TK_RSHIFT 82
#define TK_PLUS 83
#define TK_MINUS 84
#define TK_STAR 85
#define TK_SLASH 86
#define TK_REM 87
#define TK_CONCAT 88
#define TK_COLLATE 89
#define TK_UMINUS 90
#define TK_UPLUS 91
#define TK_BITNOT 92
#define TK_STRING 93
#define TK_JOIN_KW 94
#define TK_CONSTRAINT 95
#define TK_DEFAULT 96
#define TK_NULL 97
#define TK_PRIMARY 98
#define TK_UNIQUE 99
#define TK_CHECK 100
#define TK_REFERENCES 101
#define TK_AUTOINCR 102
#define TK_ON 103
#define TK_DELETE 104
#define TK_UPDATE 105
#define TK_INSERT 106
#define TK_SET 107
#define TK_DEFERRABLE 108
#define TK_FOREIGN 109
#define TK_DROP 110
#define TK_UNION 111
#define TK_ALL 112
#define TK_EXCEPT 113
#define TK_INTERSECT 114
#define TK_SELECT 115
#define TK_DISTINCT 116
#define TK_DOT 117
#define TK_FROM 118
#define TK_JOIN 119
#define TK_INDEXED 120
#define TK_INDEXED 27
#define TK_ABORT 28
#define TK_AFTER 29
#define TK_ANALYZE 30
#define TK_ASC 31
#define TK_ATTACH 32
#define TK_BEFORE 33
#define TK_BY 34
#define TK_CASCADE 35
#define TK_CAST 36
#define TK_COLUMNKW 37
#define TK_CONFLICT 38
#define TK_DATABASE 39
#define TK_DESC 40
#define TK_DETACH 41
#define TK_EACH 42
#define TK_FAIL 43
#define TK_FOR 44
#define TK_IGNORE 45
#define TK_INITIALLY 46
#define TK_INSTEAD 47
#define TK_LIKE_KW 48
#define TK_MATCH 49
#define TK_KEY 50
#define TK_OF 51
#define TK_OFFSET 52
#define TK_PRAGMA 53
#define TK_RAISE 54
#define TK_REPLACE 55
#define TK_RESTRICT 56
#define TK_ROW 57
#define TK_TRIGGER 58
#define TK_VACUUM 59
#define TK_VIEW 60
#define TK_VIRTUAL 61
#define TK_REINDEX 62
#define TK_RENAME 63
#define TK_CTIME_KW 64
#define TK_ANY 65
#define TK_OR 66
#define TK_AND 67
#define TK_IS 68
#define TK_BETWEEN 69
#define TK_IN 70
#define TK_ISNULL 71
#define TK_NOTNULL 72
#define TK_NE 73
#define TK_EQ 74
#define TK_GT 75
#define TK_LE 76
#define TK_LT 77
#define TK_GE 78
#define TK_ESCAPE 79
#define TK_BITAND 80
#define TK_BITOR 81
#define TK_LSHIFT 82
#define TK_RSHIFT 83
#define TK_PLUS 84
#define TK_MINUS 85
#define TK_STAR 86
#define TK_SLASH 87
#define TK_REM 88
#define TK_CONCAT 89
#define TK_COLLATE 90
#define TK_UMINUS 91
#define TK_UPLUS 92
#define TK_BITNOT 93
#define TK_STRING 94
#define TK_JOIN_KW 95
#define TK_CONSTRAINT 96
#define TK_DEFAULT 97
#define TK_NULL 98
#define TK_PRIMARY 99
#define TK_UNIQUE 100
#define TK_CHECK 101
#define TK_REFERENCES 102
#define TK_AUTOINCR 103
#define TK_ON 104
#define TK_DELETE 105
#define TK_UPDATE 106
#define TK_INSERT 107
#define TK_SET 108
#define TK_DEFERRABLE 109
#define TK_FOREIGN 110
#define TK_DROP 111
#define TK_UNION 112
#define TK_ALL 113
#define TK_EXCEPT 114
#define TK_INTERSECT 115
#define TK_SELECT 116
#define TK_DISTINCT 117
#define TK_DOT 118
#define TK_FROM 119
#define TK_JOIN 120
#define TK_USING 121
#define TK_ORDER 122
#define TK_GROUP 123

View file

@ -11,7 +11,7 @@
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.43 2009/01/23 16:45:01 danielk1977 Exp $
** @(#) $Id: pcache.c,v 1.44 2009/03/31 01:32:18 drh Exp $
*/
#include "sqliteInt.h"
@ -336,11 +336,9 @@ void sqlite3PcacheDrop(PgHdr *p){
** make it so.
*/
void sqlite3PcacheMakeDirty(PgHdr *p){
PCache *pCache;
p->flags &= ~PGHDR_DONT_WRITE;
assert( p->nRef>0 );
if( 0==(p->flags & PGHDR_DIRTY) ){
pCache = p->pCache;
p->flags |= PGHDR_DIRTY;
pcacheAddToDirtyList( p);
}

View file

@ -16,7 +16,7 @@
** If the default page cache implementation is overriden, then neither of
** these two features are available.
**
** @(#) $Id: pcache1.c,v 1.8 2009/01/23 16:45:01 danielk1977 Exp $
** @(#) $Id: pcache1.c,v 1.10 2009/03/23 04:33:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -129,7 +129,7 @@ static SQLITE_WSD struct PCacheGlobal {
*/
void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
PgFreeslot *p;
sz &= ~7;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.pStart = pBuf;
pcache1.pFree = 0;
@ -516,7 +516,7 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
nPinned = pCache->nPage - pCache->nRecyclable;
if( createFlag==1 && pCache->bPurgeable && (
nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
|| nPinned>=(pCache->nMax)
|| nPinned>=(pCache->nMax * 9 / 10)
)){
goto fetch_out;
}

View file

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.202 2009/01/20 16:53:41 danielk1977 Exp $
** $Id: pragma.c,v 1.204 2009/02/23 16:52:08 drh Exp $
*/
#include "sqliteInt.h"
@ -172,6 +172,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
{ "empty_result_callbacks", SQLITE_NullCallback },
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
#ifdef SQLITE_DEBUG
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
@ -831,7 +832,6 @@ void sqlite3Pragma(
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", SQLITE_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const Token *pDflt;
if( IsHiddenColumn(pCol) ){
nHidden++;
continue;
@ -842,9 +842,9 @@ void sqlite3Pragma(
pCol->zType ? pCol->zType : "", 0);
sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4);
if( pCol->pDflt ){
pDflt = &pCol->pDflt->span;
assert( pDflt->z );
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n);
const Token *p = &pCol->pDflt->span;
assert( p->z );
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)p->z, p->n);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
}

View file

@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.105 2009/01/20 16:53:41 danielk1977 Exp $
** $Id: prepare.c,v 1.114 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
@ -77,21 +77,17 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
*/
char *zErr;
int rc;
u8 lookasideEnabled;
assert( db->init.busy );
db->init.iDb = iDb;
db->init.newTnum = atoi(argv[1]);
lookasideEnabled = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
db->init.iDb = 0;
db->lookaside.bEnabled = lookasideEnabled;
assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}else if( rc!=SQLITE_INTERRUPT ){
}else if( rc!=SQLITE_INTERRUPT && (rc&0xff)!=SQLITE_LOCKED ){
corruptSchema(pData, argv[0], zErr);
}
sqlite3DbFree(db, zErr);
@ -351,10 +347,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
/* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
** the schema loaded, even if errors occured. In this situation the
** the schema loaded, even if errors occurred. In this situation the
** current sqlite3_prepare() operation will fail, but the following one
** will attempt to compile the supplied statement against whatever subset
** of the schema was loaded before the error occured. The primary
** of the schema was loaded before the error occurred. The primary
** purpose of this is to allow access to the sqlite_master table
** even when its contents have been corrupted.
*/
@ -540,18 +536,40 @@ static int sqlite3Prepare(
assert( !db->mallocFailed );
assert( sqlite3_mutex_held(db->mutex) );
/* If any attached database schemas are locked, do not proceed with
** compilation. Instead return SQLITE_LOCKED immediately.
/* Check to verify that it is possible to get a read lock on all
** database schemas. The inability to get a read lock indicates that
** some other database connection is holding a write-lock, which in
** turn means that the other connection has made uncommitted changes
** to the schema.
**
** Were we to proceed and prepare the statement against the uncommitted
** schema changes and if those schema changes are subsequently rolled
** back and different changes are made in their place, then when this
** prepared statement goes to run the schema cookie would fail to detect
** the schema change. Disaster would follow.
**
** This thread is currently holding mutexes on all Btrees (because
** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it
** is not possible for another thread to start a new schema change
** while this routine is running. Hence, we do not need to hold
** locks on the schema, we just need to make sure nobody else is
** holding them.
**
** Note that setting READ_UNCOMMITTED overrides most lock detection,
** but it does *not* override schema lock detection, so this all still
** works even if READ_UNCOMMITTED is set.
*/
for(i=0; i<db->nDb; i++) {
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
assert( sqlite3BtreeHoldsMutex(pBt) );
rc = sqlite3BtreeSchemaLocked(pBt);
if( rc ){
const char *zDb = db->aDb[i].zName;
sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb);
sqlite3Error(db, rc, "database schema is locked: %s", zDb);
(void)sqlite3SafetyOff(db);
return sqlite3ApiExit(db, SQLITE_LOCKED);
testcase( db->flags & SQLITE_ReadUncommitted );
return sqlite3ApiExit(db, rc);
}
}
}
@ -621,11 +639,13 @@ static int sqlite3Prepare(
rc = SQLITE_MISUSE;
}
if( saveSqlFlag ){
sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail - zSql));
assert( db->init.busy==0 || saveSqlFlag==0 );
if( db->init.busy==0 ){
Vdbe *pVdbe = sParse.pVdbe;
sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag);
}
if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(sParse.pVdbe);
assert(!(*ppStmt));
}else{
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
@ -664,8 +684,11 @@ static int sqlite3LockAndPrepare(
/*
** Rerun the compilation of a statement after a schema change.
** Return true if the statement was recompiled successfully.
** Return false if there is an error of some kind.
**
** If the statement is successfully recompiled, return SQLITE_OK. Otherwise,
** if the statement cannot be recompiled because another connection has
** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error
** occurs, return SQLITE_SCHEMA.
*/
int sqlite3Reprepare(Vdbe *p){
int rc;
@ -684,7 +707,7 @@ int sqlite3Reprepare(Vdbe *p){
db->mallocFailed = 1;
}
assert( pNew==0 );
return 0;
return (rc==SQLITE_LOCKED) ? SQLITE_LOCKED : SQLITE_SCHEMA;
}else{
assert( pNew!=0 );
}
@ -692,7 +715,7 @@ int sqlite3Reprepare(Vdbe *p){
sqlite3TransferBindings(pNew, (sqlite3_stmt*)p);
sqlite3VdbeResetStepResult((Vdbe*)pNew);
sqlite3VdbeFinalize((Vdbe*)pNew);
return 1;
return SQLITE_OK;
}

View file

@ -14,7 +14,7 @@
** resolve all identifiers by associating them with a particular
** table and column.
**
** $Id: resolve.c,v 1.15 2008/12/10 19:26:24 drh Exp $
** $Id: resolve.c,v 1.20 2009/03/05 04:23:47 shane Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -63,8 +63,9 @@ static void resolveAlias(
assert( pOrig!=0 );
assert( pOrig->flags & EP_Resolved );
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig);
pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
sqlite3TokenCopy(db, &pDup->token, &pOrig->token);
if( pDup->op!=TK_COLUMN && zType[0]!='G' ){
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
if( pDup==0 ) return;
@ -129,6 +130,7 @@ static int lookupName(
NameContext *pTopNC = pNC; /* First namecontext in the list */
Schema *pSchema = 0; /* Schema of the expression */
assert( pNC ); /* the name context cannot be NULL. */
assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */
/* Dequote and zero-terminate the names */
@ -282,8 +284,8 @@ static int lookupName(
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
Expr *pOrig;
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
assert( pExpr->pList==0 );
assert( pExpr->pSelect==0 );
assert( pExpr->x.pList==0 );
assert( pExpr->x.pSelect==0 );
pOrig = pEList->a[j].pExpr;
if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
@ -474,8 +476,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
*/
case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pList = pExpr->pList; /* The argument list */
int n = pList ? pList->nExpr : 0; /* Number of arguments */
ExprList *pList = pExpr->x.pList; /* The argument list */
int n = pList ? pList->nExpr : 0; /* Number of arguments */
int no_such_func = 0; /* True if no such function exists */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
@ -485,6 +487,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
zId = (char*)pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
@ -541,14 +544,14 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
case TK_EXISTS:
#endif
case TK_IN: {
if( pExpr->pSelect ){
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
#ifndef SQLITE_OMIT_CHECK
if( pNC->isCheck ){
sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
}
#endif
sqlite3WalkSelect(pWalker, pExpr->pSelect);
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
@ -736,7 +739,7 @@ static int resolveCompoundOrderBy(
}else{
iCol = resolveAsName(pParse, pEList, pE);
if( iCol==0 ){
pDup = sqlite3ExprDup(db, pE);
pDup = sqlite3ExprDup(db, pE, 0);
if( !db->mallocFailed ){
assert(pDup);
iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup);

262
select.c
View file

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.499 2009/02/09 13:19:28 drh Exp $
** $Id: select.c,v 1.506 2009/03/31 03:41:57 shane Exp $
*/
#include "sqliteInt.h"
@ -800,8 +800,7 @@ static void generateSortTail(
iTab = pOrderBy->iECursor;
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
pseudoTab = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nColumn);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, pseudoTab, eDest==SRT_Output);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, eDest==SRT_Output, nColumn);
}
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak);
codeOffset(v, p, addrContinue);
@ -987,8 +986,9 @@ static const char *columnType(
** statement.
*/
NameContext sNC;
Select *pS = pExpr->pSelect;
Select *pS = pExpr->x.pSelect;
Expr *p = pS->pEList->a[0].pExpr;
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
@ -1229,7 +1229,7 @@ static int selectColumnsFromExprList(
** The column list has only names, not types or collations. This
** routine goes through and adds the types and collations.
**
** This routine requires that all indentifiers in the SELECT
** This routine requires that all identifiers in the SELECT
** statement be resolved.
*/
static void selectAddColumnTypeAndCollation(
@ -1284,7 +1284,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
if( pTab==0 ){
return 0;
}
pTab->db = db;
pTab->dbMem = db->lookaside.bEnabled ? db : 0;
pTab->nRef = 1;
pTab->zName = 0;
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
@ -2141,7 +2141,7 @@ static int multiSelectOrderBy(
/* Reattach the ORDER BY clause to the query.
*/
p->pOrderBy = pOrderBy;
pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy);
pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
/* Allocate a range of temporary registers and the KeyInfo needed
** for the logic that removes duplicate result rows when the
@ -2392,23 +2392,26 @@ static void substExpr(
}else{
Expr *pNew;
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pNew = pEList->a[pExpr->iColumn].pExpr;
assert( pNew!=0 );
pExpr->op = pNew->op;
assert( pExpr->pLeft==0 );
pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft);
pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft, 0);
assert( pExpr->pRight==0 );
pExpr->pRight = sqlite3ExprDup(db, pNew->pRight);
assert( pExpr->pList==0 );
pExpr->pList = sqlite3ExprListDup(db, pNew->pList);
pExpr->pRight = sqlite3ExprDup(db, pNew->pRight, 0);
pExpr->iTable = pNew->iTable;
pExpr->pTab = pNew->pTab;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
sqlite3TokenCopy(db, &pExpr->token, &pNew->token);
sqlite3TokenCopy(db, &pExpr->span, &pNew->span);
pExpr->pSelect = sqlite3SelectDup(db, pNew->pSelect);
assert( pExpr->x.pList==0 && pExpr->x.pSelect==0 );
if( ExprHasProperty(pNew, EP_xIsSelect) ){
pExpr->x.pSelect = sqlite3SelectDup(db, pNew->x.pSelect, 0);
}else{
pExpr->x.pList = sqlite3ExprListDup(db, pNew->x.pList, 0);
}
pExpr->flags = pNew->flags;
pExpr->pAggInfo = pNew->pAggInfo;
pNew->pAggInfo = 0;
@ -2416,8 +2419,11 @@ static void substExpr(
}else{
substExpr(db, pExpr->pLeft, iTable, pEList);
substExpr(db, pExpr->pRight, iTable, pEList);
substSelect(db, pExpr->pSelect, iTable, pEList);
substExprList(db, pExpr->pList, iTable, pEList);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
substSelect(db, pExpr->x.pSelect, iTable, pEList);
}else{
substExprList(db, pExpr->x.pList, iTable, pEList);
}
}
}
static void substExprList(
@ -2729,7 +2735,7 @@ static int flattenSubquery(
p->pSrc = 0;
p->pPrior = 0;
p->pLimit = 0;
pNew = sqlite3SelectDup(db, p);
pNew = sqlite3SelectDup(db, p, 0);
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
p->pSrc = pSrc;
@ -2873,7 +2879,7 @@ static int flattenSubquery(
substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
}
if( pSub->pWhere ){
pWhere = sqlite3ExprDup(db, pSub->pWhere);
pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
}else{
pWhere = 0;
}
@ -2883,9 +2889,9 @@ static int flattenSubquery(
pParent->pWhere = pWhere;
substExpr(db, pParent->pHaving, iParent, pSub->pEList);
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
sqlite3ExprDup(db, pSub->pHaving));
sqlite3ExprDup(db, pSub->pHaving, 0));
assert( pParent->pGroupBy==0 );
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy);
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
substExpr(db, pParent->pWhere, iParent, pSub->pEList);
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
@ -2934,7 +2940,8 @@ static u8 minMaxQuery(Select *p){
if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL;
pExpr = pEList->a[0].pExpr;
pEList = pExpr->pList;
if( ExprHasProperty(pExpr, EP_xIsSelect) ) return 0;
pEList = pExpr->x.pList;
if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0;
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
if( pExpr->token.n!=3 ) return WHERE_ORDERBY_NORMAL;
@ -2946,6 +2953,40 @@ static u8 minMaxQuery(Select *p){
return WHERE_ORDERBY_NORMAL;
}
/*
** The select statement passed as the first argument is an aggregate query.
** The second argment is the associated aggregate-info object. This
** function tests if the SELECT is of the form:
**
** SELECT count(*) FROM <tbl>
**
** where table is a database table, not a sub-select or view. If the query
** does match this pattern, then a pointer to the Table object representing
** <tbl> is returned. Otherwise, 0 is returned.
*/
static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
Table *pTab;
Expr *pExpr;
assert( !p->pGroupBy );
if( p->pWhere || p->pEList->nExpr!=1
|| p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect
){
return 0;
}
pTab = p->pSrc->a[0].pTab;
pExpr = p->pEList->a[0].pExpr;
assert( pTab && !pTab->pSelect && pExpr );
if( IsVirtual(pTab) ) return 0;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( (pAggInfo->aFunc[0].pFunc->flags&SQLITE_FUNC_COUNT)==0 ) return 0;
if( pExpr->flags&EP_Distinct ) return 0;
return pTab;
}
/*
** If the source-list item passed as an argument was augmented with an
** INDEXED BY clause, then try to locate the specified index. If there
@ -3039,7 +3080,7 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3WalkSelect(pWalker, pSel);
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
pTab->db = db;
pTab->dbMem = db->lookaside.bEnabled ? db : 0;
pTab->nRef = 1;
pTab->zName = sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pTab);
while( pSel->pPrior ){ pSel = pSel->pPrior; }
@ -3065,7 +3106,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** in the inner view.
*/
if( pFrom->pSelect==0 ){
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect);
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
sqlite3WalkSelect(pWalker, pFrom->pSelect);
}
}
@ -3364,12 +3405,13 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
if( pFunc->iDistinct>=0 ){
Expr *pE = pFunc->pExpr;
if( pE->pList==0 || pE->pList->nExpr!=1 ){
assert( !ExprHasProperty(pE, EP_xIsSelect) );
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
"argument");
pFunc->iDistinct = -1;
}else{
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
}
@ -3386,7 +3428,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
int i;
struct AggInfo_func *pF;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
ExprList *pList = pF->pExpr->pList;
ExprList *pList = pF->pExpr->x.pList;
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
(void*)pF->pFunc, P4_FUNCDEF);
}
@ -3407,7 +3450,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
int nArg;
int addrNext = 0;
int regAgg;
ExprList *pList = pF->pExpr->pList;
ExprList *pList = pF->pExpr->x.pList;
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
@ -3657,7 +3701,7 @@ int sqlite3Select(
** GROUP BY might use an index, DISTINCT never does.
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && !p->pGroupBy ){
p->pGroupBy = sqlite3ExprListDup(db, p->pEList);
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
p->selFlags &= ~SF_Distinct;
isDistinct = 0;
@ -3780,7 +3824,8 @@ int sqlite3Select(
}
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; i<sAggInfo.nFunc; i++){
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList);
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
}
if( db->mallocFailed ) goto select_end;
@ -3987,68 +4032,127 @@ int sqlite3Select(
} /* endif pGroupBy */
else {
ExprList *pMinMax = 0;
ExprList *pDel = 0;
u8 flag;
#ifndef SQLITE_OMIT_BTREECOUNT
Table *pTab;
if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
/* If isSimpleCount() returns a pointer to a Table structure, then
** the SQL statement is of the form:
**
** SELECT count(*) FROM <tbl>
**
** where the Table structure returned represents table <tbl>.
**
** This statement is so common that it is optimized specially. The
** OP_Count instruction is executed either on the intkey table that
** contains the data for table <tbl> or on one of its indexes. It
** is better to execute the op on an index, as indexes are almost
** always spread across less pages than their corresponding tables.
*/
const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */
Index *pIdx; /* Iterator variable */
KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
Index *pBest = 0; /* Best index found so far */
int iRoot = pTab->tnum; /* Root page of scanned b-tree */
/* Check if the query is of one of the following forms:
**
** SELECT min(x) FROM ...
** SELECT max(x) FROM ...
**
** If it is, then ask the code in where.c to attempt to sort results
** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
** If where.c is able to produce results sorted in this order, then
** add vdbe code to break out of the processing loop after the
** first iteration (since the first iteration of the loop is
** guaranteed to operate on the row with the minimum or maximum
** value of x, the only row required).
**
** A special flag must be passed to sqlite3WhereBegin() to slightly
** modify behaviour as follows:
**
** + If the query is a "SELECT min(x)", then the loop coded by
** where.c should not iterate over any values with a NULL value
** for x.
**
** + The optimizer code in where.c (the thing that decides which
** index or indices to use) should place a different priority on
** satisfying the 'ORDER BY' clause than it does in other cases.
** Refer to code and comments in where.c for details.
*/
flag = minMaxQuery(p);
if( flag ){
pDel = pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList);
if( pMinMax && !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
pMinMax->a[0].pExpr->op = TK_COLUMN;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
/* Search for the index that has the least amount of columns. If
** there is such an index, and it has less columns than the table
** does, then we can assume that it consumes less space on disk and
** will therefore be cheaper to scan to determine the query result.
** In this case set iRoot to the root page number of the index b-tree
** and pKeyInfo to the KeyInfo structure required to navigate the
** index.
**
** In practice the KeyInfo structure will not be used. It is only
** passed to keep OP_OpenRead happy.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( !pBest || pIdx->nColumn<pBest->nColumn ){
pBest = pIdx;
}
}
if( pBest && pBest->nColumn<pTab->nCol ){
iRoot = pBest->tnum;
pKeyInfo = sqlite3IndexKeyinfo(pParse, pBest);
}
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
sqlite3VdbeAddOp3(v, OP_OpenRead, iCsr, iRoot, iDb);
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO_HANDOFF);
}
sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
}else
#endif /* SQLITE_OMIT_BTREECOUNT */
{
/* Check if the query is of one of the following forms:
**
** SELECT min(x) FROM ...
** SELECT max(x) FROM ...
**
** If it is, then ask the code in where.c to attempt to sort results
** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
** If where.c is able to produce results sorted in this order, then
** add vdbe code to break out of the processing loop after the
** first iteration (since the first iteration of the loop is
** guaranteed to operate on the row with the minimum or maximum
** value of x, the only row required).
**
** A special flag must be passed to sqlite3WhereBegin() to slightly
** modify behaviour as follows:
**
** + If the query is a "SELECT min(x)", then the loop coded by
** where.c should not iterate over any values with a NULL value
** for x.
**
** + The optimizer code in where.c (the thing that decides which
** index or indices to use) should place a different priority on
** satisfying the 'ORDER BY' clause than it does in other cases.
** Refer to code and comments in where.c for details.
*/
ExprList *pMinMax = 0;
u8 flag = minMaxQuery(p);
if( flag ){
assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) );
pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0);
pDel = pMinMax;
if( pMinMax && !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
pMinMax->a[0].pExpr->op = TK_COLUMN;
}
}
/* This case runs if the aggregate has no GROUP BY clause. The
** processing is much simpler since there is only a single row
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag, 0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
if( !pMinMax && flag ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak);
VdbeComment((v, "%s() by index",
(flag==WHERE_ORDERBY_MIN?"min":"max")));
}
sqlite3WhereEnd(pWInfo);
finalizeAggFunctions(pParse, &sAggInfo);
}
/* This case runs if the aggregate has no GROUP BY clause. The
** processing is much simpler since there is only a single row
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag, 0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
if( !pMinMax && flag ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak);
VdbeComment((v, "%s() by index",(flag==WHERE_ORDERBY_MIN?"min":"max")));
}
sqlite3WhereEnd(pWInfo);
finalizeAggFunctions(pParse, &sAggInfo);
pOrderBy = 0;
if( pHaving ){
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
}
selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(db, pDel);
}
sqlite3VdbeResolveLabel(v, addrEnd);

932
shell.c
View file

@ -12,7 +12,7 @@
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.201 2009/02/04 22:46:47 drh Exp $
** $Id: shell.c,v 1.207 2009/03/16 10:59:44 drh Exp $
*/
#if defined(_WIN32) || defined(WIN32)
/* This needs to come before any includes for MSVC compiler */
@ -120,6 +120,861 @@ static void endTimer(void){
*/
#define UNUSED_PARAMETER(x) (void)(x)
/**************************************************************************
***************************************************************************
** Begin genfkey logic.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined SQLITE_OMIT_SUBQUERY
#define GENFKEY_ERROR 1
#define GENFKEY_DROPTRIGGER 2
#define GENFKEY_CREATETRIGGER 3
static int genfkey_create_triggers(sqlite3 *, const char *, void *,
int (*)(void *, int, const char *)
);
struct GenfkeyCb {
void *pCtx;
int eType;
int (*xData)(void *, int, const char *);
};
typedef struct GenfkeyCb GenfkeyCb;
/* The code in this file defines a sqlite3 virtual-table module that
** provides a read-only view of the current database schema. There is one
** row in the schema table for each column in the database schema.
*/
#define SCHEMA \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"tablename," /* Name of table */ \
"cid," /* Column number (from left-to-right, 0 upward) */ \
"name," /* Column name */ \
"type," /* Specified type (i.e. VARCHAR(32)) */ \
"not_null," /* Boolean. True if NOT NULL was specified */ \
"dflt_value," /* Default value for this column */ \
"pk" /* True if this column is part of the primary key */ \
")"
#define SCHEMA2 \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"from_tbl," /* Name of table */ \
"fkid," \
"seq," \
"to_tbl," \
"from_col," \
"to_col," \
"on_update," \
"on_delete," \
"match" \
")"
#define SCHEMA3 \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"tablename," /* Name of table */ \
"seq," \
"name," \
"isunique" \
")"
#define SCHEMA4 \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"indexname," /* Name of table */ \
"seqno," \
"cid," \
"name" \
")"
#define SCHEMA5 \
"CREATE TABLE x(" \
"database," /* Name of database (i.e. main, temp etc.) */ \
"triggername," /* Name of trigger */ \
"dummy" /* Unused */ \
")"
typedef struct SchemaTable SchemaTable;
struct SchemaTable {
const char *zName;
const char *zObject;
const char *zPragma;
const char *zSchema;
} aSchemaTable[] = {
{ "table_info", "table", "PRAGMA %Q.table_info(%Q)", SCHEMA },
{ "foreign_key_list", "table", "PRAGMA %Q.foreign_key_list(%Q)", SCHEMA2 },
{ "index_list", "table", "PRAGMA %Q.index_list(%Q)", SCHEMA3 },
{ "index_info", "index", "PRAGMA %Q.index_info(%Q)", SCHEMA4 },
{ "trigger_list", "trigger", "SELECT 1", SCHEMA5 },
{ 0, 0, 0, 0 }
};
typedef struct schema_vtab schema_vtab;
typedef struct schema_cursor schema_cursor;
/* A schema table object */
struct schema_vtab {
sqlite3_vtab base;
sqlite3 *db;
SchemaTable *pType;
};
/* A schema table cursor object */
struct schema_cursor {
sqlite3_vtab_cursor base;
sqlite3_stmt *pDbList;
sqlite3_stmt *pTableList;
sqlite3_stmt *pColumnList;
int rowid;
};
/*
** Table destructor for the schema module.
*/
static int schemaDestroy(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
return 0;
}
/*
** Table constructor for the schema module.
*/
static int schemaCreate(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
int rc = SQLITE_NOMEM;
schema_vtab *pVtab;
SchemaTable *pType = &aSchemaTable[0];
UNUSED_PARAMETER(pzErr);
if( argc>3 ){
int i;
pType = 0;
for(i=0; aSchemaTable[i].zName; i++){
if( 0==strcmp(argv[3], aSchemaTable[i].zName) ){
pType = &aSchemaTable[i];
}
}
if( !pType ){
return SQLITE_ERROR;
}
}
pVtab = sqlite3_malloc(sizeof(schema_vtab));
if( pVtab ){
memset(pVtab, 0, sizeof(schema_vtab));
pVtab->db = (sqlite3 *)pAux;
pVtab->pType = pType;
rc = sqlite3_declare_vtab(db, pType->zSchema);
}
*ppVtab = (sqlite3_vtab *)pVtab;
return rc;
}
/*
** Open a new cursor on the schema table.
*/
static int schemaOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
int rc = SQLITE_NOMEM;
schema_cursor *pCur;
UNUSED_PARAMETER(pVTab);
pCur = sqlite3_malloc(sizeof(schema_cursor));
if( pCur ){
memset(pCur, 0, sizeof(schema_cursor));
*ppCursor = (sqlite3_vtab_cursor *)pCur;
rc = SQLITE_OK;
}
return rc;
}
/*
** Close a schema table cursor.
*/
static int schemaClose(sqlite3_vtab_cursor *cur){
schema_cursor *pCur = (schema_cursor *)cur;
sqlite3_finalize(pCur->pDbList);
sqlite3_finalize(pCur->pTableList);
sqlite3_finalize(pCur->pColumnList);
sqlite3_free(pCur);
return SQLITE_OK;
}
static void columnToResult(sqlite3_context *ctx, sqlite3_stmt *pStmt, int iCol){
switch( sqlite3_column_type(pStmt, iCol) ){
case SQLITE_NULL:
sqlite3_result_null(ctx);
break;
case SQLITE_INTEGER:
sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
break;
case SQLITE_FLOAT:
sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
break;
case SQLITE_TEXT: {
const char *z = (const char *)sqlite3_column_text(pStmt, iCol);
sqlite3_result_text(ctx, z, -1, SQLITE_TRANSIENT);
break;
}
}
}
/*
** Retrieve a column of data.
*/
static int schemaColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
schema_cursor *pCur = (schema_cursor *)cur;
switch( i ){
case 0:
columnToResult(ctx, pCur->pDbList, 1);
break;
case 1:
columnToResult(ctx, pCur->pTableList, 0);
break;
default:
columnToResult(ctx, pCur->pColumnList, i-2);
break;
}
return SQLITE_OK;
}
/*
** Retrieve the current rowid.
*/
static int schemaRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
schema_cursor *pCur = (schema_cursor *)cur;
*pRowid = pCur->rowid;
return SQLITE_OK;
}
static int finalize(sqlite3_stmt **ppStmt){
int rc = sqlite3_finalize(*ppStmt);
*ppStmt = 0;
return rc;
}
static int schemaEof(sqlite3_vtab_cursor *cur){
schema_cursor *pCur = (schema_cursor *)cur;
return (pCur->pDbList ? 0 : 1);
}
/*
** Advance the cursor to the next row.
*/
static int schemaNext(sqlite3_vtab_cursor *cur){
int rc = SQLITE_OK;
schema_cursor *pCur = (schema_cursor *)cur;
schema_vtab *pVtab = (schema_vtab *)(cur->pVtab);
char *zSql = 0;
while( !pCur->pColumnList || SQLITE_ROW!=sqlite3_step(pCur->pColumnList) ){
if( SQLITE_OK!=(rc = finalize(&pCur->pColumnList)) ) goto next_exit;
while( !pCur->pTableList || SQLITE_ROW!=sqlite3_step(pCur->pTableList) ){
if( SQLITE_OK!=(rc = finalize(&pCur->pTableList)) ) goto next_exit;
assert(pCur->pDbList);
while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){
rc = finalize(&pCur->pDbList);
goto next_exit;
}
/* Set zSql to the SQL to pull the list of tables from the
** sqlite_master (or sqlite_temp_master) table of the database
** identfied by the row pointed to by the SQL statement pCur->pDbList
** (iterating through a "PRAGMA database_list;" statement).
*/
if( sqlite3_column_int(pCur->pDbList, 0)==1 ){
zSql = sqlite3_mprintf(
"SELECT name FROM sqlite_temp_master WHERE type=%Q",
pVtab->pType->zObject
);
}else{
sqlite3_stmt *pDbList = pCur->pDbList;
zSql = sqlite3_mprintf(
"SELECT name FROM %Q.sqlite_master WHERE type=%Q",
sqlite3_column_text(pDbList, 1), pVtab->pType->zObject
);
}
if( !zSql ){
rc = SQLITE_NOMEM;
goto next_exit;
}
rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pTableList, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ) goto next_exit;
}
/* Set zSql to the SQL to the table_info pragma for the table currently
** identified by the rows pointed to by statements pCur->pDbList and
** pCur->pTableList.
*/
zSql = sqlite3_mprintf(pVtab->pType->zPragma,
sqlite3_column_text(pCur->pDbList, 1),
sqlite3_column_text(pCur->pTableList, 0)
);
if( !zSql ){
rc = SQLITE_NOMEM;
goto next_exit;
}
rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pColumnList, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ) goto next_exit;
}
pCur->rowid++;
next_exit:
/* TODO: Handle rc */
return rc;
}
/*
** Reset a schema table cursor.
*/
static int schemaFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
int rc;
schema_vtab *pVtab = (schema_vtab *)(pVtabCursor->pVtab);
schema_cursor *pCur = (schema_cursor *)pVtabCursor;
UNUSED_PARAMETER(idxNum);
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
pCur->rowid = 0;
finalize(&pCur->pTableList);
finalize(&pCur->pColumnList);
finalize(&pCur->pDbList);
rc = sqlite3_prepare(pVtab->db,"SELECT 0, 'main'", -1, &pCur->pDbList, 0);
return (rc==SQLITE_OK ? schemaNext(pVtabCursor) : rc);
}
/*
** Analyse the WHERE condition.
*/
static int schemaBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
UNUSED_PARAMETER(tab);
UNUSED_PARAMETER(pIdxInfo);
return SQLITE_OK;
}
/*
** A virtual table module that merely echos method calls into TCL
** variables.
*/
static sqlite3_module schemaModule = {
0, /* iVersion */
schemaCreate,
schemaCreate,
schemaBestIndex,
schemaDestroy,
schemaDestroy,
schemaOpen, /* xOpen - open a cursor */
schemaClose, /* xClose - close a cursor */
schemaFilter, /* xFilter - configure scan constraints */
schemaNext, /* xNext - advance a cursor */
schemaEof, /* xEof */
schemaColumn, /* xColumn - read data */
schemaRowid, /* xRowid - read data */
0, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
};
/*
** Extension load function.
*/
static int installSchemaModule(sqlite3 *db, sqlite3 *sdb){
sqlite3_create_module(db, "schema", &schemaModule, (void *)sdb);
return 0;
}
/*
** sj(zValue, zJoin)
**
** The following block contains the implementation of an aggregate
** function that returns a string. Each time the function is stepped,
** it appends data to an internal buffer. When the aggregate is finalized,
** the contents of the buffer are returned.
**
** The first time the aggregate is stepped the buffer is set to a copy
** of the first argument. The second time and subsequent times it is
** stepped a copy of the second argument is appended to the buffer, then
** a copy of the first.
**
** Example:
**
** INSERT INTO t1(a) VALUES('1');
** INSERT INTO t1(a) VALUES('2');
** INSERT INTO t1(a) VALUES('3');
** SELECT sj(a, ', ') FROM t1;
**
** => "1, 2, 3"
**
*/
struct StrBuffer {
char *zBuf;
};
typedef struct StrBuffer StrBuffer;
static void joinFinalize(sqlite3_context *context){
StrBuffer *p;
p = (StrBuffer *)sqlite3_aggregate_context(context, sizeof(StrBuffer));
sqlite3_result_text(context, p->zBuf, -1, SQLITE_TRANSIENT);
sqlite3_free(p->zBuf);
}
static void joinStep(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
StrBuffer *p;
UNUSED_PARAMETER(argc);
p = (StrBuffer *)sqlite3_aggregate_context(context, sizeof(StrBuffer));
if( p->zBuf==0 ){
p->zBuf = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
}else{
char *zTmp = p->zBuf;
p->zBuf = sqlite3_mprintf("%s%s%s",
zTmp, sqlite3_value_text(argv[1]), sqlite3_value_text(argv[0])
);
sqlite3_free(zTmp);
}
}
/*
** dq(zString)
**
** This scalar function accepts a single argument and interprets it as
** a text value. The return value is the argument enclosed in double
** quotes. If any double quote characters are present in the argument,
** these are escaped.
**
** dq('the raven "Nevermore."') == '"the raven ""Nevermore."""'
*/
static void doublequote(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int ii;
char *zOut;
char *zCsr;
const char *zIn = (const char *)sqlite3_value_text(argv[0]);
int nIn = sqlite3_value_bytes(argv[0]);
UNUSED_PARAMETER(argc);
zOut = sqlite3_malloc(nIn*2+3);
zCsr = zOut;
*zCsr++ = '"';
for(ii=0; ii<nIn; ii++){
*zCsr++ = zIn[ii];
if( zIn[ii]=='"' ){
*zCsr++ = '"';
}
}
*zCsr++ = '"';
*zCsr++ = '\0';
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
sqlite3_free(zOut);
}
/*
** multireplace(zString, zSearch1, zReplace1, ...)
*/
static void multireplace(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int i = 0;
char *zOut = 0;
int nOut = 0;
int nMalloc = 0;
const char *zIn = (const char *)sqlite3_value_text(argv[0]);
int nIn = sqlite3_value_bytes(argv[0]);
while( i<nIn ){
const char *zCopy = &zIn[i];
int nCopy = 1;
int nReplace = 1;
int j;
for(j=1; j<(argc-1); j+=2){
const char *z = (const char *)sqlite3_value_text(argv[j]);
int n = sqlite3_value_bytes(argv[j]);
if( n<=(nIn-i) && 0==strncmp(z, zCopy, n) ){
zCopy = (const char *)sqlite3_value_text(argv[j+1]);
nCopy = sqlite3_value_bytes(argv[j+1]);
nReplace = n;
break;
}
}
if( (nOut+nCopy)>nMalloc ){
nMalloc = 16 + (nOut+nCopy)*2;
zOut = (char *)sqlite3_realloc(zOut, nMalloc);
}
assert( nMalloc>=(nOut+nCopy) );
memcpy(&zOut[nOut], zCopy, nCopy);
i += nReplace;
nOut += nCopy;
}
sqlite3_result_text(context, zOut, nOut, SQLITE_TRANSIENT);
sqlite3_free(zOut);
}
/*
** A callback for sqlite3_exec() invokes the callback specified by the
** GenfkeyCb structure pointed to by the void* passed as the first argument.
*/
static int invokeCallback(void *p, int nArg, char **azArg, char **azCol){
GenfkeyCb *pCb = (GenfkeyCb *)p;
UNUSED_PARAMETER(nArg);
UNUSED_PARAMETER(azCol);
return pCb->xData(pCb->pCtx, pCb->eType, azArg[0]);
}
int detectSchemaProblem(
sqlite3 *db, /* Database connection */
const char *zMessage, /* English language error message */
const char *zSql, /* SQL statement to run */
GenfkeyCb *pCb
){
sqlite3_stmt *pStmt;
int rc;
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
return rc;
}
while( SQLITE_ROW==sqlite3_step(pStmt) ){
char *zDel;
int iFk = sqlite3_column_int(pStmt, 0);
const char *zTab = (const char *)sqlite3_column_text(pStmt, 1);
zDel = sqlite3_mprintf("Error in table %s: %s", zTab, zMessage);
rc = pCb->xData(pCb->pCtx, pCb->eType, zDel);
sqlite3_free(zDel);
if( rc!=SQLITE_OK ) return rc;
zDel = sqlite3_mprintf(
"DELETE FROM temp.fkey WHERE from_tbl = %Q AND fkid = %d"
, zTab, iFk
);
sqlite3_exec(db, zDel, 0, 0, 0);
sqlite3_free(zDel);
}
sqlite3_finalize(pStmt);
return SQLITE_OK;
}
/*
** Create and populate temporary table "fkey".
*/
static int populateTempTable(sqlite3 *db, GenfkeyCb *pCallback){
int rc;
rc = sqlite3_exec(db,
"CREATE VIRTUAL TABLE temp.v_fkey USING schema(foreign_key_list);"
"CREATE VIRTUAL TABLE temp.v_col USING schema(table_info);"
"CREATE VIRTUAL TABLE temp.v_idxlist USING schema(index_list);"
"CREATE VIRTUAL TABLE temp.v_idxinfo USING schema(index_info);"
"CREATE VIRTUAL TABLE temp.v_triggers USING schema(trigger_list);"
"CREATE TABLE temp.fkey AS "
"SELECT from_tbl, to_tbl, fkid, from_col, to_col, on_update, on_delete "
"FROM temp.v_fkey WHERE database = 'main';"
, 0, 0, 0
);
if( rc!=SQLITE_OK ) return rc;
rc = detectSchemaProblem(db, "foreign key columns do not exist",
"SELECT fkid, from_tbl "
"FROM temp.fkey "
"WHERE to_col IS NOT NULL AND NOT EXISTS (SELECT 1 "
"FROM temp.v_col WHERE tablename=to_tbl AND name==to_col"
")", pCallback
);
if( rc!=SQLITE_OK ) return rc;
/* At this point the temp.fkey table is mostly populated. If any foreign
** keys were specified so that they implicitly refer to they primary
** key of the parent table, the "to_col" values of the temp.fkey rows
** are still set to NULL.
**
** This is easily fixed for single column primary keys, but not for
** composites. With a composite primary key, there is no way to reliably
** query sqlite for the order in which the columns that make up the
** composite key were declared i.e. there is no way to tell if the
** schema actually contains "PRIMARY KEY(a, b)" or "PRIMARY KEY(b, a)".
** Therefore, this case is not handled. The following function call
** detects instances of this case.
*/
rc = detectSchemaProblem(db, "implicit mapping to composite primary key",
"SELECT fkid, from_tbl "
"FROM temp.fkey "
"WHERE to_col IS NULL "
"GROUP BY fkid, from_tbl HAVING count(*) > 1", pCallback
);
if( rc!=SQLITE_OK ) return rc;
/* Detect attempts to implicitly map to the primary key of a table
** that has no primary key column.
*/
rc = detectSchemaProblem(db, "implicit mapping to non-existant primary key",
"SELECT fkid, from_tbl "
"FROM temp.fkey "
"WHERE to_col IS NULL AND NOT EXISTS "
"(SELECT 1 FROM temp.v_col WHERE pk AND tablename = temp.fkey.to_tbl)"
, pCallback
);
if( rc!=SQLITE_OK ) return rc;
/* Fix all the implicit primary key mappings in the temp.fkey table. */
rc = sqlite3_exec(db,
"UPDATE temp.fkey SET to_col = "
"(SELECT name FROM temp.v_col WHERE pk AND tablename=temp.fkey.to_tbl)"
" WHERE to_col IS NULL;"
, 0, 0, 0
);
if( rc!=SQLITE_OK ) return rc;
/* Now check that all all parent keys are either primary keys or
** subject to a unique constraint.
*/
rc = sqlite3_exec(db,
"CREATE TABLE temp.idx2 AS SELECT "
"il.tablename AS tablename,"
"ii.indexname AS indexname,"
"ii.name AS col "
"FROM temp.v_idxlist AS il, temp.v_idxinfo AS ii "
"WHERE il.isunique AND il.database='main' AND ii.indexname = il.name;"
"INSERT INTO temp.idx2 "
"SELECT tablename, 'pk', name FROM temp.v_col WHERE pk;"
"CREATE TABLE temp.idx AS SELECT "
"tablename, indexname, sj(dq(col),',') AS cols "
"FROM (SELECT * FROM temp.idx2 ORDER BY col) "
"GROUP BY tablename, indexname;"
"CREATE TABLE temp.fkey2 AS SELECT "
"fkid, from_tbl, to_tbl, sj(dq(to_col),',') AS cols "
"FROM (SELECT * FROM temp.fkey ORDER BY to_col) "
"GROUP BY fkid, from_tbl;"
"CREATE TABLE temp.triggers AS SELECT "
"triggername FROM temp.v_triggers WHERE database='main' AND "
"triggername LIKE 'genfkey%';"
, 0, 0, 0
);
if( rc!=SQLITE_OK ) return rc;
rc = detectSchemaProblem(db, "foreign key is not unique",
"SELECT fkid, from_tbl "
"FROM temp.fkey2 "
"WHERE NOT EXISTS (SELECT 1 "
"FROM temp.idx WHERE tablename=to_tbl AND fkey2.cols==idx.cols"
")", pCallback
);
if( rc!=SQLITE_OK ) return rc;
return rc;
}
#define GENFKEY_ERROR 1
#define GENFKEY_DROPTRIGGER 2
#define GENFKEY_CREATETRIGGER 3
static int genfkey_create_triggers(
sqlite3 *sdb, /* Connection to read schema from */
const char *zDb, /* Name of db to read ("main", "temp") */
void *pCtx, /* Context pointer to pass to xData */
int (*xData)(void *, int, const char *)
){
const char *zSql =
"SELECT multireplace('"
"-- Triggers for foreign key mapping:\n"
"--\n"
"-- /from_readable/ REFERENCES /to_readable/\n"
"-- on delete /on_delete/\n"
"-- on update /on_update/\n"
"--\n"
/* The "BEFORE INSERT ON <referencing>" trigger. This trigger's job is to
** throw an exception if the user tries to insert a row into the
** referencing table for which there is no corresponding row in
** the referenced table.
*/
"CREATE TRIGGER /name/_insert_referencing BEFORE INSERT ON /tbl/ WHEN \n"
" /key_notnull/ AND NOT EXISTS (SELECT 1 FROM /ref/ WHERE /cond1/)\n"
"BEGIN\n"
" SELECT RAISE(ABORT, ''constraint failed'');\n"
"END;\n"
/* The "BEFORE UPDATE ON <referencing>" trigger. This trigger's job
** is to throw an exception if the user tries to update a row in the
** referencing table causing it to correspond to no row in the
** referenced table.
*/
"CREATE TRIGGER /name/_update_referencing BEFORE\n"
" UPDATE OF /rkey_list/ ON /tbl/ WHEN \n"
" /key_notnull/ AND \n"
" NOT EXISTS (SELECT 1 FROM /ref/ WHERE /cond1/)\n"
"BEGIN\n"
" SELECT RAISE(ABORT, ''constraint failed'');\n"
"END;\n"
/* The "BEFORE DELETE ON <referenced>" trigger. This trigger's job
** is to detect when a row is deleted from the referenced table to
** which rows in the referencing table correspond. The action taken
** depends on the value of the 'ON DELETE' clause.
*/
"CREATE TRIGGER /name/_delete_referenced BEFORE DELETE ON /ref/ WHEN\n"
" EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n"
"BEGIN\n"
" /delete_action/\n"
"END;\n"
/* The "BEFORE DELETE ON <referenced>" trigger. This trigger's job
** is to detect when the key columns of a row in the referenced table
** to which one or more rows in the referencing table correspond are
** updated. The action taken depends on the value of the 'ON UPDATE'
** clause.
*/
"CREATE TRIGGER /name/_update_referenced AFTER\n"
" UPDATE OF /fkey_list/ ON /ref/ WHEN \n"
" EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n"
"BEGIN\n"
" /update_action/\n"
"END;\n"
"'"
/* These are used in the SQL comment written above each set of triggers */
", '/from_readable/', from_tbl || '(' || sj(from_col, ', ') || ')'"
", '/to_readable/', to_tbl || '(' || sj(to_col, ', ') || ')'"
", '/on_delete/', on_delete"
", '/on_update/', on_update"
", '/name/', 'genfkey' || min(rowid)"
", '/tbl/', dq(from_tbl)"
", '/ref/', dq(to_tbl)"
", '/key_notnull/', sj('new.' || dq(from_col) || ' IS NOT NULL', ' AND ')"
", '/fkey_list/', sj(to_col, ', ')"
", '/rkey_list/', sj(from_col, ', ')"
", '/cond1/', sj(multireplace('new./from/ == /to/'"
", '/from/', dq(from_col)"
", '/to/', dq(to_col)"
"), ' AND ')"
", '/cond2/', sj(multireplace('old./to/ == /from/'"
", '/from/', dq(from_col)"
", '/to/', dq(to_col)"
"), ' AND ')"
", '/update_action/', CASE on_update "
"WHEN 'SET NULL' THEN "
"multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
", '/setlist/', sj(from_col||' = NULL',', ')"
", '/tbl/', dq(from_tbl)"
", '/where/', sj(from_col||' = old.'||dq(to_col),' AND ')"
")"
"WHEN 'CASCADE' THEN "
"multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
", '/setlist/', sj(dq(from_col)||' = new.'||dq(to_col),', ')"
", '/tbl/', dq(from_tbl)"
", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
")"
"ELSE "
" 'SELECT RAISE(ABORT, ''constraint failed'');'"
"END "
", '/delete_action/', CASE on_delete "
"WHEN 'SET NULL' THEN "
"multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
", '/setlist/', sj(from_col||' = NULL',', ')"
", '/tbl/', dq(from_tbl)"
", '/where/', sj(from_col||' = old.'||dq(to_col),' AND ')"
")"
"WHEN 'CASCADE' THEN "
"multireplace('DELETE FROM /tbl/ WHERE /where/;' "
", '/tbl/', dq(from_tbl)"
", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
")"
"ELSE "
" 'SELECT RAISE(ABORT, ''constraint failed'');'"
"END "
") FROM temp.fkey "
"GROUP BY from_tbl, fkid"
;
int rc;
const int enc = SQLITE_UTF8;
sqlite3 *db = 0;
GenfkeyCb cb;
cb.xData = xData;
cb.pCtx = pCtx;
UNUSED_PARAMETER(zDb);
/* Open the working database handle. */
rc = sqlite3_open(":memory:", &db);
if( rc!=SQLITE_OK ) goto genfkey_exit;
/* Create the special scalar and aggregate functions used by this program. */
sqlite3_create_function(db, "dq", 1, enc, 0, doublequote, 0, 0);
sqlite3_create_function(db, "multireplace", -1, enc, db, multireplace, 0, 0);
sqlite3_create_function(db, "sj", 2, enc, 0, 0, joinStep, joinFinalize);
/* Install the "schema" virtual table module */
installSchemaModule(db, sdb);
/* Create and populate a temp table with the information required to
** build the foreign key triggers. See function populateTempTable()
** for details.
*/
cb.eType = GENFKEY_ERROR;
rc = populateTempTable(db, &cb);
if( rc!=SQLITE_OK ) goto genfkey_exit;
/* Unless the --no-drop option was specified, generate DROP TRIGGER
** statements to drop any triggers in the database generated by a
** previous run of this program.
*/
cb.eType = GENFKEY_DROPTRIGGER;
rc = sqlite3_exec(db,
"SELECT 'DROP TRIGGER main.' || dq(triggername) || ';' FROM triggers"
,invokeCallback, (void *)&cb, 0
);
if( rc!=SQLITE_OK ) goto genfkey_exit;
/* Run the main query to create the trigger definitions. */
cb.eType = GENFKEY_CREATETRIGGER;
rc = sqlite3_exec(db, zSql, invokeCallback, (void *)&cb, 0);
if( rc!=SQLITE_OK ) goto genfkey_exit;
genfkey_exit:
sqlite3_close(db);
return rc;
}
#endif
/* End genfkey logic. */
/*************************************************************************/
/*************************************************************************/
/*
** If the following flag is set, then command execution stops
** at an error if we are not interactive.
@ -926,6 +1781,62 @@ static int run_schema_dump_query(
return rc;
}
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
struct GenfkeyCmd {
sqlite3 *db; /* Database handle */
struct callback_data *pCb; /* Callback data */
int isIgnoreErrors; /* True for --ignore-errors */
int isExec; /* True for --exec */
int isNoDrop; /* True for --no-drop */
int nErr; /* Number of errors seen so far */
};
typedef struct GenfkeyCmd GenfkeyCmd;
static int genfkeyParseArgs(GenfkeyCmd *p, char **azArg, int nArg){
int ii;
memset(p, 0, sizeof(GenfkeyCmd));
for(ii=0; ii<nArg; ii++){
int n = strlen30(azArg[ii]);
if( n>2 && n<10 && 0==strncmp(azArg[ii], "--no-drop", n) ){
p->isNoDrop = 1;
}else if( n>2 && n<16 && 0==strncmp(azArg[ii], "--ignore-errors", n) ){
p->isIgnoreErrors = 1;
}else if( n>2 && n<7 && 0==strncmp(azArg[ii], "--exec", n) ){
p->isExec = 1;
}else{
fprintf(stderr, "unknown option: %s\n", azArg[ii]);
return -1;
}
}
return SQLITE_OK;
}
static int genfkeyCmdCb(void *pCtx, int eType, const char *z){
GenfkeyCmd *p = (GenfkeyCmd *)pCtx;
if( eType==GENFKEY_ERROR && !p->isIgnoreErrors ){
p->nErr++;
fprintf(stderr, "%s\n", z);
}
if( p->nErr==0 && (
(eType==GENFKEY_CREATETRIGGER)
|| (eType==GENFKEY_DROPTRIGGER && !p->isNoDrop)
)){
if( p->isExec ){
sqlite3_exec(p->db, z, 0, 0, 0);
}else{
char *zCol = "sql";
callback((void *)p->pCb, 1, (char **)&z, (char **)&zCol);
}
}
return SQLITE_OK;
}
#endif
/*
** Text of a help message
*/
@ -937,6 +1848,14 @@ static char zHelp[] =
".echo ON|OFF Turn command echo on or off\n"
".exit Exit this program\n"
".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
".genfkey ?OPTIONS? Options are:\n"
" --no-drop: Do not drop old fkey triggers.\n"
" --ignore-errors: Ignore tables with fkey errors\n"
" --exec: Execute generated SQL immediately\n"
" See file tool/genfkey.README in the source \n"
" distribution for further information.\n"
#endif
".header(s) ON|OFF Turn display of headers on or off\n"
".help Show this message\n"
".import FILE TABLE Import data from FILE into TABLE\n"
@ -1240,6 +2159,17 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
if( c=='g' && strncmp(azArg[0], "genfkey", n)==0 ){
GenfkeyCmd cmd;
if( 0==genfkeyParseArgs(&cmd, &azArg[1], nArg-1) ){
cmd.db = p->db;
cmd.pCb = p;
genfkey_create_triggers(p->db, "main", (void *)&cmd, genfkeyCmdCb);
}
}else
#endif
if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
p->showHeader = booleanValue(azArg[1]);

2085
sqlite3.h

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.833 2009/02/05 16:53:43 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.848 2009/03/25 16:51:43 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -444,6 +444,17 @@ extern const int sqlite3one;
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
/*
** Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
#define ROUND8(x) (((x)+7)&~7)
/*
** Round down to the nearest multiple of 8
*/
#define ROUNDDOWN8(x) ((x)&~7)
/*
** An instance of the following structure is used to store the busy-handler
** callback for a given sqlite handle.
@ -675,10 +686,17 @@ struct Schema {
** lookaside malloc subsystem. Each available memory allocation in
** the lookaside subsystem is stored on a linked list of LookasideSlot
** objects.
**
** Lookaside allocations are only allowed for objects that are associated
** with a particular database connection. Hence, schema information cannot
** be stored in lookaside because in shared cache mode the schema information
** is shared by multiple database connections. Therefore, while parsing
** schema information, the Lookaside.bEnabled flag is cleared so that
** lookaside allocations are not used to construct the schema objects.
*/
struct Lookaside {
u16 sz; /* Size of each buffer in bytes */
u8 bEnabled; /* True if use lookaside. False to ignore it */
u8 bEnabled; /* False to disable new lookaside allocations */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
int nOut; /* Number of buffers currently checked out */
int mxOut; /* Highwater mark for nOut */
@ -807,7 +825,19 @@ struct sqlite3 {
#endif
Savepoint *pSavepoint; /* List of active savepoints */
int nSavepoint; /* Number of non-transaction savepoints */
int nStatement; /* Number of nested statement-transactions */
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MASTER
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
*/
sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */
sqlite3 *pUnlockConnection; /* Connection to watch for unlock */
void *pUnlockArg; /* Argument to xUnlockNotify */
void (*xUnlockNotify)(void **, int); /* Unlock notify callback */
sqlite3 *pNextBlocked; /* Next in list of all blocked connections */
#endif
};
/*
@ -847,6 +877,7 @@ struct sqlite3 {
#define SQLITE_SharedCache 0x00080000 /* Cache sharing is enabled */
#define SQLITE_Vtab 0x00100000 /* There exists a virtual table */
#define SQLITE_CommitBusy 0x00200000 /* In the process of committing */
#define SQLITE_ReverseOrder 0x00400000 /* Reverse unordered SELECTs */
/*
** Possible values for the sqlite.magic field.
@ -886,6 +917,7 @@ struct FuncDef {
#define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */
#define SQLITE_FUNC_PRIVATE 0x10 /* Allowed for internal use only */
#define SQLITE_FUNC_COUNT 0x20 /* Built-in count(*) aggregate */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@ -1080,7 +1112,7 @@ struct CollSeq {
** of a SELECT statement.
*/
struct Table {
sqlite3 *db; /* Associated database connection. Might be NULL. */
sqlite3 *dbMem; /* DB connection used for lookaside allocations. */
char *zName; /* Name of the table or view */
int iPKey; /* If not negative, use aCol[iPKey] as the primary key */
int nCol; /* Number of columns in this table */
@ -1091,7 +1123,6 @@ struct Table {
u16 nRef; /* Number of pointers to this Table */
u8 tabFlags; /* Mask of TF_* values */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
Trigger *pTrigger; /* List of SQL triggers on this table */
FKey *pFKey; /* Linked list of all foreign keys in this table */
char *zColAff; /* String defining the affinity of each column */
#ifndef SQLITE_OMIT_CHECK
@ -1106,6 +1137,7 @@ struct Table {
int nModuleArg; /* Number of arguments to the module */
char **azModuleArg; /* Text of all module args. [0] is module name */
#endif
Trigger *pTrigger; /* List of triggers stored in pSchema */
Schema *pSchema; /* Schema that contains this table */
Table *pNextZombie; /* Next on the Parse.pZombieTab list */
};
@ -1363,19 +1395,27 @@ struct AggInfo {
** Each node of an expression in the parse tree is an instance
** of this structure.
**
** Expr.op is the opcode. The integer parser token codes are reused
** as opcodes here. For example, the parser defines TK_GE to be an integer
** code representing the ">=" operator. This same integer code is reused
** Expr.op is the opcode. The integer parser token codes are reused
** as opcodes here. For example, the parser defines TK_GE to be an integer
** code representing the ">=" operator. This same integer code is reused
** to represent the greater-than-or-equal-to operator in the expression
** tree.
**
** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list
** of argument if the expression is a function.
** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
** or TK_STRING), then Expr.token contains the text of the SQL literal. If
** the expression is a variable (TK_VARIABLE), then Expr.token contains the
** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
** then Expr.token contains the name of the function.
**
** Expr.token is the operator token for this node. For some expressions
** that have subexpressions, Expr.token can be the complete text that gave
** rise to the Expr. In the latter case, the token is marked as being
** a compound token.
** Expr.pRight and Expr.pLeft are the left and right subexpressions of a
** binary operator. Either or both may be NULL.
**
** Expr.x.pList is a list of arguments if the expression is an SQL function,
** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)".
** Expr.x.pSelect is used if the expression is a sub-select or an expression of
** the form "<lhs> IN (SELECT ...)". If the EP_xIsSelect bit is set in the
** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
** valid.
**
** An expression of the form ID or ID.ID refers to a column in a table.
** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
@ -1385,10 +1425,9 @@ struct AggInfo {
** value is also stored in the Expr.iAgg column in the aggregate so that
** it can be accessed after all aggregates are computed.
**
** If the expression is a function, the Expr.iTable is an integer code
** representing which function. If the expression is an unbound variable
** marker (a question mark character '?' in the original SQL) then the
** Expr.iTable holds the index number for that variable.
** If the expression is an unbound variable marker (a question mark
** character '?' in the original SQL) then the Expr.iTable holds the index
** number for that variable.
**
** If the expression is a subquery then Expr.iColumn holds an integer
** register number containing the result of the subquery. If the
@ -1396,32 +1435,63 @@ struct AggInfo {
** gives a different answer at different times during statement processing
** then iTable is the address of a subroutine that computes the subquery.
**
** The Expr.pSelect field points to a SELECT statement. The SELECT might
** be the right operand of an IN operator. Or, if a scalar SELECT appears
** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
** operand.
**
** If the Expr is of type OP_Column, and the table it is selecting from
** is a disk table or the "old.*" pseudo-table, then pTab points to the
** corresponding table definition.
**
** ALLOCATION NOTES:
**
** Expr structures may be stored as part of the in-memory database schema,
** for example as part of trigger, view or table definitions. In this case,
** the amount of memory consumed by complex expressions may be significant.
** For this reason, less than sizeof(Expr) bytes may be allocated for some
** Expr structs stored as part of the in-memory database schema.
**
** If the EP_Reduced flag is set in Expr.flags, then only EXPR_REDUCEDSIZE
** bytes of space are allocated for the expression structure. This is enough
** space to store all fields up to and including the "Token span;" field.
**
** If the EP_TokenOnly flag is set in Expr.flags, then only EXPR_TOKENONLYSIZE
** bytes of space are allocated for the expression structure. This is enough
** space to store all fields up to and including the "Token token;" field.
*/
struct Expr {
u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */
u16 flags; /* Various flags. See below */
CollSeq *pColl; /* The collation type of the column or 0 */
Expr *pLeft, *pRight; /* Left and right subnodes */
ExprList *pList; /* A list of expressions used as function arguments
** or in "<expr> IN (<expr-list)" */
VVA_ONLY(u8 vvaFlags;) /* Flags used for VV&A only. EVVA_* below. */
u16 flags; /* Various flags. EP_* See below */
Token token; /* An operand token */
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
Token span; /* Complete text of the expression */
/* If the EP_SpanOnly flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
Expr *pLeft; /* Left subnode */
Expr *pRight; /* Right subnode */
union {
ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
} x;
CollSeq *pColl; /* The collation type of the column or 0 */
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** iColumn-th field of the iTable-th table. */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
Select *pSelect; /* When the expression is a sub-select. Also the
** right side of "<expr> IN (<select>)" */
Table *pTab; /* Table for TK_COLUMN expressions. */
#if SQLITE_MAX_EXPR_DEPTH>0
int nHeight; /* Height of the tree headed by this node */
@ -1443,6 +1513,21 @@ struct Expr {
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
#define EP_IntValue 0x0800 /* Integer value contained in iTable */
#define EP_xIsSelect 0x1000 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
#define EP_SpanOnly 0x8000 /* Expr struct is EXPR_SPANONLYSIZE bytes only */
/*
** The following are the meanings of bits in the Expr.vvaFlags field.
** This information is only used when SQLite is compiled with
** SQLITE_DEBUG defined.
*/
#ifndef NDEBUG
#define EVVA_ReadOnlyToken 0x01 /* Expr.token.z is read-only */
#endif
/*
** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
@ -1452,6 +1537,24 @@ struct Expr {
#define ExprSetProperty(E,P) (E)->flags|=(P)
#define ExprClearProperty(E,P) (E)->flags&=~(P)
/*
** Macros to determine the number of bytes required by a normal Expr
** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
** and an Expr struct with the EP_TokenOnly flag set.
*/
#define EXPR_FULLSIZE sizeof(Expr)
#define EXPR_REDUCEDSIZE offsetof(Expr,iTable)
#define EXPR_TOKENONLYSIZE offsetof(Expr,span)
#define EXPR_SPANONLYSIZE offsetof(Expr,pLeft)
/*
** Flags passed to the sqlite3ExprDup() function. See the header comment
** above sqlite3ExprDup() for details.
*/
#define EXPRDUP_REDUCE 0x0001
#define EXPRDUP_SPAN 0x0002
#define EXPRDUP_DISTINCTSPAN 0x0004
/*
** A list of expressions. Each expression may optionally have a
** name. An expr/name combination can be used in several ways, such
@ -2237,7 +2340,7 @@ void sqlite3SetString(char **, sqlite3*, const char*, ...);
void sqlite3ErrorMsg(Parse*, const char*, ...);
void sqlite3ErrorClear(Parse*);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(sqlite3*, Expr*);
void sqlite3DequoteExpr(Expr*);
int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
@ -2379,12 +2482,12 @@ void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
Expr *sqlite3ExprDup(sqlite3*,Expr*);
void sqlite3TokenCopy(sqlite3*,Token*, Token*);
ExprList *sqlite3ExprListDup(sqlite3*,ExprList*);
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*);
Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
void sqlite3TokenCopy(sqlite3*,Token*,const Token*);
ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
IdList *sqlite3IdListDup(sqlite3*,IdList*);
Select *sqlite3SelectDup(sqlite3*,Select*);
Select *sqlite3SelectDup(sqlite3*,Select*,int);
void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
void sqlite3RegisterBuiltinFunctions(sqlite3*);
@ -2411,9 +2514,10 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
void sqlite3DropTrigger(Parse*, SrcList*, int);
void sqlite3DropTriggerPtr(Parse*, Trigger*);
int sqlite3TriggersExist(Table*, int, ExprList*);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
int, int, u32*, u32*);
Trigger *sqlite3TriggersExist(Parse *, Table*, int, ExprList*, int *pMask);
Trigger *sqlite3TriggerList(Parse *, Table *);
int sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *,
int, int, int, int, u32*, u32*);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
@ -2428,7 +2532,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
# define sqlite3DeleteTrigger(A,B)
# define sqlite3DropTriggerPtr(A,B)
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J,K) 0
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J,K,L) 0
#endif
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
@ -2686,6 +2790,17 @@ int sqlite3IsMemJournal(sqlite3_file *);
u32 sqlite3Get4byte(const u8*);
void sqlite3Put4byte(u8*, u32);
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
void sqlite3ConnectionBlocked(sqlite3 *, sqlite3 *);
void sqlite3ConnectionUnlocked(sqlite3 *db);
void sqlite3ConnectionClosed(sqlite3 *db);
#else
#define sqlite3ConnectionBlocked(x,y)
#define sqlite3ConnectionUnlocked(x)
#define sqlite3ConnectionClosed(x)
#endif
#ifdef SQLITE_SSE
#include "sseInt.h"
#endif

View file

@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.153 2009/01/20 16:53:41 danielk1977 Exp $
** $Id: tokenize.c,v 1.155 2009/03/31 03:41:57 shane Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -381,14 +381,17 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
** error message.
*/
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int nErr = 0;
int i;
void *pEngine;
int tokenType;
int lastTokenParsed = -1;
sqlite3 *db = pParse->db;
int mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
int nErr = 0; /* Number of errors encountered */
int i; /* Loop counter */
void *pEngine; /* The LEMON-generated LALR(1) parser */
int tokenType; /* type of the next token */
int lastTokenParsed = -1; /* type of the previous token */
u8 enableLookaside; /* Saved value of db->lookaside.bEnabled */
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
if( db->activeVdbeCnt==0 ){
db->u1.isInterrupted = 0;
}
@ -408,6 +411,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->nVarExpr==0 );
assert( pParse->nVarExprAlloc==0 );
assert( pParse->apVarExpr==0 );
enableLookaside = db->lookaside.bEnabled;
if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
while( !db->mallocFailed && zSql[i]!=0 ){
assert( i>=0 );
pParse->sLastToken.z = (u8*)&zSql[i];
@ -462,6 +467,7 @@ abort_parse:
);
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
db->lookaside.bEnabled = enableLookaside;
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
}

150
trigger.c
View file

@ -10,7 +10,7 @@
*************************************************************************
**
**
** $Id: trigger.c,v 1.133 2008/12/26 07:56:39 danielk1977 Exp $
** $Id: trigger.c,v 1.135 2009/02/28 10:47:42 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -33,6 +33,30 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
}
}
/*
** Given table pTab, return a list of all the triggers attached to
** the table. The list is connected by Trigger.pNext pointers.
*/
Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
Schema * const pTmpSchema = pParse->db->aDb[1].pSchema;
Trigger *pList = 0; /* List of triggers to return */
if( pTmpSchema!=pTab->pSchema ){
HashElem *p;
for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
Trigger *pTrig = (Trigger *)sqliteHashData(p);
if( pTrig->pTabSchema==pTab->pSchema
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName)
){
pTrig->pNext = (pList ? pList : pTab->pTrigger);
pList = pTrig;
}
}
}
return (pList ? pList : pTab->pTrigger);
}
/*
** This is called by the parser when it sees a CREATE TRIGGER statement
** up to the point of the BEGIN before the trigger actions. A Trigger
@ -182,7 +206,7 @@ void sqlite3BeginTrigger(
pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = (u8)op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(db, pWhen);
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 );
@ -209,14 +233,16 @@ void sqlite3FinishTrigger(
TriggerStep *pStepList, /* The triggered program */
Token *pAll /* Token that describes the complete CREATE TRIGGER */
){
Trigger *pTrig = 0; /* The trigger whose construction is finishing up */
sqlite3 *db = pParse->db; /* The database */
Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */
char *zName; /* Name of trigger */
sqlite3 *db = pParse->db; /* The database */
DbFixer sFix;
int iDb; /* Database containing the trigger */
int iDb; /* Database containing the trigger */
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
zName = pTrig->name;
iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
pTrig->step_list = pStepList;
while( pStepList ){
@ -242,32 +268,29 @@ void sqlite3FinishTrigger(
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
sqlite3NestedParse(pParse,
"INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name,
db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName,
pTrig->table, z);
sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC
db, "type='trigger' AND name='%q'", zName), P4_DYNAMIC
);
}
if( db->init.busy ){
int n;
Table *pTab;
Trigger *pDel;
pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
pTrig->name, sqlite3Strlen30(pTrig->name), pTrig);
if( pDel ){
assert( pDel==pTrig );
Trigger *pLink = pTrig;
Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig);
if( pTrig ){
db->mallocFailed = 1;
goto triggerfinish_cleanup;
}else if( pLink->pSchema==pLink->pTabSchema ){
Table *pTab;
int n = sqlite3Strlen30(pLink->table) + 1;
pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table, n);
assert( pTab!=0 );
pLink->pNext = pTab->pTrigger;
pTab->pTrigger = pLink;
}
n = sqlite3Strlen30(pTrig->table) + 1;
pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
assert( pTab!=0 );
pTrig->pNext = pTab->pTrigger;
pTab->pTrigger = pTrig;
pTrig = 0;
}
triggerfinish_cleanup:
@ -292,17 +315,17 @@ static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
p->target.dyn = 1;
}
if( p->pSelect ){
Select *pNew = sqlite3SelectDup(db, p->pSelect);
Select *pNew = sqlite3SelectDup(db, p->pSelect, 1);
sqlite3SelectDelete(db, p->pSelect);
p->pSelect = pNew;
}
if( p->pWhere ){
Expr *pNew = sqlite3ExprDup(db, p->pWhere);
Expr *pNew = sqlite3ExprDup(db, p->pWhere, EXPRDUP_REDUCE);
sqlite3ExprDelete(db, p->pWhere);
p->pWhere = pNew;
}
if( p->pExprList ){
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList, 1);
sqlite3ExprListDelete(db, p->pExprList);
p->pExprList = pNew;
}
@ -546,6 +569,9 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->name, 0);
if( pParse->nMem<3 ){
pParse->nMem = 3;
}
}
}
@ -553,25 +579,15 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
** Remove a trigger from the hash tables of the sqlite* pointer.
*/
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Hash *pHash = &(db->aDb[iDb].pSchema->trigHash);
Trigger *pTrigger;
int nName = sqlite3Strlen30(zName);
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash),
zName, nName, 0);
pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0);
if( pTrigger ){
Table *pTable = tableOfTrigger(pTrigger);
assert( pTable!=0 );
if( pTable->pTrigger == pTrigger ){
pTable->pTrigger = pTrigger->pNext;
}else{
Trigger *cc = pTable->pTrigger;
while( cc ){
if( cc->pNext == pTrigger ){
cc->pNext = cc->pNext->pNext;
break;
}
cc = cc->pNext;
}
assert(cc);
if( pTrigger->pSchema==pTrigger->pTabSchema ){
Table *pTab = tableOfTrigger(pTrigger);
Trigger **pp;
for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
*pp = (*pp)->pNext;
}
sqlite3DeleteTrigger(db, pTrigger);
db->flags |= SQLITE_InternChanges;
@ -597,30 +613,31 @@ static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
}
/*
** Return a bit vector to indicate what kind of triggers exist for operation
** "op" on table pTab. If pChanges is not NULL then it is a list of columns
** that are being updated. Triggers only match if the ON clause of the
** trigger definition overlaps the set of columns being updated.
**
** The returned bit vector is some combination of TRIGGER_BEFORE and
** TRIGGER_AFTER.
** Return a list of all triggers on table pTab if there exists at least
** one trigger that must be fired when an operation of type 'op' is
** performed on the table, and, if that operation is an UPDATE, if at
** least one of the columns in pChanges is being modified.
*/
int sqlite3TriggersExist(
Trigger *sqlite3TriggersExist(
Parse *pParse, /* Parse context */
Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
ExprList *pChanges /* Columns that change in an UPDATE statement */
ExprList *pChanges, /* Columns that change in an UPDATE statement */
int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
){
Trigger *pTrigger;
int mask = 0;
pTrigger = IsVirtual(pTab) ? 0 : pTab->pTrigger;
while( pTrigger ){
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
mask |= pTrigger->tr_tm;
Trigger *pList = sqlite3TriggerList(pParse, pTab);
Trigger *p;
assert( pList==0 || IsVirtual(pTab)==0 );
for(p=pList; p; p=p->pNext){
if( p->op==op && checkColumnOverLap(p->pColumns, pChanges) ){
mask |= p->tr_tm;
}
pTrigger = pTrigger->pNext;
}
return mask;
if( pMask ){
*pMask = mask;
}
return (mask ? pList : 0);
}
/*
@ -677,7 +694,7 @@ static int codeTriggerProgram(
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
case TK_SELECT: {
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect);
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect, 0);
if( ss ){
SelectDest dest;
@ -692,8 +709,8 @@ static int codeTriggerProgram(
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Update(pParse, pSrc,
sqlite3ExprListDup(db, pTriggerStep->pExprList),
sqlite3ExprDup(db, pTriggerStep->pWhere), orconf);
sqlite3ExprListDup(db, pTriggerStep->pExprList, 0),
sqlite3ExprDup(db, pTriggerStep->pWhere, 0), orconf);
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
@ -702,8 +719,8 @@ static int codeTriggerProgram(
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc,
sqlite3ExprListDup(db, pTriggerStep->pExprList),
sqlite3SelectDup(db, pTriggerStep->pSelect),
sqlite3ExprListDup(db, pTriggerStep->pExprList, 0),
sqlite3SelectDup(db, pTriggerStep->pSelect, 0),
sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
@ -713,7 +730,7 @@ static int codeTriggerProgram(
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3DeleteFrom(pParse, pSrc,
sqlite3ExprDup(db, pTriggerStep->pWhere));
sqlite3ExprDup(db, pTriggerStep->pWhere, 0));
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
@ -757,6 +774,7 @@ static int codeTriggerProgram(
*/
int sqlite3CodeRowTrigger(
Parse *pParse, /* Parse context */
Trigger *pTrigger, /* List of triggers on table pTab */
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
@ -780,7 +798,7 @@ int sqlite3CodeRowTrigger(
assert(newIdx != -1 || oldIdx != -1);
for(p=pTab->pTrigger; p; p=p->pNext){
for(p=pTrigger; p; p=p->pNext){
int fire_this = 0;
/* Determine whether we should code this trigger */
@ -830,7 +848,7 @@ int sqlite3CodeRowTrigger(
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
whenExpr = sqlite3ExprDup(db, p->pWhen);
whenExpr = sqlite3ExprDup(db, p->pWhen, 0);
if( db->mallocFailed || sqlite3ResolveExprNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(db, whenExpr);

View file

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.191 2008/12/23 23:56:22 drh Exp $
** $Id: update.c,v 1.196 2009/02/28 10:47:42 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -107,7 +107,7 @@ void sqlite3Update(
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
int triggers_exist = 0; /* True if any row triggers exist */
Trigger *pTrigger; /* List of triggers on pTab, if required */
#endif
int iBeginAfterTrigger = 0; /* Address of after trigger program */
int iEndAfterTrigger = 0; /* Exit of after trigger program */
@ -143,10 +143,10 @@ void sqlite3Update(
** updated is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pTab, TK_UPDATE, pChanges);
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, 0);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define pTrigger 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
@ -154,7 +154,7 @@ void sqlite3Update(
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
goto update_cleanup;
}
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
@ -167,7 +167,7 @@ void sqlite3Update(
/* If there are FOR EACH ROW triggers, allocate cursors for the
** special OLD and NEW tables
*/
if( triggers_exist ){
if( pTrigger ){
newIdx = pParse->nTab++;
oldIdx = pParse->nTab++;
}
@ -299,27 +299,27 @@ void sqlite3Update(
/* Generate the code for triggers.
*/
if( triggers_exist ){
if( pTrigger ){
int iGoto;
/* Create pseudo-tables for NEW and OLD
*/
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, oldIdx, 0, pTab->nCol);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, newIdx, 0, pTab->nCol);
iGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
addr = sqlite3VdbeMakeLabel(v);
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
if( sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
TRIGGER_BEFORE, pTab, newIdx, oldIdx, onError, addr,
&old_col_mask, &new_col_mask) ){
goto update_cleanup;
}
iEndBeforeTrigger = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
if( sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
TRIGGER_AFTER, pTab, newIdx, oldIdx, onError, addr,
&old_col_mask, &new_col_mask) ){
goto update_cleanup;
}
iEndAfterTrigger = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
@ -399,7 +399,7 @@ void sqlite3Update(
}
/* Jump back to this point if a trigger encounters an IGNORE constraint. */
if( triggers_exist ){
if( pTrigger ){
sqlite3VdbeResolveLabel(v, addr);
}
@ -412,7 +412,7 @@ void sqlite3Update(
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, 0, regOldRowid);
}
if( triggers_exist ){
if( pTrigger ){
int regRowid;
int regRow;
int regCols;
@ -541,7 +541,7 @@ void sqlite3Update(
/* If there are triggers, close all the cursors after each iteration
** through the loop. The fire the after triggers.
*/
if( triggers_exist ){
if( pTrigger ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
@ -559,7 +559,7 @@ void sqlite3Update(
}
}
sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
if( triggers_exist ){
if( pTrigger ){
sqlite3VdbeAddOp2(v, OP_Close, newIdx, 0);
sqlite3VdbeAddOp2(v, OP_Close, oldIdx, 0);
}
@ -633,12 +633,12 @@ static void updateVirtualTable(
sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
if( pRowid ){
pEList = sqlite3ExprListAppend(pParse, pEList,
sqlite3ExprDup(db, pRowid), 0);
sqlite3ExprDup(db, pRowid, 0), 0);
}
assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr);
pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0);
}else{
pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
}

4
utf.c
View file

@ -12,7 +12,7 @@
** This file contains routines used to translate between UTF-8,
** UTF-16, UTF-16BE, and UTF-16LE.
**
** $Id: utf.c,v 1.70 2008/12/10 22:30:25 shane Exp $
** $Id: utf.c,v 1.71 2009/03/31 03:41:57 shane Exp $
**
** Notes on UTF-8:
**
@ -417,7 +417,7 @@ int sqlite3Utf8To8(unsigned char *zIn){
}
}
*zOut = 0;
return zOut - zStart;
return (int)(zOut - zStart);
}
#endif

10
util.c
View file

@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.248 2009/02/04 03:59:25 shane Exp $
** $Id: util.c,v 1.249 2009/03/01 22:29:20 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@ -694,7 +694,7 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
/* a: p2<<28 | p4<<14 | p6 (unmasked) */
if (!(a&0x80))
{
a &= (0x7f<<28)|(0x7f<<14)|(0x7f);
a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
b &= (0x7f<<14)|(0x7f);
b = b<<7;
a |= b;
@ -711,7 +711,7 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
/* b: p3<<28 | p5<<14 | p7 (unmasked) */
if (!(b&0x80))
{
b &= (0x7f<<28)|(0x7f<<14)|(0x7f);
b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
/* moved CSE2 up */
/* a &= (0x7f<<14)|(0x7f); */
a = a<<7;
@ -806,8 +806,8 @@ u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
if (!(a&0x80))
{
a &= (0x7f<<28)|(0x7f<<14)|(0x7f);
b &= (0x7f<<28)|(0x7f<<14)|(0x7f);
a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
b = b<<7;
*v = a | b;
return 5;

294
vdbe.c
View file

@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.817 2009/02/16 17:55:47 shane Exp $
** $Id: vdbe.c,v 1.828 2009/03/23 17:11:27 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -187,7 +187,7 @@ int sqlite3VdbeOpcodeHasProperty(int opcode, int mask){
static VdbeCursor *allocateCursor(
Vdbe *p, /* The virtual machine */
int iCur, /* Index of the new VdbeCursor */
Op *pOp, /* */
int nField, /* Number of fields in the table or index */
int iDb, /* When database the cursor belongs to, or -1 */
int isBtreeCursor /* */
){
@ -213,15 +213,6 @@ static VdbeCursor *allocateCursor(
int nByte;
VdbeCursor *pCx = 0;
/* If the opcode of pOp is OP_SetNumColumns, then pOp->p2 contains
** the number of fields in the records contained in the table or
** index being opened. Use this to reserve space for the
** VdbeCursor.aType[] array.
*/
int nField = 0;
if( pOp->opcode==OP_SetNumColumns || pOp->opcode==OP_OpenEphemeral ){
nField = pOp->p2;
}
nByte =
sizeof(VdbeCursor) +
(isBtreeCursor?sqlite3BtreeCursorSize():0) +
@ -563,7 +554,7 @@ int sqlite3VdbeExec(
Mem *pOut = 0; /* Output operand */
u8 opProperty;
int iCompare = 0; /* Result of last OP_Compare operation */
int *aPermute = 0; /* Permuation of columns for OP_Compare */
int *aPermute = 0; /* Permutation of columns for OP_Compare */
#ifdef VDBE_PROFILE
u64 start; /* CPU clock count at start of opcode */
int origPc; /* Program counter at start of opcode */
@ -819,6 +810,16 @@ case OP_Yield: { /* in1 */
break;
}
/* Opcode: HaltIfNull P1 P2 P3 P4 *
**
** Check the value in register P3. If is is NULL then Halt using
** parameter P1, P2, and P4 as if this were a Halt instruction. If the
** value in register P3 is not NULL, then this routine is a no-op.
*/
case OP_HaltIfNull: { /* in3 */
if( (pIn3->flags & MEM_Null)==0 ) break;
/* Fall through into OP_Halt */
}
/* Opcode: Halt P1 P2 * P4 *
**
@ -967,26 +968,34 @@ case OP_Blob: { /* out2-prerelease */
break;
}
/* Opcode: Variable P1 P2 * * *
/* Opcode: Variable P1 P2 P3 P4 *
**
** The value of variable P1 is written into register P2. A variable is
** an unknown in the original SQL string as handed to sqlite3_compile().
** Any occurrence of the '?' character in the original SQL is considered
** a variable. Variables in the SQL string are number from left to
** right beginning with 1. The values of variables are set using the
** sqlite3_bind() API.
** Transfer the values of bound parameters P1..P1+P3-1 into registers
** P2..P2+P3-1.
**
** If the parameter is named, then its name appears in P4 and P3==1.
** The P4 value is used by sqlite3_bind_parameter_name().
*/
case OP_Variable: { /* out2-prerelease */
case OP_Variable: {
int j = pOp->p1 - 1;
int k = pOp->p2;
Mem *pVar;
assert( j>=0 && j<p->nVar );
int n = pOp->p3;
assert( j>=0 && j+n<=p->nVar );
assert( k>=1 && k+n-1<=p->nMem );
assert( pOp->p4.z==0 || pOp->p3==1 );
pVar = &p->aVar[j];
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
while( n-- > 0 ){
pVar = &p->aVar[j++];
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
}
pOut = &p->aMem[k++];
sqlite3VdbeMemReleaseExternal(pOut);
pOut->flags = MEM_Null;
sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
}
sqlite3VdbeMemShallowCopy(pOut, &p->aVar[j], MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@ -1002,15 +1011,14 @@ case OP_Move: {
int n = pOp->p3;
int p1 = pOp->p1;
int p2 = pOp->p2;
assert( n>0 );
assert( p1>0 );
assert( p1+n<p->nMem );
pIn1 = &p->aMem[p1];
assert( p2>0 );
assert( p2+n<p->nMem );
pOut = &p->aMem[p2];
assert( n>0 && p1>0 && p2>0 );
assert( p1+n<=p2 || p2+n<=p1 );
pIn1 = &p->aMem[p1];
pOut = &p->aMem[p2];
while( n-- ){
assert( pOut<=&p->aMem[p->nMem] );
assert( pIn1<=&p->aMem[p->nMem] );
zMalloc = pOut->zMalloc;
pOut->zMalloc = 0;
sqlite3VdbeMemMove(pOut, pIn1);
@ -1076,7 +1084,24 @@ case OP_ResultRow: {
int i;
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
assert( pOp->p1+pOp->p2<=p->nMem );
assert( pOp->p1+pOp->p2<=p->nMem+1 );
/* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then
** DML statements invoke this opcode to return the number of rows
** modified to the user. This is the only way that a VM that
** opens a statement transaction may invoke this opcode.
**
** In case this is such a statement, close any statement transaction
** opened by this VM before returning control to the user. This is to
** ensure that statement-transactions are always nested, not overlapping.
** If the open statement-transaction is not closed here, then the user
** may step another VM that opens its own statement transaction. This
** may lead to overlapping statement transactions.
*/
assert( p->iStatement==0 || db->flags&SQLITE_CountRows );
if( SQLITE_OK!=(rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE)) ){
break;
}
/* Invalidate all ephemeral cursor row caches */
p->cacheCtr = (p->cacheCtr + 2)|1;
@ -1095,7 +1120,6 @@ case OP_ResultRow: {
/* Return SQLITE_ROW
*/
p->nCallback++;
p->pc = pc + 1;
rc = SQLITE_ROW;
goto vdbe_return;
@ -1300,7 +1324,7 @@ case OP_Function: {
apVal = p->apArg;
assert( apVal || n==0 );
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem) );
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pArg = &p->aMem[pOp->p2];
for(i=0; i<n; i++, pArg++){
@ -1701,7 +1725,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
/* Opcode: Permutation * * * P4 *
**
** Set the permuation used by the OP_Compare operator to be the array
** Set the permutation used by the OP_Compare operator to be the array
** of integers in P4.
**
** The permutation is only valid until the next OP_Permutation, OP_Compare,
@ -1736,9 +1760,9 @@ case OP_Compare: {
assert( n>0 );
assert( pKeyInfo!=0 );
p1 = pOp->p1;
assert( p1>0 && p1+n-1<p->nMem );
assert( p1>0 && p1+n<=p->nMem+1 );
p2 = pOp->p2;
assert( p2>0 && p2+n-1<p->nMem );
assert( p2>0 && p2+n<=p->nMem+1 );
for(i=0; i<n; i++){
int idx = aPermute ? aPermute[i] : i;
CollSeq *pColl; /* Collating sequence to use on this term */
@ -1932,9 +1956,11 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** this opcode must be present immediately before the opcode that
** opens the cursor.
*/
#if 0
case OP_SetNumColumns: {
break;
}
#endif
/* Opcode: Column P1 P2 P3 P4 *
**
@ -2253,7 +2279,7 @@ case OP_MakeRecord: {
nField = pOp->p1;
zAffinity = pOp->p4.z;
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem );
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem+1 );
pData0 = &p->aMem[nField];
nField = pOp->p2;
pLast = &pData0[nField-1];
@ -2330,6 +2356,22 @@ case OP_MakeRecord: {
break;
}
/* Opcode: Count P1 P2 * * *
**
** Store the number of entries (an integer value) in the table or index
** opened by cursor P1 in register P2
*/
#ifndef SQLITE_OMIT_BTREECOUNT
case OP_Count: { /* out2-prerelease */
i64 nEntry;
BtCursor *pCrsr = p->apCsr[pOp->p1]->pCursor;
rc = sqlite3BtreeCount(pCrsr, &nEntry);
pOut->flags = MEM_Int;
pOut->u.i = nEntry;
break;
}
#endif
/* Opcode: Statement P1 * * * *
**
** Begin an individual statement transaction which is part of a larger
@ -2361,10 +2403,12 @@ case OP_Statement: {
pBt = db->aDb[i].pBt;
assert( sqlite3BtreeIsInTrans(pBt) );
assert( (p->btreeMask & (1<<i))!=0 );
if( !sqlite3BtreeIsInStmt(pBt) ){
rc = sqlite3BtreeBeginStmt(pBt);
p->openedStatement = 1;
if( p->iStatement==0 ){
assert( db->nStatement>=0 && db->nSavepoint>=0 );
db->nStatement++;
p->iStatement = db->nSavepoint + db->nStatement;
}
rc = sqlite3BtreeBeginStmt(pBt, p->iStatement);
}
break;
}
@ -2471,7 +2515,7 @@ case OP_Savepoint: {
rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}
}
if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
sqlite3ExpirePreparedStatements(db);
@ -2507,7 +2551,8 @@ case OP_Savepoint: {
**
** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
** back any currently active btree transactions. If there are any active
** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails.
** VMs (apart from this one), then a ROLLBACK fails. A COMMIT fails if
** there are active writing VMs or active VMs that use shared cache.
**
** This instruction causes the VM to halt.
*/
@ -2550,6 +2595,7 @@ case OP_AutoCommit: {
goto vdbe_return;
}
}
assert( db->nStatement==0 );
sqlite3CloseSavepoints(db);
if( p->rc==SQLITE_OK ){
rc = SQLITE_DONE;
@ -2767,9 +2813,11 @@ case OP_VerifyCookie: {
** to get a read lock but fails, the script terminates with an
** SQLITE_BUSY error code.
**
** The P4 value is a pointer to a KeyInfo structure that defines the
** content and collating sequence of indices. P4 is NULL for cursors
** that are not pointing to indices.
** The P4 value may be either an integer (P4_INT32) or a pointer to
** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
** structure, then said structure defines the content and collating
** sequence of the index being opened. Otherwise, if P4 is an integer
** value, it is set to the number of columns in the table.
**
** See also OpenWrite.
*/
@ -2779,9 +2827,11 @@ case OP_VerifyCookie: {
** page is P2. Or if P5!=0 use the content of register P2 to find the
** root page.
**
** The P4 value is a pointer to a KeyInfo structure that defines the
** content and collating sequence of indices. P4 is NULL for cursors
** that are not pointing to indices.
** The P4 value may be either an integer (P4_INT32) or a pointer to
** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
** structure, then said structure defines the content and collating
** sequence of the index being opened. Otherwise, if P4 is an integer
** value, it is set to the number of columns in the table.
**
** This instruction works just like OpenRead except that it opens the cursor
** in read/write mode. For a given table, there can be one or more read-only
@ -2791,6 +2841,8 @@ case OP_VerifyCookie: {
*/
case OP_OpenRead:
case OP_OpenWrite: {
int nField = 0;
KeyInfo *pKeyInfo = 0;
int i = pOp->p1;
int p2 = pOp->p2;
int iDb = pOp->p3;
@ -2824,16 +2876,19 @@ case OP_OpenWrite: {
}
}
assert( i>=0 );
pCur = allocateCursor(p, i, &pOp[-1], iDb, 1);
if( pOp->p4type==P4_KEYINFO ){
pKeyInfo = pOp->p4.pKeyInfo;
pKeyInfo->enc = ENC(p->db);
nField = pKeyInfo->nField+1;
}else if( pOp->p4type==P4_INT32 ){
nField = pOp->p4.i;
}
pCur = allocateCursor(p, i, nField, iDb, 1);
if( pCur==0 ) goto no_mem;
pCur->nullRow = 1;
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, pCur->pCursor);
if( pOp->p4type==P4_KEYINFO ){
pCur->pKeyInfo = pOp->p4.pKeyInfo;
pCur->pKeyInfo->enc = ENC(p->db);
}else{
pCur->pKeyInfo = 0;
}
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
pCur->pKeyInfo = pKeyInfo;
switch( rc ){
case SQLITE_BUSY: {
p->pc = pc;
@ -2908,7 +2963,7 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_TRANSIENT_DB;
assert( i>=0 );
pCx = allocateCursor(p, i, pOp, -1, 1);
pCx = allocateCursor(p, i, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags,
@ -2943,7 +2998,7 @@ case OP_OpenEphemeral: {
break;
}
/* Opcode: OpenPseudo P1 P2 * * *
/* Opcode: OpenPseudo P1 P2 P3 * *
**
** Open a new cursor that points to a fake table that contains a single
** row of data. Any attempt to write a second row of data causes the
@ -2962,12 +3017,15 @@ case OP_OpenEphemeral: {
** is stored. In this case, the vdbe program must ensure that the
** memory cell containing the row data is not overwritten until the
** pseudo table is closed (or a new row is inserted into it).
**
** P3 is the number of fields in the records that will be stored by
** the pseudo-table.
*/
case OP_OpenPseudo: {
int i = pOp->p1;
VdbeCursor *pCx;
assert( i>=0 );
pCx = allocateCursor(p, i, &pOp[-1], -1, 0);
pCx = allocateCursor(p, i, pOp->p3, -1, 0);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->pseudoTable = 1;
@ -3512,9 +3570,8 @@ case OP_NewRowid: { /* out2-prerelease */
#endif
if( !pC->useRandomRowid ){
if( pC->nextRowidValid ){
v = pC->nextRowid;
}else{
v = sqlite3BtreeGetCachedRowid(pC->pCursor);
if( v==0 ){
rc = sqlite3BtreeLast(pC->pCursor, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
@ -3551,12 +3608,7 @@ case OP_NewRowid: { /* out2-prerelease */
}
#endif
if( v<MAX_ROWID ){
pC->nextRowidValid = 1;
pC->nextRowid = v+1;
}else{
pC->nextRowidValid = 0;
}
sqlite3BtreeSetCachedRowid(pC->pCursor, v<MAX_ROWID ? v+1 : 0);
}
if( pC->useRandomRowid ){
assert( pOp->p3==0 ); /* SQLITE_FULL must have occurred prior to this */
@ -3634,9 +3686,6 @@ case OP_Insert: {
iKey = intToKey(pKey->u.i);
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = pKey->u.i;
if( pC->nextRowidValid && pKey->u.i>=pC->nextRowid ){
pC->nextRowidValid = 0;
}
if( pData->flags & MEM_Null ){
pData->z = 0;
pData->n = 0;
@ -3671,6 +3720,7 @@ case OP_Insert: {
}else{
nZero = 0;
}
sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
pData->z, pData->n, nZero,
pOp->p5 & OPFLAG_APPEND);
@ -3733,8 +3783,8 @@ case OP_Delete: {
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
rc = sqlite3BtreeDelete(pC->pCursor);
pC->nextRowidValid = 0;
pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
@ -4066,7 +4116,7 @@ case OP_IdxDelete: {
VdbeCursor *pC;
BtCursor *pCrsr;
assert( pOp->p3>0 );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
@ -4242,7 +4292,7 @@ case OP_Destroy: { /* out2-prerelease */
** P2==1 then the table to be clear is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If the P3 value is non-zero, then the table refered to must be an
** If the P3 value is non-zero, then the table referred to must be an
** intkey table (an SQL table, not an index). In this case the row change
** count is incremented by the number of rows in the table being cleared.
** If P3 is greater than zero, then the value stored in register P3 is
@ -4321,33 +4371,58 @@ case OP_CreateTable: { /* out2-prerelease */
** then runs the new virtual machine. It is thus a re-entrant opcode.
*/
case OP_ParseSchema: {
char *zSql;
int iDb = pOp->p1;
const char *zMaster;
InitData initData;
assert( iDb>=0 && iDb<db->nDb );
if( !pOp->p2 && !DbHasProperty(db, iDb, DB_SchemaLoaded) ){
break;
/* If pOp->p2 is 0, then this opcode is being executed to read a
** single row, for example the row corresponding to a new index
** created by this VDBE, from the sqlite_master table. It only
** does this if the corresponding in-memory schema is currently
** loaded. Otherwise, the new index definition can be loaded along
** with the rest of the schema when it is required.
**
** Although the mutex on the BtShared object that corresponds to
** database iDb (the database containing the sqlite_master table
** read by this instruction) is currently held, it is necessary to
** obtain the mutexes on all attached databases before checking if
** the schema of iDb is loaded. This is because, at the start of
** the sqlite3_exec() call below, SQLite will invoke
** sqlite3BtreeEnterAll(). If all mutexes are not already held, the
** iDb mutex may be temporarily released to avoid deadlock. If
** this happens, then some other thread may delete the in-memory
** schema of database iDb before the SQL statement runs. The schema
** will not be reloaded becuase the db->init.busy flag is set. This
** can result in a "no such table: sqlite_master" or "malformed
** database schema" error being returned to the user.
*/
assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
sqlite3BtreeEnterAll(db);
if( pOp->p2 || DbHasProperty(db, iDb, DB_SchemaLoaded) ){
const char *zMaster = SCHEMA_TABLE(iDb);
char *zSql;
InitData initData;
initData.db = db;
initData.iDb = pOp->p1;
initData.pzErrMsg = &p->zErrMsg;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
db->aDb[iDb].zName, zMaster, pOp->p4.z);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
(void)sqlite3SafetyOff(db);
assert( db->init.busy==0 );
db->init.busy = 1;
initData.rc = SQLITE_OK;
assert( !db->mallocFailed );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_OK ) rc = initData.rc;
sqlite3DbFree(db, zSql);
db->init.busy = 0;
(void)sqlite3SafetyOn(db);
}
}
zMaster = SCHEMA_TABLE(iDb);
initData.db = db;
initData.iDb = pOp->p1;
initData.pzErrMsg = &p->zErrMsg;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
db->aDb[iDb].zName, zMaster, pOp->p4.z);
if( zSql==0 ) goto no_mem;
(void)sqlite3SafetyOff(db);
assert( db->init.busy==0 );
db->init.busy = 1;
initData.rc = SQLITE_OK;
assert( !db->mallocFailed );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_OK ) rc = initData.rc;
sqlite3DbFree(db, zSql);
db->init.busy = 0;
(void)sqlite3SafetyOn(db);
sqlite3BtreeLeaveAll(db);
if( rc==SQLITE_NOMEM ){
goto no_mem;
}
@ -4781,7 +4856,7 @@ case OP_TableLock: {
assert( (p->btreeMask & (1<<p1))!=0 );
assert( isWriteLock==0 || isWriteLock==1 );
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
if( rc==SQLITE_LOCKED ){
if( (rc&0xFF)==SQLITE_LOCKED ){
const char *z = pOp->p4.z;
sqlite3SetString(&p->zErrMsg, db, "database table is locked: %s", z);
}
@ -4796,8 +4871,8 @@ case OP_TableLock: {
** xBegin method for that table.
**
** Also, whether or not P4 is set, check that this is not being called from
** within a callback to a virtual table xSync() method. If it is, set the
** error code to SQLITE_LOCKED.
** within a callback to a virtual table xSync() method. If it is, the error
** code will be set to SQLITE_LOCKED.
*/
case OP_VBegin: {
sqlite3_vtab *pVtab = pOp->p4.pVtab;
@ -4863,7 +4938,7 @@ case OP_VOpen: {
pVtabCursor->pVtab = pVtab;
/* Initialise vdbe cursor object */
pCur = allocateCursor(p, pOp->p1, &pOp[-1], -1, 0);
pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
if( pCur ){
pCur->pVtabCursor = pVtabCursor;
pCur->pModule = pVtabCursor->pVtab->pModule;
@ -5023,7 +5098,7 @@ case OP_VColumn: {
pVtab->zErrMsg = 0;
/* Copy the result of the function to the P3 register. We
** do this regardless of whether or not an error occured to ensure any
** do this regardless of whether or not an error occurred to ensure any
** dynamic allocation in sContext.s (a Mem struct) is released.
*/
sqlite3VdbeChangeEncoding(&sContext.s, encoding);
@ -5204,13 +5279,14 @@ case OP_Pagecount: { /* out2-prerelease */
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/
case OP_Trace: {
if( pOp->p4.z ){
char *zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
if( zTrace ){
if( db->xTrace ){
db->xTrace(db->pTraceArg, pOp->p4.z);
db->xTrace(db->pTraceArg, zTrace);
}
#ifdef SQLITE_DEBUG
if( (db->flags & SQLITE_SqlTrace)!=0 ){
sqlite3DebugPrintf("SQL-trace: %s\n", pOp->p4.z);
sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
}
#endif /* SQLITE_DEBUG */
}

4
vdbe.h
View file

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.139 2008/10/31 10:53:23 danielk1977 Exp $
** $Id: vdbe.h,v 1.140 2009/02/19 14:39:25 danielk1977 Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -181,7 +181,7 @@ void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT

View file

@ -15,7 +15,7 @@
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
**
** $Id: vdbeInt.h,v 1.162 2009/02/03 15:39:01 drh Exp $
** $Id: vdbeInt.h,v 1.166 2009/03/18 10:33:02 danielk1977 Exp $
*/
#ifndef _VDBEINT_H_
#define _VDBEINT_H_
@ -59,13 +59,11 @@ struct VdbeCursor {
BtCursor *pCursor; /* The cursor structure of the backend */
int iDb; /* Index of cursor database in db->aDb[] (or -1) */
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
i64 nextRowid; /* Next rowid returned by OP_NewRowid */
Bool zeroed; /* True if zeroed out and ready for reuse */
Bool rowidIsValid; /* True if lastRowid is valid */
Bool atFirst; /* True if pointing to first entry */
Bool useRandomRowid; /* Generate new record numbers semi-randomly */
Bool nullRow; /* True if pointing to a row with no data */
Bool nextRowidValid; /* True if the nextRowid field is valid */
Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */
Bool ephemPseudoTable;
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
@ -279,16 +277,13 @@ struct Vdbe {
u32 magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
int nCallback; /* Number of callbacks invoked so far */
int cacheCtr; /* VdbeCursor row cache generation counter */
int contextStackTop; /* Index of top element in the context stack */
int contextStackDepth; /* The size of the "context" stack */
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
int pc; /* The program counter */
int rc; /* Value to return */
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
int errorAction; /* Recovery action to do in case of an error */
int inTempTrans; /* True if temp database is transactioned */
int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */
char *zErrMsg; /* Error message written here */
@ -300,17 +295,18 @@ struct Vdbe {
u8 inVtabMethod; /* See comments above */
u8 usesStmtJournal; /* True if uses a statement journal */
u8 readOnly; /* True for read-only statements */
u8 isPrepareV2; /* True if prepared with prepare_v2() */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
int nSql; /* Number of bytes in zSql */
char *zSql; /* Text of the SQL statement that generated this */
void *pFree; /* Free this when deleting the vdbe */
#ifdef SQLITE_DEBUG
FILE *trace; /* Write an execution trace here, if not NULL */
#endif
int openedStatement; /* True if this VM has opened a statement journal */
int iStatement; /* Statement number (or 0 if has not opened stmt) */
#ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */
@ -378,6 +374,7 @@ int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
const char *sqlite3OpcodeName(int);
int sqlite3VdbeOpcodeHasProperty(int, int);
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
int sqlite3VdbeCloseStatement(Vdbe *, int);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int sqlite3VdbeReleaseBuffers(Vdbe *p);
#endif

View file

@ -13,7 +13,7 @@
** This file contains code use to implement APIs that are part of the
** VDBE.
**
** $Id: vdbeapi.c,v 1.151 2009/02/04 03:59:25 shane Exp $
** $Id: vdbeapi.c,v 1.156 2009/03/25 15:43:09 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -204,12 +204,14 @@ int sqlite3_finalize(sqlite3_stmt *pStmt){
rc = SQLITE_OK;
}else{
Vdbe *v = (Vdbe*)pStmt;
sqlite3 *db = v->db;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = v->db->mutex;
#endif
sqlite3_mutex_enter(mutex);
stmtLruRemove(v);
rc = sqlite3VdbeFinalize(v);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(mutex);
}
return rc;
@ -234,6 +236,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
stmtLruAdd(v);
sqlite3VdbeMakeReady(v, -1, 0, 0, 0);
assert( (rc & (v->db->errMask))==rc );
rc = sqlite3ApiExit(v->db, rc);
sqlite3_mutex_leave(v->db->mutex);
}
return rc;
@ -488,34 +491,41 @@ static int sqlite3Step(Vdbe *p){
#ifndef SQLITE_OMIT_TRACE
/* Invoke the profile callback if there is one
*/
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->nOp>0
&& p->aOp[0].opcode==OP_Trace && p->aOp[0].p4.z!=0 ){
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
double rNow;
u64 elapseTime;
sqlite3OsCurrentTime(db->pVfs, &rNow);
elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
elapseTime -= p->startTime;
db->xProfile(db->pProfileArg, p->aOp[0].p4.z, elapseTime);
db->xProfile(db->pProfileArg, p->zSql, elapseTime);
}
#endif
db->errCode = rc;
/*sqlite3Error(p->db, rc, 0);*/
p->rc = sqlite3ApiExit(p->db, p->rc);
end_of_step:
assert( (rc&0xff)==rc );
if( p->zSql && (rc&0xff)<SQLITE_ROW ){
/* This behavior occurs if sqlite3_prepare_v2() was used to build
** the prepared statement. Return error codes directly */
p->db->errCode = p->rc;
/* sqlite3Error(p->db, p->rc, 0); */
return p->rc;
}else{
/* This is for legacy sqlite3_prepare() builds and when the code
** is SQLITE_ROW or SQLITE_DONE */
return rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM;
}
end_of_step:
/* At this point local variable rc holds the value that should be
** returned if this statement was compiled using the legacy
** sqlite3_prepare() interface. According to the docs, this can only
** be one of the values in the first assert() below. Variable p->rc
** contains the value that would be returned if sqlite3_finalize()
** were called on statement p.
*/
assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| rc==SQLITE_BUSY || rc==SQLITE_MISUSE
);
assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE );
if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
/* If this statement was prepared using sqlite3_prepare_v2(), and an
** error has occured, then return the error code in p->rc to the
** caller. Set the error code in the database handle to the same value.
*/
rc = db->errCode = p->rc;
}
return (rc&db->errMask);
}
/*
@ -545,11 +555,11 @@ int sqlite3_step(sqlite3_stmt *pStmt){
sqlite3_mutex_enter(db->mutex);
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < 5
&& vdbeReprepare(v) ){
&& (rc = vdbeReprepare(v))==SQLITE_OK ){
sqlite3_reset(pStmt);
v->expired = 0;
}
if( rc==SQLITE_SCHEMA && v->zSql && db->pErr ){
if( rc==SQLITE_SCHEMA && v->isPrepareV2 && db->pErr ){
/* This case occurs after failing to recompile an sql statement.
** The error message from the SQL compiler has already been loaded
** into the database handle. This block copies the error message
@ -711,7 +721,7 @@ failed:
** context.
*/
int sqlite3_aggregate_count(sqlite3_context *p){
assert( p && p->pFunc && p->pFunc->xStep );
assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
return p->pMem->n;
}
#endif
@ -754,7 +764,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
}else{
/* ((double)0) In case of SQLITE_OMIT_FLOATING_POINT... */
static const Mem nullMem = {{0}, (double)0, 0, "", 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
if( pVm->db ){
if( pVm && pVm->db ){
sqlite3_mutex_enter(pVm->db->mutex);
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
}

241
vdbeaux.c
View file

@ -14,7 +14,7 @@
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.435 2009/02/03 16:51:25 danielk1977 Exp $
** $Id: vdbeaux.c,v 1.446 2009/03/25 15:43:09 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -52,17 +52,22 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
/*
** Remember the SQL string for a prepared statement.
*/
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
if( p==0 ) return;
#ifdef SQLITE_OMIT_TRACE
if( !isPrepareV2 ) return;
#endif
assert( p->zSql==0 );
p->zSql = sqlite3DbStrNDup(p->db, z, n);
p->isPrepareV2 = isPrepareV2 ? 1 : 0;
}
/*
** Return the SQL associated with a prepared statement
*/
const char *sqlite3_sql(sqlite3_stmt *pStmt){
return ((Vdbe *)pStmt)->zSql;
Vdbe *p = (Vdbe *)pStmt;
return (p->isPrepareV2 ? p->zSql : 0);
}
/*
@ -71,7 +76,6 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt){
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
Vdbe tmp, *pTmp;
char *zTmp;
int nTmp;
tmp = *pA;
*pA = *pB;
*pB = tmp;
@ -84,9 +88,7 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
nTmp = pA->nSql;
pA->nSql = pB->nSql;
pB->nSql = nTmp;
pB->isPrepareV2 = pA->isPrepareV2;
}
#ifdef SQLITE_DEBUG
@ -112,7 +114,7 @@ static int growOpArray(Vdbe *p){
int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op)));
pNew = sqlite3DbRealloc(p->db, p->aOp, nNew*sizeof(Op));
if( pNew ){
p->nOpAlloc = nNew;
p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op);
p->aOp = pNew;
}
return (pNew ? SQLITE_OK : SQLITE_NOMEM);
@ -901,8 +903,8 @@ int sqlite3VdbeList(
}
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
p->db->mallocFailed = 1;
return SQLITE_NOMEM;
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
z = displayP4(pOp, pMem->z, 32);
@ -918,8 +920,8 @@ int sqlite3VdbeList(
if( p->explain==1 ){
if( sqlite3VdbeMemGrow(pMem, 4, 0) ){
p->db->mallocFailed = 1;
return SQLITE_NOMEM;
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
pMem->n = 2;
@ -998,6 +1000,39 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
}
#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
/*
** Allocate space from a fixed size buffer. Make *pp point to the
** allocated space. (Note: pp is a char* rather than a void** to
** work around the pointer aliasing rules of C.) *pp should initially
** be zero. If *pp is not zero, that means that the space has already
** been allocated and this routine is a noop.
**
** nByte is the number of bytes of space needed.
**
** *ppFrom point to available space and pEnd points to the end of the
** available space.
**
** *pnByte is a counter of the number of bytes of space that have failed
** to allocate. If there is insufficient space in *ppFrom to satisfy the
** request, then increment *pnByte by the amount of the request.
*/
static void allocSpace(
char *pp, /* IN/OUT: Set *pp to point to allocated buffer */
int nByte, /* Number of bytes to allocate */
u8 **ppFrom, /* IN/OUT: Allocate from *ppFrom */
u8 *pEnd, /* Pointer to 1 byte past the end of *ppFrom buffer */
int *pnByte /* If allocation cannot be made, increment *pnByte */
){
if( (*(void**)pp)==0 ){
nByte = ROUND8(nByte);
if( (pEnd - *ppFrom)>=nByte ){
*(void**)pp = (void *)*ppFrom;
*ppFrom += nByte;
}else{
*pnByte += nByte;
}
}
}
/*
** Prepare a virtual machine for execution. This involves things such
@ -1007,6 +1042,14 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
**
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
** VDBE_MAGIC_RUN.
**
** This function may be called more than once on a single virtual machine.
** The first call is made while compiling the SQL statement. Subsequent
** calls are made as part of the process of resetting a statement to be
** re-executed (from a call to sqlite3_reset()). The nVar, nMem, nCursor
** and isExplain parameters are only passed correct values the first time
** the function is called. On subsequent calls, from sqlite3_reset(), nVar
** is passed -1 and nMem, nCursor and isExplain are all passed zero.
*/
void sqlite3VdbeMakeReady(
Vdbe *p, /* The VDBE */
@ -1039,37 +1082,49 @@ void sqlite3VdbeMakeReady(
*/
nMem += nCursor;
/*
** Allocation space for registers.
/* Allocate space for memory registers, SQL variables, VDBE cursors and
** an array to marshal SQL function arguments in. This is only done the
** first time this function is called for a given VDBE, not when it is
** being called from sqlite3_reset() to reset the virtual machine.
*/
if( p->aMem==0 ){
if( nVar>=0 && !db->mallocFailed ){
u8 *zCsr = (u8 *)&p->aOp[p->nOp];
u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc];
int nByte;
int nArg; /* Maximum number of args passed to a user function. */
resolveP2Values(p, &nArg);
assert( nVar>=0 );
if( isExplain && nMem<10 ){
nMem = 10;
}
p->aMem = sqlite3DbMallocZero(db,
nMem*sizeof(Mem) /* aMem */
+ nVar*sizeof(Mem) /* aVar */
+ nArg*sizeof(Mem*) /* apArg */
+ nVar*sizeof(char*) /* azVar */
+ nCursor*sizeof(VdbeCursor*)+1 /* apCsr */
);
if( !db->mallocFailed ){
p->aMem--; /* aMem[] goes from 1..nMem */
p->nMem = nMem; /* not from 0..nMem-1 */
p->aVar = &p->aMem[nMem+1];
do {
memset(zCsr, 0, zEnd-zCsr);
nByte = 0;
allocSpace((char*)&p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->apCsr,
nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte
);
if( nByte ){
p->pFree = sqlite3DbMallocRaw(db, nByte);
}
zCsr = p->pFree;
zEnd = &zCsr[nByte];
}while( nByte && !db->mallocFailed );
p->nCursor = nCursor;
if( p->aVar ){
p->nVar = nVar;
p->okVar = 0;
p->apArg = (Mem**)&p->aVar[nVar];
p->azVar = (char**)&p->apArg[nArg];
p->apCsr = (VdbeCursor**)&p->azVar[nVar];
p->nCursor = nCursor;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
p->aVar[n].db = db;
}
}
if( p->aMem ){
p->aMem--; /* aMem[] goes from 1..nMem */
p->nMem = nMem; /* not from 0..nMem-1 */
for(n=1; n<=nMem; n++){
p->aMem[n].flags = MEM_Null;
p->aMem[n].db = db;
@ -1084,14 +1139,13 @@ void sqlite3VdbeMakeReady(
p->pc = -1;
p->rc = SQLITE_OK;
p->uniqueCnt = 0;
p->errorAction = OE_Abort;
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
p->nChange = 0;
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
p->openedStatement = 0;
p->iStatement = 0;
#ifdef VDBE_PROFILE
{
int i;
@ -1405,7 +1459,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
** master journal file will be orphaned. But we cannot delete it,
** in case the master journal file name was written into the journal
** file before the failure occured.
** file before the failure occurred.
*/
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
@ -1510,6 +1564,48 @@ static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
}
}
/*
** If the Vdbe passed as the first argument opened a statement-transaction,
** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or
** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement
** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the
** statement transaction is commtted.
**
** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
** Otherwise SQLITE_OK.
*/
int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
sqlite3 *const db = p->db;
int rc = SQLITE_OK;
if( p->iStatement && db->nStatement ){
int i;
const int iSavepoint = p->iStatement-1;
assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
assert( db->nStatement>0 );
assert( p->iStatement==(db->nStatement+db->nSavepoint) );
for(i=0; i<db->nDb; i++){
int rc2 = SQLITE_OK;
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
if( eOp==SAVEPOINT_ROLLBACK ){
rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
}
if( rc2==SQLITE_OK ){
rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
}
if( rc==SQLITE_OK ){
rc = rc2;
}
}
}
db->nStatement--;
p->iStatement = 0;
}
return rc;
}
/*
** This routine is called the when a VDBE tries to halt. If the VDBE
** has made changes and is in autocommit mode, then commit those
@ -1524,10 +1620,8 @@ static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
** means the close did not happen and needs to be repeated.
*/
int sqlite3VdbeHalt(Vdbe *p){
int rc; /* Used to store transient return codes */
sqlite3 *db = p->db;
int i;
int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
int isSpecialError; /* Set to true if SQLITE_NOMEM or IOERR */
/* This function contains the logic that determines if a statement or
** transaction will be committed or rolled back as a result of the
@ -1557,6 +1651,8 @@ int sqlite3VdbeHalt(Vdbe *p){
/* No commit or rollback needed if the program never started */
if( p->pc>=0 ){
int mrc; /* Primary error code from p->rc */
int eStatementOp = 0;
int isSpecialError; /* Set to true if a 'special' error */
/* Lock all btrees used by the statement */
sqlite3BtreeMutexArrayEnter(&p->aMutex);
@ -1571,11 +1667,11 @@ int sqlite3VdbeHalt(Vdbe *p){
*/
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
if( p->rc==SQLITE_IOERR_BLOCKED && p->usesStmtJournal ){
xFunc = sqlite3BtreeRollbackStmt;
eStatementOp = SAVEPOINT_ROLLBACK;
p->rc = SQLITE_BUSY;
}else if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL)
&& p->usesStmtJournal ){
xFunc = sqlite3BtreeRollbackStmt;
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
/* We are forced to roll back the active transaction. Before doing
** so, abort any other statements this handle currently has active.
@ -1588,8 +1684,8 @@ int sqlite3VdbeHalt(Vdbe *p){
}
}
/* If the auto-commit flag is set and this is the only active vdbe, then
** we do either a commit or rollback of the current transaction.
/* If the auto-commit flag is set and this is the only active writer
** VM, then we do either a commit or rollback of the current transaction.
**
** Note: This block also runs if one of the special errors handled
** above has occurred.
@ -1604,7 +1700,7 @@ int sqlite3VdbeHalt(Vdbe *p){
** successful or hit an 'OR FAIL' constraint. This means a commit
** is required.
*/
int rc = vdbeCommit(db, p);
rc = vdbeCommit(db, p);
if( rc==SQLITE_BUSY ){
sqlite3BtreeMutexArrayLeave(&p->aMutex);
return SQLITE_BUSY;
@ -1617,13 +1713,12 @@ int sqlite3VdbeHalt(Vdbe *p){
}else{
sqlite3RollbackAll(db);
}
}else if( !xFunc ){
db->nStatement = 0;
}else if( eStatementOp==0 ){
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
if( p->openedStatement ){
xFunc = sqlite3BtreeCommitStmt;
}
eStatementOp = SAVEPOINT_RELEASE;
}else if( p->errorAction==OE_Abort ){
xFunc = sqlite3BtreeRollbackStmt;
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
invalidateCursorsOnModifiedBtrees(db);
sqlite3RollbackAll(db);
@ -1632,33 +1727,26 @@ int sqlite3VdbeHalt(Vdbe *p){
}
}
/* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or
** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs
** and the return code is still SQLITE_OK, set the return code to the new
** error value.
/* If eStatementOp is non-zero, then a statement transaction needs to
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
** do so. If this operation returns an error, and the current statement
** error code is SQLITE_OK or SQLITE_CONSTRAINT, then set the error
** code to the new value.
*/
assert(!xFunc ||
xFunc==sqlite3BtreeCommitStmt ||
xFunc==sqlite3BtreeRollbackStmt
);
for(i=0; xFunc && i<db->nDb; i++){
int rc;
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
rc = xFunc(pBt);
if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
p->rc = rc;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
if( eStatementOp ){
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
p->rc = rc;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
}
/* If this was an INSERT, UPDATE or DELETE and the statement was committed,
** set the change counter.
/* If this was an INSERT, UPDATE or DELETE and no statement transaction
** has been rolled back, update the database connection change-counter.
*/
if( p->changeCntOn && p->pc>=0 ){
if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
if( eStatementOp!=SAVEPOINT_ROLLBACK ){
sqlite3VdbeSetChanges(db, p->nChange);
}else{
sqlite3VdbeSetChanges(db, 0);
@ -1690,6 +1778,15 @@ int sqlite3VdbeHalt(Vdbe *p){
p->rc = SQLITE_NOMEM;
}
/* If the auto-commit flag is set to true, then any locks that were held
** by connection db have now been released. Call sqlite3ConnectionUnlocked()
** to invoke any required unlock-notify callbacks.
*/
if( db->autoCommit ){
sqlite3ConnectionUnlocked(db);
}
assert( db->activeVdbeCnt>0 || db->autoCommit==0 || db->nStatement==0 );
return SQLITE_OK;
}
@ -1847,17 +1944,15 @@ void sqlite3VdbeDelete(Vdbe *p){
sqlite3DbFree(db, pOp->zComment);
#endif
}
sqlite3DbFree(db, p->aOp);
}
releaseMemArray(p->aVar, p->nVar);
sqlite3DbFree(db, p->aLabel);
if( p->aMem ){
sqlite3DbFree(db, &p->aMem[1]);
}
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
p->magic = VDBE_MAGIC_DEAD;
sqlite3DbFree(db, p->aOp);
sqlite3DbFree(db, p->pFree);
sqlite3DbFree(db, p);
}

View file

@ -12,7 +12,7 @@
**
** This file contains code used to implement incremental BLOB I/O.
**
** $Id: vdbeblob.c,v 1.26 2008/10/02 14:49:02 danielk1977 Exp $
** $Id: vdbeblob.c,v 1.31 2009/03/24 15:08:10 drh Exp $
*/
#include "sqliteInt.h"
@ -70,17 +70,15 @@ int sqlite3_blob_open(
/* One of the following two instructions is replaced by an
** OP_Noop before exection.
*/
{OP_SetNumColumns, 0, 0, 0}, /* 2: Num cols for cursor */
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
{OP_SetNumColumns, 0, 0, 0}, /* 4: Num cols for cursor */
{OP_OpenWrite, 0, 0, 0}, /* 5: Open cursor 0 for read/write */
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
{OP_Variable, 1, 1, 0}, /* 6: Push the rowid to the stack */
{OP_NotExists, 0, 10, 1}, /* 7: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 8 */
{OP_ResultRow, 1, 0, 0}, /* 9 */
{OP_Close, 0, 0, 0}, /* 10 */
{OP_Halt, 0, 0, 0}, /* 11 */
{OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
{OP_NotExists, 0, 8, 1}, /* 5: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 6 */
{OP_ResultRow, 1, 0, 0}, /* 7 */
{OP_Close, 0, 0, 0}, /* 8 */
{OP_Halt, 0, 0, 0}, /* 9 */
};
Vdbe *v = 0;
@ -178,19 +176,19 @@ int sqlite3_blob_open(
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum.
*/
sqlite3VdbeChangeToNoop(v, (flags ? 3 : 5), 1);
sqlite3VdbeChangeP2(v, (flags ? 5 : 3), pTab->tnum);
sqlite3VdbeChangeP3(v, (flags ? 5 : 3), iDb);
sqlite3VdbeChangeToNoop(v, (flags ? 2 : 3), 1);
sqlite3VdbeChangeP2(v, (flags ? 3 : 2), pTab->tnum);
sqlite3VdbeChangeP3(v, (flags ? 3 : 2), iDb);
/* Configure the OP_SetNumColumns. Configure the cursor to
/* Configure the number of columns. Configure the cursor to
** think that the table has one more column than it really
** does. An OP_Column to retrieve this imaginary column will
** always return an SQL NULL. This is useful because it means
** we can invoke OP_Column to fill in the vdbe cursors type
** and offset cache without causing any IO.
*/
sqlite3VdbeChangeP2(v, flags ? 4 : 2, pTab->nCol+1);
sqlite3VdbeChangeP2(v, 8, pTab->nCol);
sqlite3VdbeChangeP4(v, flags ? 3 : 2, SQLITE_INT_TO_PTR(pTab->nCol+1), P4_INT32);
sqlite3VdbeChangeP2(v, 6, pTab->nCol);
if( !db->mallocFailed ){
sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
}
@ -250,8 +248,8 @@ int sqlite3_blob_open(
blob_open_out:
zErr[sizeof(zErr)-1] = '\0';
if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3_finalize((sqlite3_stmt *)v);
if( v && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(v);
}
sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
rc = sqlite3ApiExit(db, rc);
@ -266,9 +264,13 @@ blob_open_out:
int sqlite3_blob_close(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
int rc;
sqlite3 *db;
db = p->db;
sqlite3_mutex_enter(db->mutex);
rc = sqlite3_finalize(p->pStmt);
sqlite3DbFree(p->db, p);
sqlite3DbFree(db, p);
sqlite3_mutex_leave(db->mutex);
return rc;
}

View file

@ -15,7 +15,7 @@
** only within the VDBE. Interface routines refer to a Mem using the
** name sqlite_value
**
** $Id: vdbemem.c,v 1.137 2009/02/04 03:59:25 shane Exp $
** $Id: vdbemem.c,v 1.139 2009/03/29 15:12:10 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -321,6 +321,10 @@ static i64 doubleToInt64(double r){
if( r<(double)minInt ){
return minInt;
}else if( r>(double)maxInt ){
/* minInt is correct here - not maxInt. It turns out that assigning
** a very large positive number to an integer results in a very large
** negative integer. This makes no sense, but it is what x86 hardware
** does so for compatibility we will do the same in software. */
return minInt;
}else{
return (i64)r;
@ -333,9 +337,10 @@ static i64 doubleToInt64(double r){
** If pMem is an integer, then the value is exact. If pMem is
** a floating-point then the value returned is the integer part.
** If pMem is a string or blob, then we make an attempt to convert
** it into a integer and return that. If pMem is NULL, return 0.
** it into a integer and return that. If pMem represents an
** an SQL-NULL value, return 0.
**
** If pMem is a string, its encoding might be changed.
** If pMem represents a string value, its encoding might be changed.
*/
i64 sqlite3VdbeIntValue(Mem *pMem){
int flags;

11
vtab.c
View file

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.81 2008/12/10 19:26:24 drh Exp $
** $Id: vtab.c,v 1.84 2009/03/24 15:08:10 drh Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
@ -118,7 +118,8 @@ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
*/
void sqlite3VtabClear(Table *p){
sqlite3_vtab *pVtab = p->pVtab;
sqlite3 *db = p->db;
Schema *pSchema = p->pSchema;
sqlite3 *db = pSchema ? pSchema->db : 0;
if( pVtab ){
assert( p->pMod && p->pMod->pModule );
sqlite3VtabUnlock(db, pVtab);
@ -571,7 +572,9 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
}
sParse.declareVtab = 0;
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
if( sParse.pVdbe ){
sqlite3VdbeFinalize(sParse.pVdbe);
}
sqlite3DeleteTable(sParse.pNewTable);
sParse.pNewTable = 0;
@ -711,7 +714,7 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
/* Special case: If db->aVTrans is NULL and db->nVTrans is greater
** than zero, then this function is being called from within a
** virtual module xSync() callback. It is illegal to write to
** virtual module tables in this case, so return SQLITE_LOCKED.
** virtual module tables in this case, so return SQLITE_MISUSE.
*/
if( sqlite3VtabInSync(db) ){
return SQLITE_LOCKED;

View file

@ -12,7 +12,7 @@
** This file contains routines used for walking the parser tree for
** an SQL statement.
**
** $Id: walker.c,v 1.1 2008/08/20 16:35:10 drh Exp $
** $Id: walker.c,v 1.2 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -45,9 +45,10 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
if( rc==WRC_Continue ){
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
if( sqlite3WalkExprList(pWalker, pExpr->pList) ) return WRC_Abort;
if( sqlite3WalkSelect(pWalker, pExpr->pSelect) ){
return WRC_Abort;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
}else{
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
}
}
return rc & WRC_Abort;

158
where.c
View file

@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.368 2009/02/04 03:59:25 shane Exp $
** $Id: where.c,v 1.379 2009/03/29 00:15:54 drh Exp $
*/
#include "sqliteInt.h"
@ -431,8 +431,11 @@ static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){
}
mask = exprTableUsage(pMaskSet, p->pRight);
mask |= exprTableUsage(pMaskSet, p->pLeft);
mask |= exprListTableUsage(pMaskSet, p->pList);
mask |= exprSelectTableUsage(pMaskSet, p->pSelect);
if( ExprHasProperty(p, EP_xIsSelect) ){
mask |= exprSelectTableUsage(pMaskSet, p->x.pSelect);
}else{
mask |= exprListTableUsage(pMaskSet, p->x.pList);
}
return mask;
}
static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){
@ -634,7 +637,7 @@ static int isLikeOrGlob(
#ifdef SQLITE_EBCDIC
if( *pnoCase ) return 0;
#endif
pList = pExpr->pList;
pList = pExpr->x.pList;
pRight = pList->a[0].pExpr;
if( pRight->op!=TK_STRING ){
return 0;
@ -653,7 +656,7 @@ static int isLikeOrGlob(
(pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
return 0;
}
sqlite3DequoteExpr(db, pRight);
sqlite3DequoteExpr(pRight);
z = (char *)pRight->token.z;
cnt = 0;
if( z ){
@ -689,7 +692,7 @@ static int isMatchOfColumn(
sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){
return 0;
}
pList = pExpr->pList;
pList = pExpr->x.pList;
if( pList->nExpr!=2 ){
return 0;
}
@ -953,17 +956,18 @@ static void exprAnalyzeOrTerm(
assert( pOrTerm->eOperator==WO_EQ );
assert( pOrTerm->leftCursor==iCursor );
assert( pOrTerm->u.leftColumn==iColumn );
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight);
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0);
pLeft = pOrTerm->pExpr->pLeft;
}
assert( pLeft!=0 );
pDup = sqlite3ExprDup(db, pLeft);
pDup = sqlite3ExprDup(db, pLeft, 0);
pNew = sqlite3Expr(db, TK_IN, pDup, 0, 0);
if( pNew ){
int idxNew;
transferJoinMarkings(pNew, pExpr);
pNew->pList = pList;
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
pNew->x.pList = pList;
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
@ -1026,8 +1030,11 @@ static void exprAnalyze(
op = pExpr->op;
if( op==TK_IN ){
assert( pExpr->pRight==0 );
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
pTerm->prereqRight = exprSelectTableUsage(pMaskSet, pExpr->x.pSelect);
}else{
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->x.pList);
}
}else if( op==TK_ISNULL ){
pTerm->prereqRight = 0;
}else{
@ -1057,7 +1064,7 @@ static void exprAnalyze(
Expr *pDup;
if( pTerm->leftCursor>=0 ){
int idxNew;
pDup = sqlite3ExprDup(db, pExpr);
pDup = sqlite3ExprDup(db, pExpr, 0);
if( db->mallocFailed ){
sqlite3ExprDelete(db, pDup);
return;
@ -1100,7 +1107,7 @@ static void exprAnalyze(
** BETWEEN term is skipped.
*/
else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){
ExprList *pList = pExpr->pList;
ExprList *pList = pExpr->x.pList;
int i;
static const u8 ops[] = {TK_GE, TK_LE};
assert( pList!=0 );
@ -1108,8 +1115,8 @@ static void exprAnalyze(
for(i=0; i<2; i++){
Expr *pNewExpr;
int idxNew;
pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft),
sqlite3ExprDup(db, pList->a[i].pExpr), 0);
pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0),
sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
@ -1148,18 +1155,18 @@ static void exprAnalyze(
Expr *pNewExpr1, *pNewExpr2;
int idxNew1, idxNew2;
pLeft = pExpr->pList->a[1].pExpr;
pRight = pExpr->pList->a[0].pExpr;
pLeft = pExpr->x.pList->a[1].pExpr;
pRight = pExpr->x.pList->a[0].pExpr;
pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0);
if( pStr1 ){
sqlite3TokenCopy(db, &pStr1->token, &pRight->token);
pStr1->token.n = nPattern;
pStr1->flags = EP_Dequoted;
}
pStr2 = sqlite3ExprDup(db, pStr1);
pStr2 = sqlite3ExprDup(db, pStr1, 0);
if( !db->mallocFailed ){
u8 c, *pC;
assert( pStr2->token.dyn );
/* assert( pStr2->token.dyn ); */
pC = (u8*)&pStr2->token.z[nPattern-1];
c = *pC;
if( noCase ){
@ -1168,11 +1175,11 @@ static void exprAnalyze(
}
*pC = c + 1;
}
pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft), pStr1, 0);
pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft,0),pStr1,0);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft), pStr2, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft,0),pStr2,0);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
@ -1198,13 +1205,13 @@ static void exprAnalyze(
WhereTerm *pNewTerm;
Bitmask prereqColumn, prereqExpr;
pRight = pExpr->pList->a[0].pExpr;
pLeft = pExpr->pList->a[1].pExpr;
pRight = pExpr->x.pList->a[0].pExpr;
pLeft = pExpr->x.pList->a[1].pExpr;
prereqExpr = exprTableUsage(pMaskSet, pRight);
prereqColumn = exprTableUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0);
pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
pNewTerm = &pWC->a[idxNew];
@ -1708,15 +1715,15 @@ static double bestVirtualIndex(
** * Whether or not there must be separate lookups in the
** index and in the main table.
**
** If there was an INDEXED BY clause attached to the table in the SELECT
** statement, then this function only considers plans using the
** named index. If one cannot be found, then the returned cost is
** SQLITE_BIG_DBL. If a plan can be found that uses the named index,
** If there was an INDEXED BY clause (pSrc->pIndex) attached to the table in
** the SQL statement, then this function only considers plans using the
** named index. If no such plan is found, then the returned cost is
** SQLITE_BIG_DBL. If a plan is found that uses the named index,
** then the cost is calculated in the usual way.
**
** If a NOT INDEXED clause was attached to the table in the SELECT
** statement, then no indexes are considered. However, the selected
** plan may still take advantage of the tables built-in rowid
** If a NOT INDEXED clause (pSrc->notIndexed!=0) was attached to the table
** in the SELECT statement, then no indexes are considered. However, the
** selected plan may still take advantage of the tables built-in rowid
** index.
*/
static void bestIndex(
@ -1776,10 +1783,12 @@ static void bestIndex(
pCost->rCost = 0;
pCost->nRow = 1;
return;
}else if( (pExpr = pTerm->pExpr)->pList!=0 ){
}else if( !ExprHasProperty((pExpr = pTerm->pExpr), EP_xIsSelect)
&& pExpr->x.pList
){
/* Rowid IN (LIST): cost is NlogN where N is the number of list
** elements. */
pCost->rCost = pCost->nRow = pExpr->pList->nExpr;
pCost->rCost = pCost->nRow = pExpr->x.pList->nExpr;
pCost->rCost *= estLog(pCost->rCost);
}else{
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
@ -1828,7 +1837,15 @@ static void bestIndex(
cost += cost*estLog(cost);
WHERETRACE(("... sorting increases cost to %.9g\n", cost));
}
}else if( pParse->db->flags & SQLITE_ReverseOrder ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
*/
wsFlags |= WHERE_REVERSE;
}
/* Remember this case if it is the best so far */
if( cost<pCost->rCost ){
pCost->rCost = cost;
pCost->nRow = nRow;
@ -1909,12 +1926,18 @@ static void bestIndex(
pProbe = pSrc->pIndex;
}
for(; pProbe; pProbe=(pSrc->pIndex ? 0 : pProbe->pNext)){
double inMultiplier = 1;
double inMultiplier = 1; /* Number of equality look-ups needed */
int inMultIsEst = 0; /* True if inMultiplier is an estimate */
WHERETRACE(("... index %s:\n", pProbe->zName));
/* Count the number of columns in the index that are satisfied
** by x=EXPR constraints or x IN (...) constraints.
** by x=EXPR constraints or x IN (...) constraints. For a term
** of the form x=EXPR we only have to do a single binary search.
** But for x IN (...) we have to do a number of binary searched
** equal to the number of entries on the RHS of the IN operator.
** The inMultipler variable with try to estimate the number of
** binary searches needed.
*/
wsFlags = 0;
for(i=0; i<pProbe->nColumn; i++){
@ -1925,23 +1948,33 @@ static void bestIndex(
if( pTerm->eOperator & WO_IN ){
Expr *pExpr = pTerm->pExpr;
wsFlags |= WHERE_COLUMN_IN;
if( pExpr->pSelect!=0 ){
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
inMultiplier *= 25;
}else if( pExpr->pList ){
inMultiplier *= pExpr->pList->nExpr + 1;
inMultIsEst = 1;
}else if( pExpr->x.pList ){
inMultiplier *= pExpr->x.pList->nExpr + 1;
}
}
}
nRow = pProbe->aiRowEst[i] * inMultiplier;
cost = nRow * estLog(inMultiplier);
/* If inMultiplier is an estimate and that estimate results in an
** nRow it that is more than half number of rows in the table,
** then reduce inMultipler */
if( inMultIsEst && nRow*2 > pProbe->aiRowEst[0] ){
nRow = pProbe->aiRowEst[0]/2;
inMultiplier = nRow/pProbe->aiRowEst[i];
}
cost = nRow + inMultiplier*estLog(pProbe->aiRowEst[0]);
nEq = i;
if( pProbe->onError!=OE_None && (wsFlags & WHERE_COLUMN_IN)==0
&& nEq==pProbe->nColumn ){
wsFlags |= WHERE_UNIQUE;
}
WHERETRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n",nEq,inMultiplier,cost));
WHERETRACE(("...... nEq=%d inMult=%.9g nRow=%.9g cost=%.9g\n",
nEq, inMultiplier, nRow, cost));
/* Look for range constraints
/* Look for range constraints. Assume that each range constraint
** makes the search space 1/3rd smaller.
*/
if( nEq<pProbe->nColumn ){
int j = pProbe->aiColumn[nEq];
@ -1958,7 +1991,8 @@ static void bestIndex(
cost /= 3;
nRow /= 3;
}
WHERETRACE(("...... range reduces cost to %.9g\n", cost));
WHERETRACE(("...... range reduces nRow to %.9g and cost to %.9g\n",
nRow, cost));
}
}
@ -1978,6 +2012,12 @@ static void bestIndex(
cost += cost*estLog(cost);
WHERETRACE(("...... orderby increases cost to %.9g\n", cost));
}
}else if( pParse->db->flags & SQLITE_ReverseOrder ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
*/
wsFlags |= WHERE_REVERSE;
}
/* Check to see if we can get away with using just the index without
@ -2738,11 +2778,13 @@ static Bitmask codeOneLoopStart(
/* Case 5: There is no usable index. We must do a complete
** scan of the entire table.
*/
static const u8 aStep[] = { OP_Next, OP_Prev };
static const u8 aStart[] = { OP_Rewind, OP_Last };
assert( bRev==0 || bRev==1 );
assert( omitTable==0 );
assert( bRev==0 );
pLevel->op = OP_Next;
pLevel->op = aStep[bRev];
pLevel->p1 = iCur;
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addrBrk);
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
codeRowSetEarly = 0;
}
@ -2836,7 +2878,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
assert( pInfo->needToFreeIdxStr==0 || db->mallocFailed );
if( pInfo->needToFreeIdxStr ){
sqlite3_free(pInfo->idxStr);
}
}
sqlite3DbFree(db, pInfo);
}
}
@ -2943,6 +2985,7 @@ WhereInfo *sqlite3WhereBegin(
int regRowSet /* Register hold RowSet if WHERE_FILL_ROWSET is set */
){
int i; /* Loop counter */
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
WhereInfo *pWInfo; /* Will become the return value of this function */
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
Bitmask notReady; /* Cursors that are not yet positioned */
@ -2968,15 +3011,19 @@ WhereInfo *sqlite3WhereBegin(
}
/* Allocate and initialize the WhereInfo structure that will become the
** return value.
** return value. A single allocation is used to store the WhereInfo
** struct, the contents of WhereInfo.a[], the WhereClause structure
** and the WhereMaskSet structure. Since WhereClause contains an 8-byte
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
db = pParse->db;
pWInfo = sqlite3DbMallocZero(db,
sizeof(WhereInfo)
+ (pTabList->nSrc-1)*sizeof(WhereLevel)
+ sizeof(WhereClause)
+ sizeof(WhereMaskSet)
);
nByteWInfo = ROUND8(sizeof(WhereInfo)+(pTabList->nSrc-1)*sizeof(WhereLevel));
pWInfo = sqlite3DbMallocZero(db,
nByteWInfo +
sizeof(WhereClause) +
sizeof(WhereMaskSet)
);
if( db->mallocFailed ){
goto whereBeginError;
}
@ -2985,7 +3032,7 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
pWInfo->regRowSet = (wctrlFlags & WHERE_FILL_ROWSET) ? regRowSet : -1;
pWInfo->pWC = pWC = (WhereClause*)&pWInfo->a[pWInfo->nLevel];
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
pMaskSet = (WhereMaskSet*)&pWC[1];
@ -3231,7 +3278,7 @@ WhereInfo *sqlite3WhereBegin(
Bitmask b = pTabItem->colUsed;
int n = 0;
for(; b; b=b>>1, n++){}
sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-2, n);
sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, SQLITE_INT_TO_PTR(n), P4_INT32);
assert( n<=pTab->nCol );
}
}else{
@ -3244,7 +3291,6 @@ WhereInfo *sqlite3WhereBegin(
int iIdxCur = pLevel->iIdxCur;
assert( pIx->pSchema==pTab->pSchema );
assert( iIdxCur>=0 );
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pIx->nColumn+1);
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIx->tnum, iDb,
(char*)pKey, P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIx->zName));