Upgraded SQLite 3 to version 3.3.12

This commit is contained in:
Ilia Alshanetsky 2007-02-09 03:17:47 +00:00
parent 7aa2282124
commit d35449bbfb
49 changed files with 5187 additions and 2911 deletions

1
NEWS
View file

@ -1,6 +1,7 @@
PHP NEWS PHP NEWS
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2007, PHP 5.2.2 ?? ??? 2007, PHP 5.2.2
- Upgraded SQLite 3 to version 3.3.12 (Ilia)
- Add --ri switch to CLI which allows to check extension information. (Marcus) - Add --ri switch to CLI which allows to check extension information. (Marcus)
- Fixed bug #39836 (SplObjectStorage empty after unserialize). (Marcus) - Fixed bug #39836 (SplObjectStorage empty after unserialize). (Marcus)

View file

@ -1 +1 @@
3.3.7 3.3.12

View file

@ -28,7 +28,7 @@
** This function is used by SQL generated to implement the ** This function is used by SQL generated to implement the
** ALTER TABLE command. The first argument is the text of a CREATE TABLE or ** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
** CREATE INDEX command. The second is a table name. The table name in ** CREATE INDEX command. The second is a table name. The table name in
** the CREATE TABLE or CREATE INDEX statement is replaced with the second ** the CREATE TABLE or CREATE INDEX statement is replaced with the third
** argument and the result returned. Examples: ** argument and the result returned. Examples:
** **
** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') ** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
@ -78,10 +78,10 @@ static void renameTableFunc(
} }
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
/* This function is used by SQL generated to implement the ALTER TABLE /* This function is used by SQL generated to implement the
** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER ** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
** statement. The second is a table name. The table name in the CREATE ** statement. The second is a table name. The table name in the CREATE
** TRIGGER statement is replaced with the second argument and the result ** TRIGGER statement is replaced with the third argument and the result
** returned. This is analagous to renameTableFunc() above, except for CREATE ** returned. This is analagous to renameTableFunc() above, except for CREATE
** TRIGGER, not CREATE INDEX and CREATE TABLE. ** TRIGGER, not CREATE INDEX and CREATE TABLE.
*/ */

View file

@ -387,17 +387,13 @@ struct BtCursor {
CellInfo info; /* A parse of the cell we are pointing at */ CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */ u8 wrFlag; /* True if writable */
u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 eState; /* One of the CURSOR_XXX constants (see below) */
#ifndef SQLITE_OMIT_SHARED_CACHE
void *pKey; /* Saved key that was cursor's last known position */ void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */ i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */ int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
#endif
}; };
/* /*
** Potential values for BtCursor.eState. The first two values (VALID and ** Potential values for BtCursor.eState.
** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur
** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined.
** **
** CURSOR_VALID: ** CURSOR_VALID:
** Cursor points to a valid entry. getPayload() etc. may be called. ** Cursor points to a valid entry. getPayload() etc. may be called.
@ -425,7 +421,8 @@ struct BtCursor {
*/ */
#if SQLITE_TEST #if SQLITE_TEST
# define TRACE(X) if( sqlite3_btree_trace )\ # define TRACE(X) if( sqlite3_btree_trace )\
{ sqlite3DebugPrintf X; fflush(stdout); } /* { sqlite3DebugPrintf X; fflush(stdout); } */ \
{ printf X; fflush(stdout); }
int sqlite3_btree_trace=0; /* True to enable tracing */ int sqlite3_btree_trace=0; /* True to enable tracing */
#else #else
# define TRACE(X) # define TRACE(X)
@ -434,7 +431,7 @@ int sqlite3_btree_trace=0; /* True to enable tracing */
/* /*
** Forward declaration ** Forward declaration
*/ */
static int checkReadLocks(BtShared*,Pgno,BtCursor*); static int checkReadLocks(Btree*,Pgno,BtCursor*);
/* /*
** Read or write a two- and four-byte big-endian integer values. ** Read or write a two- and four-byte big-endian integer values.
@ -509,105 +506,8 @@ struct BtLock {
#define queryTableLock(a,b,c) SQLITE_OK #define queryTableLock(a,b,c) SQLITE_OK
#define lockTable(a,b,c) SQLITE_OK #define lockTable(a,b,c) SQLITE_OK
#define unlockAllTables(a) #define unlockAllTables(a)
#define restoreOrClearCursorPosition(a,b) SQLITE_OK
#define saveAllCursors(a,b,c) SQLITE_OK
#else #else
static void releasePage(MemPage *pPage);
/*
** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
*/
static int saveCursorPosition(BtCursor *pCur){
int rc;
assert( CURSOR_VALID==pCur->eState );
assert( 0==pCur->pKey );
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
/* If this is an intKey table, then the above call to BtreeKeySize()
** stores the integer key in pCur->nKey. In this case this value is
** all that is required. Otherwise, if pCur is not open on an intKey
** table, then malloc space for and store the pCur->nKey bytes of key
** data.
*/
if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
void *pKey = sqliteMalloc(pCur->nKey);
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);
if( rc==SQLITE_OK ){
pCur->pKey = pKey;
}else{
sqliteFree(pKey);
}
}else{
rc = SQLITE_NOMEM;
}
}
assert( !pCur->pPage->intKey || !pCur->pKey );
if( rc==SQLITE_OK ){
releasePage(pCur->pPage);
pCur->pPage = 0;
pCur->eState = CURSOR_REQUIRESEEK;
}
return rc;
}
/*
** Save the positions of all cursors except pExcept open on the table
** with root-page iRoot. Usually, this is called just before cursor
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
*/
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
BtCursor *p;
if( sqlite3ThreadDataReadOnly()->useSharedData ){
for(p=pBt->pCursor; p; p=p->pNext){
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
p->eState==CURSOR_VALID ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
}
}
}
}
return SQLITE_OK;
}
/*
** Restore the cursor to the position it was in (or as close to as possible)
** when saveCursorPosition() was called. Note that this call deletes the
** saved position info stored by saveCursorPosition(), so there can be
** at most one effective restoreOrClearCursorPosition() call after each
** saveCursorPosition().
**
** If the second argument argument - doSeek - is false, then instead of
** returning the cursor to it's saved position, any saved position is deleted
** and the cursor state set to CURSOR_INVALID.
*/
static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
int rc = SQLITE_OK;
assert( sqlite3ThreadDataReadOnly()->useSharedData );
assert( pCur->eState==CURSOR_REQUIRESEEK );
pCur->eState = CURSOR_INVALID;
if( doSeek ){
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
}
if( rc==SQLITE_OK ){
sqliteFree(pCur->pKey);
pCur->pKey = 0;
assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
}
return rc;
}
#define restoreOrClearCursorPosition(p,x) \
(p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
/* /*
** Query to see if btree handle p may obtain a lock of type eLock ** Query to see if btree handle p may obtain a lock of type eLock
@ -747,6 +647,98 @@ static void unlockAllTables(Btree *p){
} }
#endif /* SQLITE_OMIT_SHARED_CACHE */ #endif /* SQLITE_OMIT_SHARED_CACHE */
static void releasePage(MemPage *pPage); /* Forward reference */
/*
** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
*/
static int saveCursorPosition(BtCursor *pCur){
int rc;
assert( CURSOR_VALID==pCur->eState );
assert( 0==pCur->pKey );
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
/* If this is an intKey table, then the above call to BtreeKeySize()
** stores the integer key in pCur->nKey. In this case this value is
** all that is required. Otherwise, if pCur is not open on an intKey
** table, then malloc space for and store the pCur->nKey bytes of key
** data.
*/
if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
void *pKey = sqliteMalloc(pCur->nKey);
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);
if( rc==SQLITE_OK ){
pCur->pKey = pKey;
}else{
sqliteFree(pKey);
}
}else{
rc = SQLITE_NOMEM;
}
}
assert( !pCur->pPage->intKey || !pCur->pKey );
if( rc==SQLITE_OK ){
releasePage(pCur->pPage);
pCur->pPage = 0;
pCur->eState = CURSOR_REQUIRESEEK;
}
return rc;
}
/*
** Save the positions of all cursors except pExcept open on the table
** with root-page iRoot. Usually, this is called just before cursor
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
*/
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
BtCursor *p;
for(p=pBt->pCursor; p; p=p->pNext){
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
p->eState==CURSOR_VALID ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
}
}
}
return SQLITE_OK;
}
/*
** Restore the cursor to the position it was in (or as close to as possible)
** when saveCursorPosition() was called. Note that this call deletes the
** saved position info stored by saveCursorPosition(), so there can be
** at most one effective restoreOrClearCursorPosition() call after each
** saveCursorPosition().
**
** If the second argument argument - doSeek - is false, then instead of
** returning the cursor to it's saved position, any saved position is deleted
** and the cursor state set to CURSOR_INVALID.
*/
static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
int rc = SQLITE_OK;
assert( pCur->eState==CURSOR_REQUIRESEEK );
pCur->eState = CURSOR_INVALID;
if( doSeek ){
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
}
if( rc==SQLITE_OK ){
sqliteFree(pCur->pKey);
pCur->pKey = 0;
assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
}
return rc;
}
#define restoreOrClearCursorPosition(p,x) \
(p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
/* /*
** These macros define the location of the pointer-map entry for a ** These macros define the location of the pointer-map entry for a
@ -1048,91 +1040,6 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){
#endif #endif
/*
** Do sanity checking on a page. Throw an exception if anything is
** not right.
**
** This routine is used for internal error checking only. It is omitted
** from most builds.
*/
#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0
static void _pageIntegrity(MemPage *pPage){
int usableSize;
u8 *data;
int i, j, idx, c, pc, hdr, nFree;
int cellOffset;
int nCell, cellLimit;
u8 *used;
used = sqliteMallocRaw( pPage->pBt->pageSize );
if( used==0 ) return;
usableSize = pPage->pBt->usableSize;
assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
hdr = pPage->hdrOffset;
assert( hdr==(pPage->pgno==1 ? 100 : 0) );
assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
c = pPage->aData[hdr];
if( pPage->isInit ){
assert( pPage->leaf == ((c & PTF_LEAF)!=0) );
assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );
assert( pPage->leafData == ((c & PTF_LEAFDATA)!=0) );
assert( pPage->intKey == ((c & (PTF_INTKEY|PTF_LEAFDATA))!=0) );
assert( pPage->hasData ==
!(pPage->zeroData || (!pPage->leaf && pPage->leafData)) );
assert( pPage->cellOffset==pPage->hdrOffset+12-4*pPage->leaf );
assert( pPage->nCell = get2byte(&pPage->aData[hdr+3]) );
}
data = pPage->aData;
memset(used, 0, usableSize);
for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;
nFree = 0;
pc = get2byte(&data[hdr+1]);
while( pc ){
int size;
assert( pc>0 && pc<usableSize-4 );
size = get2byte(&data[pc+2]);
assert( pc+size<=usableSize );
nFree += size;
for(i=pc; i<pc+size; i++){
assert( used[i]==0 );
used[i] = 1;
}
pc = get2byte(&data[pc]);
}
idx = 0;
nCell = get2byte(&data[hdr+3]);
cellLimit = get2byte(&data[hdr+5]);
assert( pPage->isInit==0
|| pPage->nFree==nFree+data[hdr+7]+cellLimit-(cellOffset+2*nCell) );
cellOffset = pPage->cellOffset;
for(i=0; i<nCell; i++){
int size;
pc = get2byte(&data[cellOffset+2*i]);
assert( pc>0 && pc<usableSize-4 );
size = cellSize(pPage, &data[pc]);
assert( pc+size<=usableSize );
for(j=pc; j<pc+size; j++){
assert( used[j]==0 );
used[j] = 1;
}
}
for(i=cellOffset+2*nCell; i<cellimit; i++){
assert( used[i]==0 );
used[i] = 1;
}
nFree = 0;
for(i=0; i<usableSize; i++){
assert( used[i]<=1 );
if( used[i]==0 ) nFree++;
}
assert( nFree==data[hdr+7] );
sqliteFree(used);
}
#define pageIntegrity(X) _pageIntegrity(X)
#else
# define pageIntegrity(X)
#endif
/* A bunch of assert() statements to check the transaction state variables /* A bunch of assert() statements to check the transaction state variables
** of handle p (type Btree*) are internally consistent. ** of handle p (type Btree*) are internally consistent.
*/ */
@ -1439,7 +1346,6 @@ static int initPage(
} }
pPage->isInit = 1; pPage->isInit = 1;
pageIntegrity(pPage);
return SQLITE_OK; return SQLITE_OK;
} }
@ -1470,7 +1376,6 @@ static void zeroPage(MemPage *pPage, int flags){
pPage->idxShift = 0; pPage->idxShift = 0;
pPage->nCell = 0; pPage->nCell = 0;
pPage->isInit = 1; pPage->isInit = 1;
pageIntegrity(pPage);
} }
/* /*
@ -1591,9 +1496,9 @@ int sqlite3BtreeOpen(
*/ */
#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM) #if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
#ifdef SQLITE_OMIT_MEMORYDB #ifdef SQLITE_OMIT_MEMORYDB
const int isMemdb = !zFilename; const int isMemdb = 0;
#else #else
const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1); const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
#endif #endif
#endif #endif
@ -1645,8 +1550,13 @@ int sqlite3BtreeOpen(
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags); rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
if( rc==SQLITE_OK ){
rc = sqlite3pager_read_fileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
}
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
if( pBt->pPager ) sqlite3pager_close(pBt->pPager); if( pBt->pPager ){
sqlite3pager_close(pBt->pPager);
}
sqliteFree(pBt); sqliteFree(pBt);
sqliteFree(p); sqliteFree(p);
*ppBtree = 0; *ppBtree = 0;
@ -1659,7 +1569,6 @@ int sqlite3BtreeOpen(
pBt->pCursor = 0; pBt->pCursor = 0;
pBt->pPage1 = 0; pBt->pPage1 = 0;
pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager); pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager);
sqlite3pager_read_fileheader(pBt->pPager, sizeof(zDbHeader), zDbHeader);
pBt->pageSize = get2byte(&zDbHeader[16]); pBt->pageSize = get2byte(&zDbHeader[16]);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
@ -2022,6 +1931,7 @@ static int lockBtreeWithRetry(Btree *pRef){
*/ */
static void unlockBtreeIfUnused(BtShared *pBt){ static void unlockBtreeIfUnused(BtShared *pBt){
if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
if( sqlite3pager_refcount(pBt->pPager)>=1 ){
if( pBt->pPage1->aData==0 ){ if( pBt->pPage1->aData==0 ){
MemPage *pPage = pBt->pPage1; MemPage *pPage = pBt->pPage1;
pPage->aData = &((u8*)pPage)[-pBt->pageSize]; pPage->aData = &((u8*)pPage)[-pBt->pageSize];
@ -2029,6 +1939,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){
pPage->pgno = 1; pPage->pgno = 1;
} }
releasePage(pBt->pPage1); releasePage(pBt->pPage1);
}
pBt->pPage1 = 0; pBt->pPage1 = 0;
pBt->inStmt = 0; pBt->inStmt = 0;
} }
@ -2548,7 +2459,7 @@ static int countWriteCursors(BtShared *pBt){
} }
#endif #endif
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/* /*
** Print debugging information about all cursors to standard output. ** Print debugging information about all cursors to standard output.
*/ */
@ -2778,7 +2689,7 @@ int sqlite3BtreeCursor(
if( pBt->readOnly ){ if( pBt->readOnly ){
return SQLITE_READONLY; return SQLITE_READONLY;
} }
if( checkReadLocks(pBt, iTable, 0) ){ if( checkReadLocks(p, iTable, 0) ){
return SQLITE_LOCKED; return SQLITE_LOCKED;
} }
} }
@ -2980,7 +2891,6 @@ static int getPayload(
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
pBt = pCur->pBtree->pBt; pBt = pCur->pBtree->pBt;
pPage = pCur->pPage; pPage = pCur->pPage;
pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur); getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader; aPayload = pCur->info.pCell + pCur->info.nHeader;
@ -3118,7 +3028,6 @@ static const unsigned char *fetchPayload(
assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur!=0 && pCur->pPage!=0 );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage; pPage = pCur->pPage;
pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur); getCellInfo(pCur);
aPayload = pCur->info.pCell; aPayload = pCur->info.pCell;
@ -3180,7 +3089,6 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage); rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
if( rc ) return rc; if( rc ) return rc;
pageIntegrity(pNewPage);
pNewPage->idxParent = pCur->idx; pNewPage->idxParent = pCur->idx;
pOldPage = pCur->pPage; pOldPage = pCur->pPage;
pOldPage->idxShift = 0; pOldPage->idxShift = 0;
@ -3228,10 +3136,8 @@ static void moveToParent(BtCursor *pCur){
pPage = pCur->pPage; pPage = pCur->pPage;
assert( pPage!=0 ); assert( pPage!=0 );
assert( !isRootPage(pPage) ); assert( !isRootPage(pPage) );
pageIntegrity(pPage);
pParent = pPage->pParent; pParent = pPage->pParent;
assert( pParent!=0 ); assert( pParent!=0 );
pageIntegrity(pParent);
idxParent = pPage->idxParent; idxParent = pPage->idxParent;
sqlite3pager_ref(pParent->aData); sqlite3pager_ref(pParent->aData);
releasePage(pPage); releasePage(pPage);
@ -3261,7 +3167,6 @@ static int moveToRoot(BtCursor *pCur){
return rc; return rc;
} }
releasePage(pCur->pPage); releasePage(pCur->pPage);
pageIntegrity(pRoot);
pCur->pPage = pRoot; pCur->pPage = pRoot;
} }
pCur->idx = 0; pCur->idx = 0;
@ -3415,7 +3320,6 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
if( !pPage->intKey && pKey==0 ){ if( !pPage->intKey && pKey==0 ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
pageIntegrity(pPage);
while( lwr<=upr ){ while( lwr<=upr ){
void *pCellKey; void *pCellKey;
i64 nCellKey; i64 nCellKey;
@ -3668,14 +3572,14 @@ static int allocatePage(
int rc; int rc;
int n; /* Number of pages on the freelist */ int n; /* Number of pages on the freelist */
int k; /* Number of leaves on the trunk of the freelist */ int k; /* Number of leaves on the trunk of the freelist */
MemPage *pTrunk = 0;
MemPage *pPrevTrunk = 0;
pPage1 = pBt->pPage1; pPage1 = pBt->pPage1;
n = get4byte(&pPage1->aData[36]); n = get4byte(&pPage1->aData[36]);
if( n>0 ){ if( n>0 ){
/* There are pages on the freelist. Reuse one of those pages. */ /* There are pages on the freelist. Reuse one of those pages. */
MemPage *pTrunk = 0;
Pgno iTrunk; Pgno iTrunk;
MemPage *pPrevTrunk = 0;
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */ u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
/* If the 'exact' parameter was true and a query of the pointer-map /* If the 'exact' parameter was true and a query of the pointer-map
@ -3716,16 +3620,8 @@ static int allocatePage(
} }
rc = getPage(pBt, iTrunk, &pTrunk); rc = getPage(pBt, iTrunk, &pTrunk);
if( rc ){ if( rc ){
releasePage(pPrevTrunk); pTrunk = 0;
return rc; goto end_allocate_page;
}
/* TODO: This should move to after the loop? */
rc = sqlite3pager_write(pTrunk->aData);
if( rc ){
releasePage(pTrunk);
releasePage(pPrevTrunk);
return rc;
} }
k = get4byte(&pTrunk->aData[4]); k = get4byte(&pTrunk->aData[4]);
@ -3734,6 +3630,10 @@ static int allocatePage(
** So extract the trunk page itself and use it as the newly ** So extract the trunk page itself and use it as the newly
** allocated page */ ** allocated page */
assert( pPrevTrunk==0 ); assert( pPrevTrunk==0 );
rc = sqlite3pager_write(pTrunk->aData);
if( rc ){
goto end_allocate_page;
}
*pPgno = iTrunk; *pPgno = iTrunk;
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk; *ppPage = pTrunk;
@ -3741,7 +3641,8 @@ static int allocatePage(
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>pBt->usableSize/4 - 8 ){ }else if( k>pBt->usableSize/4 - 8 ){
/* Value of k is out of range. Database corruption */ /* Value of k is out of range. Database corruption */
return SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
}else if( searchList && nearby==iTrunk ){ }else if( searchList && nearby==iTrunk ){
/* The list is being searched and this trunk page is the page /* The list is being searched and this trunk page is the page
@ -3750,6 +3651,10 @@ static int allocatePage(
assert( *pPgno==iTrunk ); assert( *pPgno==iTrunk );
*ppPage = pTrunk; *ppPage = pTrunk;
searchList = 0; searchList = 0;
rc = sqlite3pager_write(pTrunk->aData);
if( rc ){
goto end_allocate_page;
}
if( k==0 ){ if( k==0 ){
if( !pPrevTrunk ){ if( !pPrevTrunk ){
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
@ -3765,26 +3670,26 @@ static int allocatePage(
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
rc = getPage(pBt, iNewTrunk, &pNewTrunk); rc = getPage(pBt, iNewTrunk, &pNewTrunk);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
releasePage(pTrunk); goto end_allocate_page;
releasePage(pPrevTrunk);
return rc;
} }
rc = sqlite3pager_write(pNewTrunk->aData); rc = sqlite3pager_write(pNewTrunk->aData);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
releasePage(pNewTrunk); releasePage(pNewTrunk);
releasePage(pTrunk); goto end_allocate_page;
releasePage(pPrevTrunk);
return rc;
} }
memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4); memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4);
put4byte(&pNewTrunk->aData[4], k-1); put4byte(&pNewTrunk->aData[4], k-1);
memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4); memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4);
releasePage(pNewTrunk);
if( !pPrevTrunk ){ if( !pPrevTrunk ){
put4byte(&pPage1->aData[32], iNewTrunk); put4byte(&pPage1->aData[32], iNewTrunk);
}else{ }else{
rc = sqlite3pager_write(pPrevTrunk->aData);
if( rc ){
goto end_allocate_page;
}
put4byte(&pPrevTrunk->aData[0], iNewTrunk); put4byte(&pPrevTrunk->aData[0], iNewTrunk);
} }
releasePage(pNewTrunk);
} }
pTrunk = 0; pTrunk = 0;
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
@ -3794,6 +3699,10 @@ static int allocatePage(
int closest; int closest;
Pgno iPage; Pgno iPage;
unsigned char *aData = pTrunk->aData; unsigned char *aData = pTrunk->aData;
rc = sqlite3pager_write(aData);
if( rc ){
goto end_allocate_page;
}
if( nearby>0 ){ if( nearby>0 ){
int i, dist; int i, dist;
closest = 0; closest = 0;
@ -3837,8 +3746,8 @@ static int allocatePage(
} }
} }
releasePage(pPrevTrunk); releasePage(pPrevTrunk);
pPrevTrunk = 0;
}while( searchList ); }while( searchList );
releasePage(pTrunk);
}else{ }else{
/* There are no pages on the freelist, so create a new page at the /* There are no pages on the freelist, so create a new page at the
** end of the file */ ** end of the file */
@ -3867,6 +3776,10 @@ static int allocatePage(
} }
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
end_allocate_page:
releasePage(pTrunk);
releasePage(pPrevTrunk);
return rc; return rc;
} }
@ -4267,7 +4180,6 @@ static int insertCell(
put2byte(&data[ins], idx); put2byte(&data[ins], idx);
put2byte(&data[hdr+3], pPage->nCell); put2byte(&data[hdr+3], pPage->nCell);
pPage->idxShift = 1; pPage->idxShift = 1;
pageIntegrity(pPage);
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){ if( pPage->pBt->autoVacuum ){
/* The cell may contain a pointer to an overflow page. If so, write /* The cell may contain a pointer to an overflow page. If so, write
@ -5007,8 +4919,6 @@ static int balance_nonroot(MemPage *pPage){
** But the parent page will always be initialized. ** But the parent page will always be initialized.
*/ */
assert( pParent->isInit ); assert( pParent->isInit );
/* assert( pPage->isInit ); // No! pPage might have been added to freelist */
/* pageIntegrity(pPage); // No! pPage might have been added to freelist */
rc = balance(pParent, 0); rc = balance(pParent, 0);
/* /*
@ -5215,27 +5125,35 @@ static int balance(MemPage *pPage, int insert){
/* /*
** This routine checks all cursors that point to table pgnoRoot. ** This routine checks all cursors that point to table pgnoRoot.
** If any of those cursors other than pExclude were opened with ** If any of those cursors were opened with wrFlag==0 in a different
** wrFlag==0 then this routine returns SQLITE_LOCKED. If all ** database connection (a database connection that shares the pager
** cursors that point to pgnoRoot were opened with wrFlag==1 ** cache with the current connection) and that other connection
** then this routine returns SQLITE_OK. ** is not in the ReadUncommmitted state, then this routine returns
** SQLITE_LOCKED.
** **
** In addition to checking for read-locks (where a read-lock ** In addition to checking for read-locks (where a read-lock
** means a cursor opened with wrFlag==0) this routine also moves ** means a cursor opened with wrFlag==0) this routine also moves
** all cursors other than pExclude so that they are pointing to the ** all cursors write cursors so that they are pointing to the
** first Cell on root page. This is necessary because an insert ** first Cell on the root page. This is necessary because an insert
** or delete might change the number of cells on a page or delete ** or delete might change the number of cells on a page or delete
** a page entirely and we do not want to leave any cursors ** a page entirely and we do not want to leave any cursors
** pointing to non-existant pages or cells. ** pointing to non-existant pages or cells.
*/ */
static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){ static int checkReadLocks(Btree *pBtree, Pgno pgnoRoot, BtCursor *pExclude){
BtCursor *p; BtCursor *p;
BtShared *pBt = pBtree->pBt;
sqlite3 *db = pBtree->pSqlite;
for(p=pBt->pCursor; p; p=p->pNext){ for(p=pBt->pCursor; p; p=p->pNext){
u32 flags = (p->pBtree->pSqlite ? p->pBtree->pSqlite->flags : 0); if( p==pExclude ) continue;
if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue; if( p->eState!=CURSOR_VALID ) continue;
if( p->wrFlag==0 && flags&SQLITE_ReadUncommitted ) continue; if( p->pgnoRoot!=pgnoRoot ) continue;
if( p->wrFlag==0 ) return SQLITE_LOCKED; if( p->wrFlag==0 ){
if( p->pPage->pgno!=p->pgnoRoot ){ sqlite3 *dbOther = p->pBtree->pSqlite;
if( dbOther==0 ||
(dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0) ){
return SQLITE_LOCKED;
}
}else if( p->pPage->pgno!=p->pgnoRoot ){
moveToRoot(p); moveToRoot(p);
} }
} }
@ -5272,7 +5190,7 @@ int sqlite3BtreeInsert(
if( !pCur->wrFlag ){ if( !pCur->wrFlag ){
return SQLITE_PERM; /* Cursor not open for writing */ return SQLITE_PERM; /* Cursor not open for writing */
} }
if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){ if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */ return SQLITE_LOCKED; /* The table pCur points to has a read lock */
} }
@ -5354,7 +5272,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
if( !pCur->wrFlag ){ if( !pCur->wrFlag ){
return SQLITE_PERM; /* Did not open this cursor for writing */ return SQLITE_PERM; /* Did not open this cursor for writing */
} }
if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){ if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */ return SQLITE_LOCKED; /* The table pCur points to has a read lock */
} }
@ -5631,25 +5549,13 @@ cleardatabasepage_out:
*/ */
int sqlite3BtreeClearTable(Btree *p, int iTable){ int sqlite3BtreeClearTable(Btree *p, int iTable){
int rc; int rc;
BtCursor *pCur;
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
sqlite3 *db = p->pSqlite;
if( p->inTrans!=TRANS_WRITE ){ if( p->inTrans!=TRANS_WRITE ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
} }
rc = checkReadLocks(p, iTable, 0);
/* If this connection is not in read-uncommitted mode and currently has if( rc ){
** a read-cursor open on the table being cleared, return SQLITE_LOCKED. return rc;
*/
if( 0==db || 0==(db->flags&SQLITE_ReadUncommitted) ){
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( pCur->pBtree==p && pCur->pgnoRoot==(Pgno)iTable ){
if( 0==pCur->wrFlag ){
return SQLITE_LOCKED;
}
moveToRoot(pCur);
}
}
} }
/* Save the position of all cursors open on this table */ /* Save the position of all cursors open on this table */
@ -5969,7 +5875,7 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
} }
#endif #endif
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/* /*
** Fill aResult[] with information about the entry and page that the ** Fill aResult[] with information about the entry and page that the
** cursor is pointing to. ** cursor is pointing to.
@ -5997,14 +5903,12 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
return rc; return rc;
} }
pageIntegrity(pPage);
assert( pPage->isInit ); assert( pPage->isInit );
getTempCursor(pCur, &tmpCur); getTempCursor(pCur, &tmpCur);
while( upCnt-- ){ while( upCnt-- ){
moveToParent(&tmpCur); moveToParent(&tmpCur);
} }
pPage = tmpCur.pPage; pPage = tmpCur.pPage;
pageIntegrity(pPage);
aResult[0] = sqlite3pager_pagenumber(pPage->aData); aResult[0] = sqlite3pager_pagenumber(pPage->aData);
assert( aResult[0]==pPage->pgno ); assert( aResult[0]==pPage->pgno );
aResult[1] = tmpCur.idx; aResult[1] = tmpCur.idx;
@ -6057,7 +5961,9 @@ struct IntegrityCk {
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int nPage; /* Number of pages in the database */ int nPage; /* Number of pages in the database */
int *anRef; /* Number of times each page is referenced */ int *anRef; /* Number of times each page is referenced */
char *zErrMsg; /* An error message. NULL of no errors seen. */ int mxErr; /* Stop accumulating errors when this reaches zero */
char *zErrMsg; /* An error message. NULL if no errors seen. */
int nErr; /* Number of messages written to zErrMsg so far */
}; };
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
@ -6072,6 +5978,9 @@ static void checkAppendMsg(
){ ){
va_list ap; va_list ap;
char *zMsg2; char *zMsg2;
if( !pCheck->mxErr ) return;
pCheck->mxErr--;
pCheck->nErr++;
va_start(ap, zFormat); va_start(ap, zFormat);
zMsg2 = sqlite3VMPrintf(zFormat, ap); zMsg2 = sqlite3VMPrintf(zFormat, ap);
va_end(ap); va_end(ap);
@ -6155,7 +6064,7 @@ static void checkList(
int i; int i;
int expected = N; int expected = N;
int iFirst = iPage; int iFirst = iPage;
while( N-- > 0 ){ while( N-- > 0 && pCheck->mxErr ){
unsigned char *pOvfl; unsigned char *pOvfl;
if( iPage<1 ){ if( iPage<1 ){
checkAppendMsg(pCheck, zContext, checkAppendMsg(pCheck, zContext,
@ -6267,7 +6176,7 @@ static int checkTreePage(
/* Check out all the cells. /* Check out all the cells.
*/ */
depth = 0; depth = 0;
for(i=0; i<pPage->nCell; i++){ for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
u8 *pCell; u8 *pCell;
int sz; int sz;
CellInfo info; CellInfo info;
@ -6382,7 +6291,13 @@ static int checkTreePage(
** and a pointer to that error message is returned. The calling function ** and a pointer to that error message is returned. The calling function
** is responsible for freeing the error message when it is done. ** is responsible for freeing the error message when it is done.
*/ */
char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){ char *sqlite3BtreeIntegrityCheck(
Btree *p, /* The btree to be checked */
int *aRoot, /* An array of root pages numbers for individual trees */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
int *pnErr /* Write number of errors seen to this variable */
){
int i; int i;
int nRef; int nRef;
IntegrityCk sCheck; IntegrityCk sCheck;
@ -6395,6 +6310,9 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
sCheck.pBt = pBt; sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager; sCheck.pPager = pBt->pPager;
sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager); sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
*pnErr = 0;
if( sCheck.nPage==0 ){ if( sCheck.nPage==0 ){
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
return 0; return 0;
@ -6402,6 +6320,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) ); sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
if( !sCheck.anRef ){ if( !sCheck.anRef ){
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
*pnErr = 1;
return sqlite3MPrintf("Unable to malloc %d bytes", return sqlite3MPrintf("Unable to malloc %d bytes",
(sCheck.nPage+1)*sizeof(sCheck.anRef[0])); (sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
} }
@ -6419,7 +6338,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Check all the tables. /* Check all the tables.
*/ */
for(i=0; i<nRoot; i++){ for(i=0; i<nRoot && sCheck.mxErr; i++){
if( aRoot[i]==0 ) continue; if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 ){ if( pBt->autoVacuum && aRoot[i]>1 ){
@ -6431,7 +6350,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure every page in the file is referenced /* Make sure every page in the file is referenced
*/ */
for(i=1; i<=sCheck.nPage; i++){ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM #ifdef SQLITE_OMIT_AUTOVACUUM
if( sCheck.anRef[i]==0 ){ if( sCheck.anRef[i]==0 ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i); checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
@ -6464,6 +6383,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Clean up and report errors. /* Clean up and report errors.
*/ */
sqliteFree(sCheck.anRef); sqliteFree(sCheck.anRef);
*pnErr = sCheck.nErr;
return sCheck.zErrMsg; return sCheck.zErrMsg;
} }
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@ -6522,7 +6442,6 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage); rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
if( rc ) break; if( rc ) break;
rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage); rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
if( rc ) break;
sqlite3pager_unref(pPage); sqlite3pager_unref(pPage);
} }
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){

View file

@ -131,7 +131,7 @@ const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot); char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*); struct Pager *sqlite3BtreePager(Btree*);

View file

@ -1077,8 +1077,12 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName); pCol->zName);
}else{ }else{
Expr *pCopy;
sqlite3ExprDelete(pCol->pDflt); sqlite3ExprDelete(pCol->pDflt);
pCol->pDflt = sqlite3ExprDup(pExpr); pCol->pDflt = pCopy = sqlite3ExprDup(pExpr);
if( pCopy ){
sqlite3TokenCopy(&pCopy->span, &pExpr->span);
}
} }
} }
sqlite3ExprDelete(pExpr); sqlite3ExprDelete(pExpr);
@ -1586,7 +1590,8 @@ void sqlite3CreateView(
Token *pName1, /* The token that holds the name of the view */ Token *pName1, /* The token that holds the name of the view */
Token *pName2, /* The token that holds the name of the view */ Token *pName2, /* The token that holds the name of the view */
Select *pSelect, /* A SELECT statement that will become the new view */ Select *pSelect, /* A SELECT statement that will become the new view */
int isTemp /* TRUE for a TEMPORARY view */ int isTemp, /* TRUE for a TEMPORARY view */
int noErr /* Suppress error messages if VIEW already exists */
){ ){
Table *p; Table *p;
int n; int n;
@ -1601,7 +1606,7 @@ void sqlite3CreateView(
sqlite3SelectDelete(pSelect); sqlite3SelectDelete(pSelect);
return; return;
} }
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, 0); sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
p = pParse->pNewTable; p = pParse->pNewTable;
if( p==0 || pParse->nErr ){ if( p==0 || pParse->nErr ){
sqlite3SelectDelete(pSelect); sqlite3SelectDelete(pSelect);
@ -2935,15 +2940,6 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
} }
} }
/*
** Add an alias to the last identifier on the given identifier list.
*/
void sqlite3SrcListAddAlias(SrcList *pList, Token *pToken){
if( pList && pList->nSrc>0 ){
pList->a[pList->nSrc-1].zAlias = sqlite3NameFromToken(pToken);
}
}
/* /*
** Delete an entire SrcList including all its substructure. ** Delete an entire SrcList including all its substructure.
*/ */
@ -2963,6 +2959,74 @@ void sqlite3SrcListDelete(SrcList *pList){
sqliteFree(pList); sqliteFree(pList);
} }
/*
** This routine is called by the parser to add a new term to the
** end of a growing FROM clause. The "p" parameter is the part of
** the FROM clause that has already been constructed. "p" is NULL
** if this is the first term of the FROM clause. pTable and pDatabase
** are the name of the table and database named in the FROM clause term.
** pDatabase is NULL if the database name qualifier is missing - the
** usual case. If the term has a alias, then pAlias points to the
** alias token. If the term is a subquery, then pSubquery is the
** SELECT statement that the subquery encodes. The pTable and
** pDatabase parameters are NULL for subqueries. The pOn and pUsing
** parameters are the content of the ON and USING clauses.
**
** Return a new SrcList which encodes is the FROM with the new
** term added.
*/
SrcList *sqlite3SrcListAppendFromTerm(
SrcList *p, /* The left part of the FROM clause already seen */
Token *pTable, /* Name of the table to add to the FROM clause */
Token *pDatabase, /* Name of the database containing pTable */
Token *pAlias, /* The right-hand side of the AS subexpression */
Select *pSubquery, /* A subquery used in place of a table name */
Expr *pOn, /* The ON clause of a join */
IdList *pUsing /* The USING clause of a join */
){
struct SrcList_item *pItem;
p = sqlite3SrcListAppend(p, pTable, pDatabase);
if( p==0 || p->nSrc==0 ){
sqlite3ExprDelete(pOn);
sqlite3IdListDelete(pUsing);
sqlite3SelectDelete(pSubquery);
return p;
}
pItem = &p->a[p->nSrc-1];
if( pAlias && pAlias->n ){
pItem->zAlias = sqlite3NameFromToken(pAlias);
}
pItem->pSelect = pSubquery;
pItem->pOn = pOn;
pItem->pUsing = pUsing;
return p;
}
/*
** When building up a FROM clause in the parser, the join operator
** is initially attached to the left operand. But the code generator
** expects the join operator to be on the right operand. This routine
** Shifts all join operators from left to right for an entire FROM
** clause.
**
** Example: Suppose the join is like this:
**
** A natural cross join B
**
** The operator is "natural cross join". The A and B operands are stored
** in p->a[0] and p->a[1], respectively. The parser initially stores the
** operator with A. This routine shifts that operator over to B.
*/
void sqlite3SrcListShiftJoinType(SrcList *p){
if( p && p->a ){
int i;
for(i=p->nSrc-1; i>0; i--){
p->a[i].jointype = p->a[i-1].jointype;
}
p->a[0].jointype = 0;
}
}
/* /*
** Begin a transaction ** Begin a transaction
*/ */

View file

@ -237,11 +237,11 @@ static void computeJD(DateTime *p){
X2 = 30.6001*(M+1); X2 = 30.6001*(M+1);
p->rJD = X1 + X2 + D + B - 1524.5; p->rJD = X1 + X2 + D + B - 1524.5;
p->validJD = 1; p->validJD = 1;
p->validYMD = 0;
if( p->validHMS ){ if( p->validHMS ){
p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0; p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
if( p->validTZ ){ if( p->validTZ ){
p->rJD -= p->tz*60/86400.0; p->rJD -= p->tz*60/86400.0;
p->validYMD = 0;
p->validHMS = 0; p->validHMS = 0;
p->validTZ = 0; p->validTZ = 0;
} }
@ -360,6 +360,7 @@ static void computeYMD(DateTime *p){
static void computeHMS(DateTime *p){ static void computeHMS(DateTime *p){
int Z, s; int Z, s;
if( p->validHMS ) return; if( p->validHMS ) return;
computeJD(p);
Z = p->rJD + 0.5; Z = p->rJD + 0.5;
s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5; s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
p->s = 0.001*s; p->s = 0.001*s;
@ -415,8 +416,7 @@ static double localtimeOffset(DateTime *p){
computeJD(&x); computeJD(&x);
t = (x.rJD-2440587.5)*86400.0 + 0.5; t = (x.rJD-2440587.5)*86400.0 + 0.5;
sqlite3OsEnterMutex(); sqlite3OsEnterMutex();
pTm = php_localtime_r pTm = php_localtime_r(&t, &tmbuf);
(&t, &tmbuf);
y.Y = pTm->tm_year + 1900; y.Y = pTm->tm_year + 1900;
y.M = pTm->tm_mon + 1; y.M = pTm->tm_mon + 1;
y.D = pTm->tm_mday; y.D = pTm->tm_mday;
@ -813,9 +813,9 @@ static void strftimeFunc(
switch( zFmt[i] ){ switch( zFmt[i] ){
case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break; case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break;
case 'f': { case 'f': {
int s = x.s; double s = x.s;
int ms = (x.s - s)*1000.0; if( s>59.999 ) s = 59.999;
sprintf(&z[j],"%02d.%03d",s,ms); sqlite3_snprintf(7, &z[j],"%02.3f", s);
j += strlen(&z[j]); j += strlen(&z[j]);
break; break;
} }
@ -828,7 +828,7 @@ static void strftimeFunc(
y.M = 1; y.M = 1;
y.D = 1; y.D = 1;
computeJD(&y); computeJD(&y);
nDay = x.rJD - y.rJD; nDay = x.rJD - y.rJD + 0.5;
if( zFmt[i]=='W' ){ if( zFmt[i]=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = ((int)(x.rJD+0.5)) % 7; wd = ((int)(x.rJD+0.5)) % 7;
@ -848,7 +848,7 @@ static void strftimeFunc(
j += strlen(&z[j]); j += strlen(&z[j]);
break; break;
} }
case 'S': sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break; case 'S': sprintf(&z[j],"%02d",(int)x.s); j+=2; break;
case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break; case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break;
case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break; case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
case '%': z[j++] = '%'; break; case '%': z[j++] = '%'; break;
@ -948,9 +948,21 @@ static void currentTimeFunc(
} }
#endif #endif
#ifdef HAVE_GMTIME_R
{
struct tm sNow;
gmtime_r(&t, &sNow);
strftime(zBuf, 20, zFormat, &sNow);
}
#else
{
struct tm *pTm;
sqlite3OsEnterMutex(); sqlite3OsEnterMutex();
strftime(zBuf, 20, zFormat, gmtime(&t)); pTm = gmtime(&t);
strftime(zBuf, 20, zFormat, pTm);
sqlite3OsLeaveMutex(); sqlite3OsLeaveMutex();
}
#endif
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
} }

View file

@ -891,13 +891,13 @@ static int lookupName(
pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->iColumn = j==pTab->iPKey ? -1 : j;
pExpr->affinity = pTab->aCol[j].affinity; pExpr->affinity = pTab->aCol[j].affinity;
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0); pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
if( pItem->jointype & JT_NATURAL ){ if( i<pSrcList->nSrc-1 ){
if( pItem[1].jointype & JT_NATURAL ){
/* If this match occurred in the left table of a natural join, /* If this match occurred in the left table of a natural join,
** then skip the right table to avoid a duplicate match */ ** then skip the right table to avoid a duplicate match */
pItem++; pItem++;
i++; i++;
} }else if( (pUsing = pItem[1].pUsing)!=0 ){
if( (pUsing = pItem->pUsing)!=0 ){
/* If this match occurs on a column that is in the USING clause /* If this match occurs on a column that is in the USING clause
** of a join, skip the search of the right table of the join ** of a join, skip the search of the right table of the join
** to avoid a duplicate match there. */ ** to avoid a duplicate match there. */
@ -910,6 +910,7 @@ static int lookupName(
} }
} }
} }
}
break; break;
} }
} }
@ -1161,6 +1162,7 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
int wrong_num_args = 0; /* True if wrong number of arguments */ int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */ int is_agg = 0; /* True if is an aggregate function */
int i; int i;
int auth; /* Authorization to use the function */
int nId; /* Number of characters in function name */ int nId; /* Number of characters in function name */
const char *zId; /* The function name. */ const char *zId; /* The function name. */
FuncDef *pDef; /* Information about the function */ FuncDef *pDef; /* Information about the function */
@ -1179,6 +1181,20 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
}else{ }else{
is_agg = pDef->xFunc==0; is_agg = pDef->xFunc==0;
} }
#ifndef SQLITE_OMIT_AUTHORIZATION
if( pDef ){
auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
if( auth!=SQLITE_OK ){
if( auth==SQLITE_DENY ){
sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
pDef->zName);
pNC->nErr++;
}
pExpr->op = TK_NULL;
return 1;
}
}
#endif
if( is_agg && !pNC->allowAgg ){ if( is_agg && !pNC->allowAgg ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++; pNC->nErr++;
@ -2192,6 +2208,7 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
switch( pExpr->op ){ switch( pExpr->op ){
case TK_AGG_COLUMN:
case TK_COLUMN: { case TK_COLUMN: {
/* Check to see if the column is in one of the tables in the FROM /* Check to see if the column is in one of the tables in the FROM
** clause of the aggregate query */ ** clause of the aggregate query */

View file

@ -547,19 +547,6 @@ static void versionFunc(
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC); sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
} }
/*
** The MATCH() function is unimplemented. If anybody tries to use it,
** return an error.
*/
static void matchStub(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
static const char zErr[] = "MATCH is not implemented";
sqlite3_result_error(context, zErr, sizeof(zErr)-1);
}
/* /*
** EXPERIMENTAL - This is not an official function. The interface may ** EXPERIMENTAL - This is not an official function. The interface may
@ -654,15 +641,21 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
}; };
assert( argc==1 ); assert( argc==1 );
zIn = (u8*)sqlite3_value_text(argv[0]); zIn = (u8*)sqlite3_value_text(argv[0]);
if( zIn==0 ) zIn = ""; if( zIn==0 ) zIn = (u8*)"";
for(i=0; zIn[i] && !isalpha(zIn[i]); i++){} for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
if( zIn[i] ){ if( zIn[i] ){
u8 prevcode = iCode[zIn[i]&0x7f];
zResult[0] = toupper(zIn[i]); zResult[0] = toupper(zIn[i]);
for(j=1; j<4 && zIn[i]; i++){ for(j=1; j<4 && zIn[i]; i++){
int code = iCode[zIn[i]&0x7f]; int code = iCode[zIn[i]&0x7f];
if( code>0 ){ if( code>0 ){
if( code!=prevcode ){
prevcode = code;
zResult[j++] = code + '0'; zResult[j++] = code + '0';
} }
}else{
prevcode = 0;
}
} }
while( j<4 ){ while( j<4 ){
zResult[j++] = '0'; zResult[j++] = '0';
@ -1036,7 +1029,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid }, { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
{ "changes", 0, 1, SQLITE_UTF8, 0, changes }, { "changes", 0, 1, SQLITE_UTF8, 0, changes },
{ "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes }, { "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
{ "match", 2, 0, SQLITE_UTF8, 0, matchStub },
#ifdef SQLITE_SOUNDEX #ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif #endif
@ -1109,6 +1101,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
} }
} }
sqlite3RegisterDateTimeFunctions(db); sqlite3RegisterDateTimeFunctions(db);
sqlite3_overload_function(db, "MATCH", 2);
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
(void)sqlite3SseFunctions(db); (void)sqlite3SseFunctions(db);
#endif #endif

View file

@ -387,11 +387,9 @@ void sqlite3Insert(
NameContext sNC; NameContext sNC;
memset(&sNC, 0, sizeof(sNC)); memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse; sNC.pParse = pParse;
assert( pList!=0 );
srcTab = -1; srcTab = -1;
useTempTable = 0; useTempTable = 0;
assert( pList ); nColumn = pList ? pList->nExpr : 0;
nColumn = pList->nExpr;
for(i=0; i<nColumn; i++){ for(i=0; i<nColumn; i++){
if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){ if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){
goto insert_cleanup; goto insert_cleanup;
@ -402,7 +400,7 @@ void sqlite3Insert(
/* Make sure the number of columns in the source data matches the number /* Make sure the number of columns in the source data matches the number
** of columns to be inserted into the table. ** of columns to be inserted into the table.
*/ */
if( pColumn==0 && nColumn!=pTab->nCol ){ if( pColumn==0 && nColumn && nColumn!=pTab->nCol ){
sqlite3ErrorMsg(pParse, sqlite3ErrorMsg(pParse,
"table %S has %d columns but %d values were supplied", "table %S has %d columns but %d values were supplied",
pTabList, 0, pTab->nCol, nColumn); pTabList, 0, pTab->nCol, nColumn);
@ -455,7 +453,7 @@ void sqlite3Insert(
** key, the set the keyColumn variable to the primary key column index ** key, the set the keyColumn variable to the primary key column index
** in the original table definition. ** in the original table definition.
*/ */
if( pColumn==0 ){ if( pColumn==0 && nColumn>0 ){
keyColumn = pTab->iPKey; keyColumn = pTab->iPKey;
} }
@ -618,12 +616,12 @@ void sqlite3Insert(
if( pColumn->a[j].idx==i ) break; if( pColumn->a[j].idx==i ) break;
} }
} }
if( pColumn && j>=pColumn->nId ){ if( nColumn==0 || (pColumn && j>=pColumn->nId) ){
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt); sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
}else if( useTempTable ){ }else if( useTempTable ){
sqlite3VdbeAddOp(v, OP_Column, srcTab, j); sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
}else if( pSelect ){ }else if( pSelect ){
sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j, 1); sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j+IsVirtual(pTab), 1);
}else{ }else{
sqlite3ExprCode(pParse, pList->a[j].pExpr); sqlite3ExprCode(pParse, pList->a[j].pExpr);
} }

View file

@ -131,5 +131,6 @@ exec_out:
*pzErrMsg = 0; *pzErrMsg = 0;
} }
assert( (rc&db->errMask)==rc );
return rc; return rc;
} }

View file

@ -17,6 +17,7 @@
#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
#include "sqlite3ext.h" #include "sqlite3ext.h"
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
@ -74,6 +75,20 @@
# define sqlite3_declare_vtab 0 # define sqlite3_declare_vtab 0
#endif #endif
#ifdef SQLITE_OMIT_SHARED_CACHE
# define sqlite3_enable_shared_cache 0
#endif
#ifdef SQLITE_OMIT_TRACE
# define sqlite3_profile 0
# define sqlite3_trace 0
#endif
#ifdef SQLITE_OMIT_GET_TABLE
# define sqlite3_free_table 0
# define sqlite3_get_table 0
#endif
/* /*
** The following structure contains pointers to all SQLite API routines. ** The following structure contains pointers to all SQLite API routines.
** A pointer to this structure is passed into extensions when they are ** A pointer to this structure is passed into extensions when they are
@ -89,7 +104,7 @@
** also check to make sure that the pointer to the function is ** also check to make sure that the pointer to the function is
** not NULL before calling it. ** not NULL before calling it.
*/ */
const sqlite3_api_routines sqlite3_api = { const sqlite3_api_routines sqlite3_apis = {
sqlite3_aggregate_context, sqlite3_aggregate_context,
sqlite3_aggregate_count, sqlite3_aggregate_count,
sqlite3_bind_blob, sqlite3_bind_blob,
@ -153,7 +168,7 @@ const sqlite3_api_routines sqlite3_api = {
sqlite3_get_autocommit, sqlite3_get_autocommit,
sqlite3_get_auxdata, sqlite3_get_auxdata,
sqlite3_get_table, sqlite3_get_table,
sqlite3_global_recover, 0, /* Was sqlite3_global_recover(), but that function is deprecated */
sqlite3_interrupt, sqlite3_interrupt,
sqlite3_last_insert_rowid, sqlite3_last_insert_rowid,
sqlite3_libversion, sqlite3_libversion,
@ -213,30 +228,9 @@ const sqlite3_api_routines sqlite3_api = {
** a library that is new enough to support that API. ** a library that is new enough to support that API.
************************************************************************* *************************************************************************
*/ */
sqlite3_overload_function,
}; };
/*
** The windows implementation of shared-library loaders
*/
#if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) || defined(__BORLANDC__)
# include <windows.h>
# define SQLITE_LIBRARY_TYPE HANDLE
# define SQLITE_OPEN_LIBRARY(A) LoadLibrary(A)
# define SQLITE_FIND_SYMBOL(A,B) GetProcAddress(A,B)
# define SQLITE_CLOSE_LIBRARY(A) FreeLibrary(A)
#endif /* windows */
/*
** The unix implementation of shared-library loaders
*/
#if defined(HAVE_DLOPEN) && !defined(SQLITE_LIBRARY_TYPE)
# include <dlfcn.h>
# define SQLITE_LIBRARY_TYPE void*
# define SQLITE_OPEN_LIBRARY(A) dlopen(A, RTLD_NOW | RTLD_GLOBAL)
# define SQLITE_FIND_SYMBOL(A,B) dlsym(A,B)
# define SQLITE_CLOSE_LIBRARY(A) dlclose(A)
#endif
/* /*
** Attempt to load an SQLite extension library contained in the file ** Attempt to load an SQLite extension library contained in the file
** zFile. The entry point is zProc. zProc may be 0 in which case a ** zFile. The entry point is zProc. zProc may be 0 in which case a
@ -255,11 +249,10 @@ int sqlite3_load_extension(
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
char **pzErrMsg /* Put error message here if not 0 */ char **pzErrMsg /* Put error message here if not 0 */
){ ){
#ifdef SQLITE_LIBRARY_TYPE void *handle;
SQLITE_LIBRARY_TYPE handle;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
char *zErrmsg = 0; char *zErrmsg = 0;
SQLITE_LIBRARY_TYPE *aHandle; void **aHandle;
/* Ticket #1863. To avoid a creating security problems for older /* Ticket #1863. To avoid a creating security problems for older
** applications that relink against newer versions of SQLite, the ** applications that relink against newer versions of SQLite, the
@ -278,7 +271,7 @@ int sqlite3_load_extension(
zProc = "sqlite3_extension_init"; zProc = "sqlite3_extension_init";
} }
handle = SQLITE_OPEN_LIBRARY(zFile); handle = sqlite3OsDlopen(zFile);
if( handle==0 ){ if( handle==0 ){
if( pzErrMsg ){ if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile); *pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile);
@ -286,20 +279,20 @@ int sqlite3_load_extension(
return SQLITE_ERROR; return SQLITE_ERROR;
} }
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
SQLITE_FIND_SYMBOL(handle, zProc); sqlite3OsDlsym(handle, zProc);
if( xInit==0 ){ if( xInit==0 ){
if( pzErrMsg ){ if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("no entry point [%s] in shared library [%s]", *pzErrMsg = sqlite3_mprintf("no entry point [%s] in shared library [%s]",
zProc, zFile); zProc, zFile);
} }
SQLITE_CLOSE_LIBRARY(handle); sqlite3OsDlclose(handle);
return SQLITE_ERROR; return SQLITE_ERROR;
}else if( xInit(db, &zErrmsg, &sqlite3_api) ){ }else if( xInit(db, &zErrmsg, &sqlite3_apis) ){
if( pzErrMsg ){ if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
} }
sqlite3_free(zErrmsg); sqlite3_free(zErrmsg);
SQLITE_CLOSE_LIBRARY(handle); sqlite3OsDlclose(handle);
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@ -315,14 +308,8 @@ int sqlite3_load_extension(
sqliteFree(db->aExtension); sqliteFree(db->aExtension);
db->aExtension = aHandle; db->aExtension = aHandle;
((SQLITE_LIBRARY_TYPE*)db->aExtension)[db->nExtension-1] = handle; db->aExtension[db->nExtension-1] = handle;
return SQLITE_OK; return SQLITE_OK;
#else
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("extension loading is disabled");
}
return SQLITE_ERROR;
#endif
} }
/* /*
@ -330,13 +317,11 @@ int sqlite3_load_extension(
** to clean up loaded extensions ** to clean up loaded extensions
*/ */
void sqlite3CloseExtensions(sqlite3 *db){ void sqlite3CloseExtensions(sqlite3 *db){
#ifdef SQLITE_LIBRARY_TYPE
int i; int i;
for(i=0; i<db->nExtension; i++){ for(i=0; i<db->nExtension; i++){
SQLITE_CLOSE_LIBRARY(((SQLITE_LIBRARY_TYPE*)db->aExtension)[i]); sqlite3OsDlclose(db->aExtension[i]);
} }
sqliteFree(db->aExtension); sqliteFree(db->aExtension);
#endif
} }
/* /*
@ -352,4 +337,86 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
return SQLITE_OK; return SQLITE_OK;
} }
/*
** A list of automatically loaded extensions.
**
** This list is shared across threads, so be sure to hold the
** mutex while accessing or changing it.
*/
static int nAutoExtension = 0;
static void **aAutoExtension = 0;
/*
** Register a statically linked extension that is automatically
** loaded by every new database connection.
*/
int sqlite3_auto_extension(void *xInit){
int i;
int rc = SQLITE_OK;
sqlite3OsEnterMutex();
for(i=0; i<nAutoExtension; i++){
if( aAutoExtension[i]==xInit ) break;
}
if( i==nAutoExtension ){
nAutoExtension++;
aAutoExtension = sqlite3Realloc( aAutoExtension,
nAutoExtension*sizeof(aAutoExtension[0]) );
if( aAutoExtension==0 ){
nAutoExtension = 0;
rc = SQLITE_NOMEM;
}else{
aAutoExtension[nAutoExtension-1] = xInit;
}
}
sqlite3OsLeaveMutex();
assert( (rc&0xff)==rc );
return rc;
}
/*
** Reset the automatic extension loading mechanism.
*/
void sqlite3_reset_auto_extension(void){
sqlite3OsEnterMutex();
sqliteFree(aAutoExtension);
aAutoExtension = 0;
nAutoExtension = 0;
sqlite3OsLeaveMutex();
}
/*
** Load all automatic extensions.
*/
int sqlite3AutoLoadExtensions(sqlite3 *db){
int i;
int go = 1;
int rc = SQLITE_OK;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
if( nAutoExtension==0 ){
/* Common case: early out without every having to acquire a mutex */
return SQLITE_OK;
}
for(i=0; go; i++){
char *zErrmsg = 0;
sqlite3OsEnterMutex();
if( i>=nAutoExtension ){
xInit = 0;
go = 0;
}else{
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
aAutoExtension[i];
}
sqlite3OsLeaveMutex();
if( xInit && xInit(db, &zErrmsg, &sqlite3_apis) ){
sqlite3Error(db, SQLITE_ERROR,
"automatic extension loading failed: %s", zErrmsg);
go = 0;
rc = SQLITE_ERROR;
}
}
return rc;
}
#endif /* SQLITE_OMIT_LOAD_EXTENSION */ #endif /* SQLITE_OMIT_LOAD_EXTENSION */

View file

@ -223,7 +223,7 @@ void sqlite3RollbackAll(sqlite3 *db){
*/ */
const char *sqlite3ErrStr(int rc){ const char *sqlite3ErrStr(int rc){
const char *z; const char *z;
switch( rc ){ switch( rc & 0xff ){
case SQLITE_ROW: case SQLITE_ROW:
case SQLITE_DONE: case SQLITE_DONE:
case SQLITE_OK: z = "not an error"; break; case SQLITE_OK: z = "not an error"; break;
@ -541,6 +541,32 @@ int sqlite3_create_function16(
} }
#endif #endif
/*
** Declare that a function has been overloaded by a virtual table.
**
** If the function already exists as a regular global function, then
** this routine is a no-op. If the function does not exist, then create
** a new one that always throws a run-time error.
**
** When virtual tables intend to provide an overloaded function, they
** should call this routine to make sure the global function exists.
** A global function must exist in order for name resolution to work
** properly.
*/
int sqlite3_overload_function(
sqlite3 *db,
const char *zName,
int nArg
){
int nName = strlen(zName);
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
0, sqlite3InvalidFunction, 0, 0);
}
return sqlite3ApiExit(db, SQLITE_OK);
}
#ifndef SQLITE_OMIT_TRACE #ifndef SQLITE_OMIT_TRACE
/* /*
** Register a trace function. The pArg from the previously registered trace ** Register a trace function. The pArg from the previously registered trace
@ -763,7 +789,7 @@ int sqlite3_errcode(sqlite3 *db){
if( sqlite3SafetyCheck(db) ){ if( sqlite3SafetyCheck(db) ){
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
return db->errCode; return db->errCode & db->errMask;
} }
/* /*
@ -841,6 +867,7 @@ static int openDatabase(
/* Allocate the sqlite data structure */ /* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite3) ); db = sqliteMalloc( sizeof(sqlite3) );
if( db==0 ) goto opendb_out; if( db==0 ) goto opendb_out;
db->errMask = 0xff;
db->priorNewRowid = 0; db->priorNewRowid = 0;
db->magic = SQLITE_MAGIC_BUSY; db->magic = SQLITE_MAGIC_BUSY;
db->nDb = 2; db->nDb = 2;
@ -907,11 +934,30 @@ static int openDatabase(
** is accessed. ** is accessed.
*/ */
if( !sqlite3MallocFailed() ){ if( !sqlite3MallocFailed() ){
sqlite3RegisterBuiltinFunctions(db);
sqlite3Error(db, SQLITE_OK, 0); sqlite3Error(db, SQLITE_OK, 0);
sqlite3RegisterBuiltinFunctions(db);
} }
db->magic = SQLITE_MAGIC_OPEN; db->magic = SQLITE_MAGIC_OPEN;
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
*/
(void)sqlite3AutoLoadExtensions(db);
#ifdef SQLITE_ENABLE_FTS1
{
extern int sqlite3Fts1Init(sqlite3*);
sqlite3Fts1Init(db);
}
#endif
#ifdef SQLITE_ENABLE_FTS2
{
extern int sqlite3Fts2Init(sqlite3*);
sqlite3Fts2Init(db);
}
#endif
opendb_out: opendb_out:
if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){ if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
sqlite3_close(db); sqlite3_close(db);
@ -999,6 +1045,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
}else{ }else{
rc = sqlite3VdbeReset((Vdbe*)pStmt); rc = sqlite3VdbeReset((Vdbe*)pStmt);
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0); sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
assert( (rc & (sqlite3_db_handle(pStmt)->errMask))==rc );
} }
return rc; return rc;
} }
@ -1285,3 +1332,11 @@ int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int sqlite3_sleep(int ms){ int sqlite3_sleep(int ms){
return sqlite3OsSleep(ms); return sqlite3OsSleep(ms);
} }
/*
** Enable or disable the extended result codes.
*/
int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
db->errMask = onoff ? 0xffffffff : 0xff;
return SQLITE_OK;
}

View file

@ -2,136 +2,148 @@
/* See the mkopcodec.awk script for details. */ /* See the mkopcodec.awk script for details. */
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
const char *const sqlite3OpcodeNames[] = { "?", const char *const sqlite3OpcodeNames[] = { "?",
/* 1 */ "MemLoad", /* 1 */ "NotExists",
/* 2 */ "Column", /* 2 */ "Dup",
/* 3 */ "SetCookie", /* 3 */ "MoveLt",
/* 4 */ "IfMemPos", /* 4 */ "VCreate",
/* 5 */ "MoveGt", /* 5 */ "DropTrigger",
/* 6 */ "AggFocus", /* 6 */ "OpenPseudo",
/* 7 */ "RowKey", /* 7 */ "MemInt",
/* 8 */ "IdxRecno", /* 8 */ "IntegrityCk",
/* 9 */ "AggNext", /* 9 */ "RowKey",
/* 10 */ "OpenWrite", /* 10 */ "LoadAnalysis",
/* 11 */ "If", /* 11 */ "IdxGT",
/* 12 */ "PutStrKey", /* 12 */ "Last",
/* 13 */ "Pop", /* 13 */ "MemLoad",
/* 14 */ "SortPut", /* 14 */ "SetCookie",
/* 15 */ "AggContextPush", /* 15 */ "Sequence",
/* 16 */ "CollSeq", /* 16 */ "Not",
/* 17 */ "OpenRead", /* 17 */ "Pull",
/* 18 */ "Expire", /* 18 */ "VUpdate",
/* 19 */ "SortReset", /* 19 */ "VColumn",
/* 20 */ "AutoCommit", /* 20 */ "DropTable",
/* 21 */ "Sort", /* 21 */ "MemStore",
/* 22 */ "ListRewind", /* 22 */ "ContextPush",
/* 23 */ "IntegrityCk", /* 23 */ "Rowid",
/* 24 */ "Function", /* 24 */ "VFilter",
/* 25 */ "Noop", /* 25 */ "NullRow",
/* 26 */ "Return", /* 26 */ "Noop",
/* 27 */ "Variable", /* 27 */ "VRowid",
/* 28 */ "String", /* 28 */ "ParseSchema",
/* 29 */ "ParseSchema", /* 29 */ "Statement",
/* 30 */ "PutIntKey", /* 30 */ "CollSeq",
/* 31 */ "AggFunc", /* 31 */ "ContextPop",
/* 32 */ "Close", /* 32 */ "MemIncr",
/* 33 */ "ListWrite", /* 33 */ "MoveGe",
/* 34 */ "CreateIndex", /* 34 */ "If",
/* 35 */ "IsUnique", /* 35 */ "IfNot",
/* 36 */ "IdxIsNull", /* 36 */ "Destroy",
/* 37 */ "NotFound", /* 37 */ "Distinct",
/* 38 */ "MustBeInt", /* 38 */ "CreateIndex",
/* 39 */ "Halt", /* 39 */ "SetNumColumns",
/* 40 */ "IdxLT", /* 40 */ "ResetCount",
/* 41 */ "AddImm", /* 41 */ "MakeIdxRec",
/* 42 */ "Statement", /* 42 */ "Goto",
/* 43 */ "RowData", /* 43 */ "IdxDelete",
/* 44 */ "MemMax", /* 44 */ "MemMove",
/* 45 */ "Push", /* 45 */ "Found",
/* 46 */ "KeyAsData", /* 46 */ "MoveGt",
/* 47 */ "NotExists", /* 47 */ "IfMemZero",
/* 48 */ "OpenTemp", /* 48 */ "MustBeInt",
/* 49 */ "MemIncr", /* 49 */ "Prev",
/* 50 */ "Gosub", /* 50 */ "MemNull",
/* 51 */ "AggSet", /* 51 */ "AutoCommit",
/* 52 */ "Integer", /* 52 */ "String",
/* 53 */ "SortNext", /* 53 */ "FifoWrite",
/* 54 */ "Prev", /* 54 */ "Return",
/* 55 */ "CreateTable", /* 55 */ "Callback",
/* 56 */ "Last", /* 56 */ "AddImm",
/* 57 */ "ResetCount", /* 57 */ "Function",
/* 58 */ "Callback", /* 58 */ "NewRowid",
/* 59 */ "ContextPush", /* 59 */ "Blob",
/* 60 */ "DropTrigger", /* 60 */ "Next",
/* 61 */ "DropIndex", /* 61 */ "Or",
/* 62 */ "FullKey", /* 62 */ "And",
/* 63 */ "IdxGE", /* 63 */ "ForceInt",
/* 64 */ "Or", /* 64 */ "ReadCookie",
/* 65 */ "And", /* 65 */ "Halt",
/* 66 */ "Not", /* 66 */ "IsNull",
/* 67 */ "IdxDelete", /* 67 */ "NotNull",
/* 68 */ "Vacuum", /* 68 */ "Ne",
/* 69 */ "MoveLe", /* 69 */ "Eq",
/* 70 */ "IsNull", /* 70 */ "Gt",
/* 71 */ "NotNull", /* 71 */ "Le",
/* 72 */ "Ne", /* 72 */ "Lt",
/* 73 */ "Eq", /* 73 */ "Ge",
/* 74 */ "Gt", /* 74 */ "Expire",
/* 75 */ "Le", /* 75 */ "BitAnd",
/* 76 */ "Lt", /* 76 */ "BitOr",
/* 77 */ "Ge", /* 77 */ "ShiftLeft",
/* 78 */ "IfNot", /* 78 */ "ShiftRight",
/* 79 */ "BitAnd", /* 79 */ "Add",
/* 80 */ "BitOr", /* 80 */ "Subtract",
/* 81 */ "ShiftLeft", /* 81 */ "Multiply",
/* 82 */ "ShiftRight", /* 82 */ "Divide",
/* 83 */ "Add", /* 83 */ "Remainder",
/* 84 */ "Subtract", /* 84 */ "Concat",
/* 85 */ "Multiply", /* 85 */ "Negative",
/* 86 */ "Divide", /* 86 */ "DropIndex",
/* 87 */ "Remainder", /* 87 */ "BitNot",
/* 88 */ "Concat", /* 88 */ "String8",
/* 89 */ "Negative", /* 89 */ "IdxInsert",
/* 90 */ "DropTable", /* 90 */ "FifoRead",
/* 91 */ "BitNot", /* 91 */ "Column",
/* 92 */ "String8", /* 92 */ "Int64",
/* 93 */ "MakeRecord", /* 93 */ "Gosub",
/* 94 */ "Delete", /* 94 */ "IfMemNeg",
/* 95 */ "AggContextPop", /* 95 */ "RowData",
/* 96 */ "ListRead", /* 96 */ "MemMax",
/* 97 */ "ListReset", /* 97 */ "Close",
/* 98 */ "Dup", /* 98 */ "VerifyCookie",
/* 99 */ "Goto", /* 99 */ "IfMemPos",
/* 100 */ "Clear", /* 100 */ "Null",
/* 101 */ "IdxGT", /* 101 */ "Integer",
/* 102 */ "MoveLt", /* 102 */ "Transaction",
/* 103 */ "VerifyCookie", /* 103 */ "IdxLT",
/* 104 */ "Pull", /* 104 */ "Delete",
/* 105 */ "SetNumColumns", /* 105 */ "Rewind",
/* 106 */ "AbsValue", /* 106 */ "Push",
/* 107 */ "Transaction", /* 107 */ "RealAffinity",
/* 108 */ "AggGet", /* 108 */ "Clear",
/* 109 */ "ContextPop", /* 109 */ "AggStep",
/* 110 */ "Next", /* 110 */ "Explain",
/* 111 */ "AggInit", /* 111 */ "Vacuum",
/* 112 */ "Distinct", /* 112 */ "VDestroy",
/* 113 */ "NewRecno", /* 113 */ "IsUnique",
/* 114 */ "AggReset", /* 114 */ "VOpen",
/* 115 */ "Destroy", /* 115 */ "AggFinal",
/* 116 */ "ReadCookie", /* 116 */ "OpenWrite",
/* 117 */ "ForceInt", /* 117 */ "VNext",
/* 118 */ "Recno", /* 118 */ "AbsValue",
/* 119 */ "OpenPseudo", /* 119 */ "Sort",
/* 120 */ "Blob", /* 120 */ "NotFound",
/* 121 */ "MemStore", /* 121 */ "MoveLe",
/* 122 */ "Rewind", /* 122 */ "MakeRecord",
/* 123 */ "MoveGe", /* 123 */ "Variable",
/* 124 */ "IdxPut", /* 124 */ "CreateTable",
/* 125 */ "Found", /* 125 */ "Insert",
/* 126 */ "NullRow", /* 126 */ "Real",
/* 127 */ "NotUsed_127", /* 127 */ "HexBlob",
/* 128 */ "NotUsed_128", /* 128 */ "IdxGE",
/* 129 */ "NotUsed_129", /* 129 */ "OpenRead",
/* 130 */ "Real", /* 130 */ "IdxRowid",
/* 131 */ "HexBlob", /* 131 */ "VBegin",
/* 132 */ "TableLock",
/* 133 */ "OpenEphemeral",
/* 134 */ "Pop",
/* 135 */ "NotUsed_135",
/* 136 */ "NotUsed_136",
/* 137 */ "NotUsed_137",
/* 138 */ "NotUsed_138",
/* 139 */ "ToText",
/* 140 */ "ToBlob",
/* 141 */ "ToNumeric",
/* 142 */ "ToInt",
/* 143 */ "ToReal",
}; };
#endif #endif

View file

@ -1,147 +1,147 @@
/* Automatically generated. Do not edit */ /* Automatically generated. Do not edit */
/* See the mkopcodeh.awk script for details */ /* See the mkopcodeh.awk script for details */
#define OP_MemLoad 1 #define OP_NotExists 1
#define OP_VNext 2 #define OP_Dup 2
#define OP_HexBlob 127 /* same as TK_BLOB */ #define OP_MoveLt 3
#define OP_Column 3
#define OP_SetCookie 4
#define OP_IfMemPos 5
#define OP_Real 126 /* same as TK_FLOAT */
#define OP_Sequence 6
#define OP_MoveGt 7
#define OP_Ge 73 /* same as TK_GE */
#define OP_RowKey 8
#define OP_Eq 69 /* same as TK_EQ */
#define OP_OpenWrite 9
#define OP_NotNull 67 /* same as TK_NOTNULL */
#define OP_If 10
#define OP_ToInt 142 /* same as TK_TO_INT */
#define OP_String8 88 /* same as TK_STRING */
#define OP_Pop 11
#define OP_VRowid 12
#define OP_CollSeq 13
#define OP_OpenRead 14
#define OP_Expire 15
#define OP_AutoCommit 17
#define OP_Gt 70 /* same as TK_GT */
#define OP_IntegrityCk 18
#define OP_Sort 19
#define OP_Function 20
#define OP_And 62 /* same as TK_AND */
#define OP_Subtract 80 /* same as TK_MINUS */
#define OP_Noop 21
#define OP_Return 22
#define OP_Remainder 83 /* same as TK_REM */
#define OP_NewRowid 23
#define OP_Multiply 81 /* same as TK_STAR */ #define OP_Multiply 81 /* same as TK_STAR */
#define OP_IfMemNeg 24 #define OP_VCreate 4
#define OP_Variable 25
#define OP_String 26
#define OP_RealAffinity 27
#define OP_ParseSchema 28
#define OP_VOpen 29
#define OP_Close 30
#define OP_CreateIndex 31
#define OP_IsUnique 32
#define OP_IdxIsNull 33
#define OP_NotFound 34
#define OP_Int64 35
#define OP_MustBeInt 36
#define OP_Halt 37
#define OP_Rowid 38
#define OP_IdxLT 39
#define OP_AddImm 40
#define OP_Statement 41
#define OP_RowData 42
#define OP_MemMax 43
#define OP_Push 44
#define OP_Or 61 /* same as TK_OR */
#define OP_NotExists 45
#define OP_MemIncr 46
#define OP_Gosub 47
#define OP_Divide 82 /* same as TK_SLASH */
#define OP_Integer 48
#define OP_ToNumeric 141 /* same as TK_TO_NUMERIC*/
#define OP_MemInt 49
#define OP_Prev 50
#define OP_Concat 84 /* same as TK_CONCAT */
#define OP_BitAnd 75 /* same as TK_BITAND */ #define OP_BitAnd 75 /* same as TK_BITAND */
#define OP_VColumn 51 #define OP_DropTrigger 5
#define OP_CreateTable 52 #define OP_OpenPseudo 6
#define OP_Last 53 #define OP_MemInt 7
#define OP_IsNull 66 /* same as TK_ISNULL */ #define OP_IntegrityCk 8
#define OP_IdxRowid 54 #define OP_RowKey 9
#define OP_MakeIdxRec 55 #define OP_LoadAnalysis 10
#define OP_ShiftRight 78 /* same as TK_RSHIFT */ #define OP_IdxGT 11
#define OP_ResetCount 56 #define OP_Last 12
#define OP_FifoWrite 57 #define OP_Subtract 80 /* same as TK_MINUS */
#define OP_Callback 58 #define OP_MemLoad 13
#define OP_ContextPush 59 #define OP_Remainder 83 /* same as TK_REM */
#define OP_DropTrigger 60 #define OP_SetCookie 14
#define OP_DropIndex 63 #define OP_Sequence 15
#define OP_IdxGE 64 #define OP_Pull 17
#define OP_IdxDelete 65 #define OP_VUpdate 18
#define OP_Vacuum 74 #define OP_VColumn 19
#define OP_MoveLe 86 #define OP_DropTable 20
#define OP_IfNot 89 #define OP_MemStore 21
#define OP_DropTable 90 #define OP_ContextPush 22
#define OP_MakeRecord 91 #define OP_NotNull 67 /* same as TK_NOTNULL */
#define OP_ToBlob 140 /* same as TK_TO_BLOB */ #define OP_Rowid 23
#define OP_Delete 92 #define OP_Real 126 /* same as TK_FLOAT */
#define OP_AggFinal 93 #define OP_String8 88 /* same as TK_STRING */
#define OP_ShiftLeft 77 /* same as TK_LSHIFT */ #define OP_And 62 /* same as TK_AND */
#define OP_Dup 94
#define OP_Goto 95
#define OP_TableLock 96
#define OP_FifoRead 97
#define OP_Clear 98
#define OP_IdxGT 99
#define OP_MoveLt 100
#define OP_Le 71 /* same as TK_LE */
#define OP_VerifyCookie 101
#define OP_AggStep 102
#define OP_Pull 103
#define OP_ToText 139 /* same as TK_TO_TEXT */
#define OP_Not 16 /* same as TK_NOT */
#define OP_ToReal 143 /* same as TK_TO_REAL */
#define OP_SetNumColumns 104
#define OP_AbsValue 105
#define OP_Transaction 106
#define OP_VFilter 107
#define OP_Negative 85 /* same as TK_UMINUS */
#define OP_Ne 68 /* same as TK_NE */
#define OP_VDestroy 108
#define OP_ContextPop 109
#define OP_BitOr 76 /* same as TK_BITOR */
#define OP_Next 110
#define OP_IdxInsert 111
#define OP_Distinct 112
#define OP_Lt 72 /* same as TK_LT */
#define OP_Insert 113
#define OP_Destroy 114
#define OP_ReadCookie 115
#define OP_ForceInt 116
#define OP_LoadAnalysis 117
#define OP_Explain 118
#define OP_IfMemZero 119
#define OP_OpenPseudo 120
#define OP_OpenEphemeral 121
#define OP_Null 122
#define OP_Blob 123
#define OP_Add 79 /* same as TK_PLUS */
#define OP_MemStore 124
#define OP_Rewind 125
#define OP_MoveGe 128
#define OP_VBegin 129
#define OP_VUpdate 130
#define OP_BitNot 87 /* same as TK_BITNOT */ #define OP_BitNot 87 /* same as TK_BITNOT */
#define OP_VCreate 131 #define OP_VFilter 24
#define OP_MemMove 132 #define OP_NullRow 25
#define OP_MemNull 133 #define OP_Noop 26
#define OP_Found 134 #define OP_VRowid 27
#define OP_NullRow 135 #define OP_Ge 73 /* same as TK_GE */
#define OP_HexBlob 127 /* same as TK_BLOB */
#define OP_ParseSchema 28
#define OP_Statement 29
#define OP_CollSeq 30
#define OP_ContextPop 31
#define OP_ToText 139 /* same as TK_TO_TEXT */
#define OP_MemIncr 32
#define OP_MoveGe 33
#define OP_Eq 69 /* same as TK_EQ */
#define OP_ToNumeric 141 /* same as TK_TO_NUMERIC*/
#define OP_If 34
#define OP_IfNot 35
#define OP_ShiftRight 78 /* same as TK_RSHIFT */
#define OP_Destroy 36
#define OP_Distinct 37
#define OP_CreateIndex 38
#define OP_SetNumColumns 39
#define OP_Not 16 /* same as TK_NOT */
#define OP_Gt 70 /* same as TK_GT */
#define OP_ResetCount 40
#define OP_MakeIdxRec 41
#define OP_Goto 42
#define OP_IdxDelete 43
#define OP_MemMove 44
#define OP_Found 45
#define OP_MoveGt 46
#define OP_IfMemZero 47
#define OP_MustBeInt 48
#define OP_Prev 49
#define OP_MemNull 50
#define OP_AutoCommit 51
#define OP_String 52
#define OP_FifoWrite 53
#define OP_ToInt 142 /* same as TK_TO_INT */
#define OP_Return 54
#define OP_Callback 55
#define OP_AddImm 56
#define OP_Function 57
#define OP_Concat 84 /* same as TK_CONCAT */
#define OP_NewRowid 58
#define OP_Blob 59
#define OP_IsNull 66 /* same as TK_ISNULL */
#define OP_Next 60
#define OP_ForceInt 63
#define OP_ReadCookie 64
#define OP_Halt 65
#define OP_Expire 74
#define OP_Or 61 /* same as TK_OR */
#define OP_DropIndex 86
#define OP_IdxInsert 89
#define OP_ShiftLeft 77 /* same as TK_LSHIFT */
#define OP_FifoRead 90
#define OP_Column 91
#define OP_Int64 92
#define OP_Gosub 93
#define OP_IfMemNeg 94
#define OP_RowData 95
#define OP_BitOr 76 /* same as TK_BITOR */
#define OP_MemMax 96
#define OP_Close 97
#define OP_ToReal 143 /* same as TK_TO_REAL */
#define OP_VerifyCookie 98
#define OP_IfMemPos 99
#define OP_Null 100
#define OP_Integer 101
#define OP_Transaction 102
#define OP_Divide 82 /* same as TK_SLASH */
#define OP_IdxLT 103
#define OP_Delete 104
#define OP_Rewind 105
#define OP_Push 106
#define OP_RealAffinity 107
#define OP_Clear 108
#define OP_AggStep 109
#define OP_Explain 110
#define OP_Vacuum 111
#define OP_VDestroy 112
#define OP_IsUnique 113
#define OP_VOpen 114
#define OP_AggFinal 115
#define OP_OpenWrite 116
#define OP_Negative 85 /* same as TK_UMINUS */
#define OP_Le 71 /* same as TK_LE */
#define OP_VNext 117
#define OP_AbsValue 118
#define OP_Sort 119
#define OP_NotFound 120
#define OP_MoveLe 121
#define OP_MakeRecord 122
#define OP_Add 79 /* same as TK_PLUS */
#define OP_Ne 68 /* same as TK_NE */
#define OP_Variable 123
#define OP_CreateTable 124
#define OP_Insert 125
#define OP_IdxGE 128
#define OP_OpenRead 129
#define OP_IdxRowid 130
#define OP_ToBlob 140 /* same as TK_TO_BLOB */
#define OP_VBegin 131
#define OP_TableLock 132
#define OP_OpenEphemeral 133
#define OP_Lt 72 /* same as TK_LT */
#define OP_Pop 134
/* The following opcode values are never used */ /* The following opcode values are never used */
#define OP_NotUsed_135 135
#define OP_NotUsed_136 136 #define OP_NotUsed_136 136
#define OP_NotUsed_137 137 #define OP_NotUsed_137 137
#define OP_NotUsed_138 138 #define OP_NotUsed_138 138
@ -149,13 +149,13 @@
/* Opcodes that are guaranteed to never push a value onto the stack /* Opcodes that are guaranteed to never push a value onto the stack
** contain a 1 their corresponding position of the following mask ** contain a 1 their corresponding position of the following mask
** set. See the opcodeNoPush() function in vdbeaux.c */ ** set. See the opcodeNoPush() function in vdbeaux.c */
#define NOPUSH_MASK_0 0xeeb4 #define NOPUSH_MASK_0 0x5c7a
#define NOPUSH_MASK_1 0x796b #define NOPUSH_MASK_1 0xf777
#define NOPUSH_MASK_2 0xfbb7 #define NOPUSH_MASK_2 0xedaf
#define NOPUSH_MASK_3 0xff24 #define NOPUSH_MASK_3 0xf1eb
#define NOPUSH_MASK_4 0xffff #define NOPUSH_MASK_4 0xfffe
#define NOPUSH_MASK_5 0xb6ef #define NOPUSH_MASK_5 0x62ef
#define NOPUSH_MASK_6 0xfdfd #define NOPUSH_MASK_6 0xbfcf
#define NOPUSH_MASK_7 0x33b3 #define NOPUSH_MASK_7 0x23bf
#define NOPUSH_MASK_8 0xf8cf #define NOPUSH_MASK_8 0xf87b
#define NOPUSH_MASK_9 0x0000 #define NOPUSH_MASK_9 0x0000

View file

@ -81,9 +81,21 @@
** prefix to reflect your program's name, so that if your program exits ** prefix to reflect your program's name, so that if your program exits
** prematurely, old temporary files can be easily identified. This can be done ** prematurely, old temporary files can be easily identified. This can be done
** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line. ** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
**
** 2006-10-31: The default prefix used to be "sqlite_". But then
** Mcafee started using SQLite in their anti-virus product and it
** started putting files with the "sqlite" name in the c:/temp folder.
** This annoyed many windows users. Those users would then do a
** Google search for "sqlite", find the telephone numbers of the
** developers and call to wake them up at night and complain.
** For this reason, the default name prefix is changed to be "sqlite"
** spelled backwards. So the temp files are still identified, but
** anybody smart enough to figure out the code is also likely smart
** enough to know that calling the developer will not help get rid
** of the file.
*/ */
#ifndef TEMP_FILE_PREFIX #ifndef TEMP_FILE_PREFIX
# define TEMP_FILE_PREFIX "sqlite_" # define TEMP_FILE_PREFIX "etilqs_"
#endif #endif
/* /*
@ -110,6 +122,9 @@
#define sqlite3OsRealloc sqlite3GenericRealloc #define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree #define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize #define sqlite3OsAllocationSize sqlite3GenericAllocationSize
#define sqlite3OsDlopen sqlite3UnixDlopen
#define sqlite3OsDlsym sqlite3UnixDlsym
#define sqlite3OsDlclose sqlite3UnixDlclose
#endif #endif
#if OS_WIN #if OS_WIN
#define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite #define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite
@ -132,6 +147,9 @@
#define sqlite3OsRealloc sqlite3GenericRealloc #define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree #define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize #define sqlite3OsAllocationSize sqlite3GenericAllocationSize
#define sqlite3OsDlopen sqlite3WinDlopen
#define sqlite3OsDlsym sqlite3WinDlsym
#define sqlite3OsDlclose sqlite3WinDlclose
#endif #endif
#if OS_OS2 #if OS_OS2
#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite #define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite
@ -154,6 +172,9 @@
#define sqlite3OsRealloc sqlite3GenericRealloc #define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree #define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize #define sqlite3OsAllocationSize sqlite3GenericAllocationSize
#define sqlite3OsDlopen sqlite3Os2Dlopen
#define sqlite3OsDlsym sqlite3Os2Dlsym
#define sqlite3OsDlclose sqlite3Os2Dlclose
#endif #endif
@ -337,6 +358,9 @@ void *sqlite3OsMalloc(int);
void *sqlite3OsRealloc(void *, int); void *sqlite3OsRealloc(void *, int);
void sqlite3OsFree(void *); void sqlite3OsFree(void *);
int sqlite3OsAllocationSize(void *); int sqlite3OsAllocationSize(void *);
void *sqlite3OsDlopen(const char*);
void *sqlite3OsDlsym(void*, const char*);
int sqlite3OsDlclose(void*);
/* /*
** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer ** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer
@ -381,16 +405,26 @@ struct sqlite3OsVtbl {
void *(*xRealloc)(void *, int); void *(*xRealloc)(void *, int);
void (*xFree)(void *); void (*xFree)(void *);
int (*xAllocationSize)(void *); int (*xAllocationSize)(void *);
void *(*xDlopen)(const char*);
void *(*xDlsym)(void*, const char*);
int (*xDlclose)(void*);
}; };
/* Macro used to comment out routines that do not exists when there is /* Macro used to comment out routines that do not exists when there is
** no disk I/O ** no disk I/O or extension loading
*/ */
#ifdef SQLITE_OMIT_DISKIO #ifdef SQLITE_OMIT_DISKIO
# define IF_DISKIO(X) 0 # define IF_DISKIO(X) 0
#else #else
# define IF_DISKIO(X) X # define IF_DISKIO(X) X
#endif #endif
#ifdef SQLITE_OMIT_LOAD_EXTENSION
# define IF_DLOPEN(X) 0
#else
# define IF_DLOPEN(X) X
#endif
#ifdef _SQLITE_OS_C_ #ifdef _SQLITE_OS_C_
/* /*
@ -416,7 +450,10 @@ struct sqlite3OsVtbl {
sqlite3OsMalloc, sqlite3OsMalloc,
sqlite3OsRealloc, sqlite3OsRealloc,
sqlite3OsFree, sqlite3OsFree,
sqlite3OsAllocationSize sqlite3OsAllocationSize,
IF_DLOPEN( sqlite3OsDlopen ),
IF_DLOPEN( sqlite3OsDlsym ),
IF_DLOPEN( sqlite3OsDlclose ),
}; };
#else #else
/* /*

View file

@ -92,25 +92,25 @@ int sqlite3_io_error_hit = 0;
int sqlite3_io_error_pending = 0; int sqlite3_io_error_pending = 0;
int sqlite3_diskfull_pending = 0; int sqlite3_diskfull_pending = 0;
int sqlite3_diskfull = 0; int sqlite3_diskfull = 0;
#define SimulateIOError(A) \ #define SimulateIOError(CODE) \
if( sqlite3_io_error_pending ) \ if( sqlite3_io_error_pending ) \
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; } if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); CODE; }
static void local_ioerr(){ static void local_ioerr(){
sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */ sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */
} }
#define SimulateDiskfullError \ #define SimulateDiskfullError(CODE) \
if( sqlite3_diskfull_pending ){ \ if( sqlite3_diskfull_pending ){ \
if( sqlite3_diskfull_pending == 1 ){ \ if( sqlite3_diskfull_pending == 1 ){ \
local_ioerr(); \ local_ioerr(); \
sqlite3_diskfull = 1; \ sqlite3_diskfull = 1; \
return SQLITE_FULL; \ CODE; \
}else{ \ }else{ \
sqlite3_diskfull_pending--; \ sqlite3_diskfull_pending--; \
} \ } \
} }
#else #else
#define SimulateIOError(A) #define SimulateIOError(A)
#define SimulateDiskfullError #define SimulateDiskfullError(A)
#endif #endif
/* /*

File diff suppressed because it is too large Load diff

View file

@ -40,6 +40,7 @@
*/ */
#if defined(_WIN32_WCE) #if defined(_WIN32_WCE)
# define OS_WINCE 1 # define OS_WINCE 1
# define AreFileApisANSI() 1
#else #else
# define OS_WINCE 0 # define OS_WINCE 0
#endif #endif
@ -124,16 +125,14 @@ int sqlite3_os_type = 0;
#endif /* OS_WINCE */ #endif /* OS_WINCE */
/* /*
** Convert a UTF-8 string to UTF-32. Space to hold the returned string ** Convert a UTF-8 string to microsoft unicode (UTF-16?).
** is obtained from sqliteMalloc. **
** Space to hold the returned string is obtained from sqliteMalloc.
*/ */
static WCHAR *utf8ToUnicode(const char *zFilename){ static WCHAR *utf8ToUnicode(const char *zFilename){
int nChar; int nChar;
WCHAR *zWideFilename; WCHAR *zWideFilename;
if( !isNT() ){
return 0;
}
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) ); zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){ if( zWideFilename==0 ){
@ -148,7 +147,7 @@ static WCHAR *utf8ToUnicode(const char *zFilename){
} }
/* /*
** Convert UTF-32 to UTF-8. Space to hold the returned string is ** Convert microsoft unicode to UTF-8. Space to hold the returned string is
** obtained from sqliteMalloc(). ** obtained from sqliteMalloc().
*/ */
static char *unicodeToUtf8(const WCHAR *zWideFilename){ static char *unicodeToUtf8(const WCHAR *zWideFilename){
@ -169,6 +168,91 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){
return zFilename; return zFilename;
} }
/*
** Convert an ansi string to microsoft unicode, based on the
** current codepage settings for file apis.
**
** Space to hold the returned string is obtained
** from sqliteMalloc.
*/
static WCHAR *mbcsToUnicode(const char *zFilename){
int nByte;
WCHAR *zMbcsFilename;
int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR);
zMbcsFilename = sqliteMalloc( nByte*sizeof(zMbcsFilename[0]) );
if( zMbcsFilename==0 ){
return 0;
}
nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
if( nByte==0 ){
sqliteFree(zMbcsFilename);
zMbcsFilename = 0;
}
return zMbcsFilename;
}
/*
** Convert microsoft unicode to multibyte character string, based on the
** user's Ansi codepage.
**
** Space to hold the returned string is obtained from
** sqliteMalloc().
*/
static char *unicodeToMbcs(const WCHAR *zWideFilename){
int nByte;
char *zFilename;
int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
zFilename = sqliteMalloc( nByte );
if( zFilename==0 ){
return 0;
}
nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
0, 0);
if( nByte == 0 ){
sqliteFree(zFilename);
zFilename = 0;
}
return zFilename;
}
/*
** Convert multibyte character string to UTF-8. Space to hold the
** returned string is obtained from sqliteMalloc().
*/
static char *mbcsToUtf8(const char *zFilename){
char *zFilenameUtf8;
WCHAR *zTmpWide;
zTmpWide = mbcsToUnicode(zFilename);
if( zTmpWide==0 ){
return 0;
}
zFilenameUtf8 = unicodeToUtf8(zTmpWide);
sqliteFree(zTmpWide);
return zFilenameUtf8;
}
/*
** Convert UTF-8 to multibyte character string. Space to hold the
** returned string is obtained from sqliteMalloc().
*/
static char *utf8ToMbcs(const char *zFilename){
char *zFilenameMbcs;
WCHAR *zTmpWide;
zTmpWide = utf8ToUnicode(zFilename);
if( zTmpWide==0 ){
return 0;
}
zFilenameMbcs = unicodeToMbcs(zTmpWide);
sqliteFree(zTmpWide);
return zFilenameMbcs;
}
#if OS_WINCE #if OS_WINCE
/************************************************************************* /*************************************************************************
** This section contains code for WinCE only. ** This section contains code for WinCE only.
@ -475,6 +559,23 @@ static BOOL winceLockFileEx(
*****************************************************************************/ *****************************************************************************/
#endif /* OS_WINCE */ #endif /* OS_WINCE */
/*
** Convert a UTF-8 filename into whatever form the underlying
** operating system wants filenames in. Space to hold the result
** is obtained from sqliteMalloc and must be freed by the calling
** function.
*/
static void *convertUtf8Filename(const char *zFilename){
void *zConverted = 0;
if( isNT() ){
zConverted = utf8ToUnicode(zFilename);
}else{
zConverted = utf8ToMbcs(zFilename);
}
/* caller will handle out of memory */
return zConverted;
}
/* /*
** Delete the named file. ** Delete the named file.
** **
@ -489,25 +590,30 @@ static BOOL winceLockFileEx(
*/ */
#define MX_DELETION_ATTEMPTS 3 #define MX_DELETION_ATTEMPTS 3
int sqlite3WinDelete(const char *zFilename){ int sqlite3WinDelete(const char *zFilename){
WCHAR *zWide = utf8ToUnicode(zFilename);
int cnt = 0; int cnt = 0;
int rc; int rc;
if( zWide ){ void *zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
if( isNT() ){
do{ do{
rc = DeleteFileW(zWide); rc = DeleteFileW(zConverted);
}while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); }while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff
sqliteFree(zWide); && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
}else{ }else{
#if OS_WINCE #if OS_WINCE
return SQLITE_NOMEM; return SQLITE_NOMEM;
#else #else
do{ do{
rc = DeleteFileA(zFilename); rc = DeleteFileA(zConverted);
}while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); }while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff
&& cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
#endif #endif
} }
sqliteFree(zConverted);
TRACE2("DELETE \"%s\"\n", zFilename); TRACE2("DELETE \"%s\"\n", zFilename);
return rc==0 ? SQLITE_OK : SQLITE_IOERR; return rc!=0 ? SQLITE_OK : SQLITE_IOERR;
} }
/* /*
@ -515,17 +621,20 @@ int sqlite3WinDelete(const char *zFilename){
*/ */
int sqlite3WinFileExists(const char *zFilename){ int sqlite3WinFileExists(const char *zFilename){
int exists = 0; int exists = 0;
WCHAR *zWide = utf8ToUnicode(zFilename); void *zConverted = convertUtf8Filename(zFilename);
if( zWide ){ if( zConverted==0 ){
exists = GetFileAttributesW(zWide) != 0xffffffff; return SQLITE_NOMEM;
sqliteFree(zWide); }
if( isNT() ){
exists = GetFileAttributesW((WCHAR*)zConverted) != 0xffffffff;
}else{ }else{
#if OS_WINCE #if OS_WINCE
return SQLITE_NOMEM; return SQLITE_NOMEM;
#else #else
exists = GetFileAttributesA(zFilename) != 0xffffffff; exists = GetFileAttributesA((char*)zConverted) != 0xffffffff;
#endif #endif
} }
sqliteFree(zConverted);
return exists; return exists;
} }
@ -552,10 +661,14 @@ int sqlite3WinOpenReadWrite(
){ ){
winFile f; winFile f;
HANDLE h; HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename); void *zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
assert( *pId==0 ); assert( *pId==0 );
if( zWide ){
h = CreateFileW(zWide, if( isNT() ){
h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, NULL,
@ -564,7 +677,7 @@ int sqlite3WinOpenReadWrite(
NULL NULL
); );
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
h = CreateFileW(zWide, h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, NULL,
@ -573,7 +686,7 @@ int sqlite3WinOpenReadWrite(
NULL NULL
); );
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
sqliteFree(zWide); sqliteFree(zConverted);
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
*pReadonly = 1; *pReadonly = 1;
@ -583,16 +696,15 @@ int sqlite3WinOpenReadWrite(
#if OS_WINCE #if OS_WINCE
if (!winceCreateLock(zFilename, &f)){ if (!winceCreateLock(zFilename, &f)){
CloseHandle(h); CloseHandle(h);
sqliteFree(zWide); sqliteFree(zConverted);
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
#endif #endif
sqliteFree(zWide);
}else{ }else{
#if OS_WINCE #if OS_WINCE
return SQLITE_NOMEM; return SQLITE_NOMEM;
#else #else
h = CreateFileA(zFilename, h = CreateFileA((char*)zConverted,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, NULL,
@ -601,7 +713,7 @@ int sqlite3WinOpenReadWrite(
NULL NULL
); );
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
h = CreateFileA(zFilename, h = CreateFileA((char*)zConverted,
GENERIC_READ, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, NULL,
@ -610,6 +722,7 @@ int sqlite3WinOpenReadWrite(
NULL NULL
); );
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
sqliteFree(zConverted);
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
*pReadonly = 1; *pReadonly = 1;
@ -618,6 +731,9 @@ int sqlite3WinOpenReadWrite(
} }
#endif /* OS_WINCE */ #endif /* OS_WINCE */
} }
sqliteFree(zConverted);
f.h = h; f.h = h;
#if OS_WINCE #if OS_WINCE
f.zDeleteOnClose = 0; f.zDeleteOnClose = 0;
@ -650,8 +766,11 @@ int sqlite3WinOpenReadWrite(
int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
winFile f; winFile f;
HANDLE h; HANDLE h;
int fileflags; DWORD fileflags;
WCHAR *zWide = utf8ToUnicode(zFilename); void *zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
assert( *pId == 0 ); assert( *pId == 0 );
fileflags = FILE_FLAG_RANDOM_ACCESS; fileflags = FILE_FLAG_RANDOM_ACCESS;
#if !OS_WINCE #if !OS_WINCE
@ -659,10 +778,10 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE; fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
} }
#endif #endif
if( zWide ){ if( isNT() ){
int cnt = 0; int cnt = 0;
do{ do{
h = CreateFileW(zWide, h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
0, 0,
NULL, NULL,
@ -671,14 +790,13 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
NULL NULL
); );
}while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) ); }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
sqliteFree(zWide);
}else{ }else{
#if OS_WINCE #if OS_WINCE
return SQLITE_NOMEM; return SQLITE_NOMEM;
#else #else
int cnt = 0; int cnt = 0;
do{ do{
h = CreateFileA(zFilename, h = CreateFileA((char*)zConverted,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
0, 0,
NULL, NULL,
@ -689,14 +807,18 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
}while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) ); }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
#endif /* OS_WINCE */ #endif /* OS_WINCE */
} }
#if OS_WINCE
if( delFlag && h!=INVALID_HANDLE_VALUE ){
f.zDeleteOnClose = zConverted;
zConverted = 0;
}
f.hMutex = NULL;
#endif
sqliteFree(zConverted);
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
f.h = h; f.h = h;
#if OS_WINCE
f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0;
f.hMutex = NULL;
#endif
TRACE3("OPEN EX %d \"%s\"\n", h, zFilename); TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
return allocateWinFile(&f, pId); return allocateWinFile(&f, pId);
} }
@ -711,10 +833,13 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
winFile f; winFile f;
HANDLE h; HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename); void *zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
assert( *pId==0 ); assert( *pId==0 );
if( zWide ){ if( isNT() ){
h = CreateFileW(zWide, h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ, GENERIC_READ,
0, 0,
NULL, NULL,
@ -722,12 +847,11 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL NULL
); );
sqliteFree(zWide);
}else{ }else{
#if OS_WINCE #if OS_WINCE
return SQLITE_NOMEM; return SQLITE_NOMEM;
#else #else
h = CreateFileA(zFilename, h = CreateFileA((char*)zConverted,
GENERIC_READ, GENERIC_READ,
0, 0,
NULL, NULL,
@ -737,6 +861,7 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
); );
#endif #endif
} }
sqliteFree(zConverted);
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
@ -802,9 +927,21 @@ int sqlite3WinTempFileName(char *zBuf){
strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30); strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
sqliteFree(zMulti); sqliteFree(zMulti);
}else{
return SQLITE_NOMEM;
} }
}else{ }else{
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath); char *zUtf8;
char zMbcsPath[SQLITE_TEMPNAME_SIZE];
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zMbcsPath);
zUtf8 = mbcsToUtf8(zMbcsPath);
if( zUtf8 ){
strncpy(zTempPath, zUtf8, SQLITE_TEMPNAME_SIZE-30);
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
sqliteFree(zUtf8);
}else{
return SQLITE_NOMEM;
}
} }
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0; zTempPath[i] = 0;
@ -864,15 +1001,16 @@ static int winClose(OsFile **pId){
static int winRead(OsFile *id, void *pBuf, int amt){ static int winRead(OsFile *id, void *pBuf, int amt){
DWORD got; DWORD got;
assert( id!=0 ); assert( id!=0 );
SimulateIOError(SQLITE_IOERR); SimulateIOError(return SQLITE_IOERR_READ);
TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){ if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
got = 0; return SQLITE_IOERR_READ;
} }
if( got==(DWORD)amt ){ if( got==(DWORD)amt ){
return SQLITE_OK; return SQLITE_OK;
}else{ }else{
return SQLITE_IOERR; memset(&((char*)pBuf)[got], 0, amt-got);
return SQLITE_IOERR_SHORT_READ;
} }
} }
@ -884,8 +1022,8 @@ static int winWrite(OsFile *id, const void *pBuf, int amt){
int rc = 0; int rc = 0;
DWORD wrote; DWORD wrote;
assert( id!=0 ); assert( id!=0 );
SimulateIOError(SQLITE_IOERR); SimulateIOError(return SQLITE_IOERR_READ);
SimulateDiskfullError; SimulateDiskfullError(return SQLITE_FULL);
TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
assert( amt>0 ); assert( amt>0 );
while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0 while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
@ -915,7 +1053,7 @@ static int winSeek(OsFile *id, i64 offset){
DWORD rc; DWORD rc;
assert( id!=0 ); assert( id!=0 );
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
if( offset ) SimulateDiskfullError if( offset ) SimulateDiskfullError(return SQLITE_FULL);
#endif #endif
SEEK(offset/1024 + 1); SEEK(offset/1024 + 1);
rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN); rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN);
@ -944,7 +1082,7 @@ static int winSync(OsFile *id, int dataOnly){
** than UNIX. ** than UNIX.
*/ */
int sqlite3WinSyncDirectory(const char *zDirname){ int sqlite3WinSyncDirectory(const char *zDirname){
SimulateIOError(SQLITE_IOERR); SimulateIOError(return SQLITE_IOERR_READ);
return SQLITE_OK; return SQLITE_OK;
} }
@ -955,7 +1093,7 @@ static int winTruncate(OsFile *id, i64 nByte){
LONG upperBits = nByte>>32; LONG upperBits = nByte>>32;
assert( id!=0 ); assert( id!=0 );
TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte); TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
SimulateIOError(SQLITE_IOERR); SimulateIOError(return SQLITE_IOERR_TRUNCATE);
SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN); SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
SetEndOfFile(((winFile*)id)->h); SetEndOfFile(((winFile*)id)->h);
return SQLITE_OK; return SQLITE_OK;
@ -967,7 +1105,7 @@ static int winTruncate(OsFile *id, i64 nByte){
static int winFileSize(OsFile *id, i64 *pSize){ static int winFileSize(OsFile *id, i64 *pSize){
DWORD upperBits, lowerBits; DWORD upperBits, lowerBits;
assert( id!=0 ); assert( id!=0 );
SimulateIOError(SQLITE_IOERR); SimulateIOError(return SQLITE_IOERR_FSTAT);
lowerBits = GetFileSize(((winFile*)id)->h, &upperBits); lowerBits = GetFileSize(((winFile*)id)->h, &upperBits);
*pSize = (((i64)upperBits)<<32) + lowerBits; *pSize = (((i64)upperBits)<<32) + lowerBits;
return SQLITE_OK; return SQLITE_OK;
@ -1022,20 +1160,24 @@ static int unlockReadLock(winFile *pFile){
*/ */
int sqlite3WinIsDirWritable(char *zDirname){ int sqlite3WinIsDirWritable(char *zDirname){
int fileAttr; int fileAttr;
WCHAR *zWide; void *zConverted;
if( zDirname==0 ) return 0; if( zDirname==0 ) return 0;
if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0; if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
zWide = utf8ToUnicode(zDirname);
if( zWide ){ zConverted = convertUtf8Filename(zDirname);
fileAttr = GetFileAttributesW(zWide); if( zConverted==0 ){
sqliteFree(zWide); return SQLITE_NOMEM;
}
if( isNT() ){
fileAttr = GetFileAttributesW((WCHAR*)zConverted);
}else{ }else{
#if OS_WINCE #if OS_WINCE
return 0; return 0;
#else #else
fileAttr = GetFileAttributesA(zDirname); fileAttr = GetFileAttributesA((char*)zConverted);
#endif #endif
} }
sqliteFree(zConverted);
if( fileAttr == 0xffffffff ) return 0; if( fileAttr == 0xffffffff ) return 0;
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
return 0; return 0;
@ -1224,7 +1366,7 @@ static int winUnlock(OsFile *id, int locktype){
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
/* This should never happen. We should always be able to /* This should never happen. We should always be able to
** reacquire the read lock */ ** reacquire the read lock */
rc = SQLITE_IOERR; rc = SQLITE_IOERR_UNLOCK;
} }
} }
if( type>=RESERVED_LOCK ){ if( type>=RESERVED_LOCK ){
@ -1258,24 +1400,33 @@ char *sqlite3WinFullPathname(const char *zRelative){
/* WinCE has no concept of a relative pathname, or so I am told. */ /* WinCE has no concept of a relative pathname, or so I am told. */
zFull = sqliteStrDup(zRelative); zFull = sqliteStrDup(zRelative);
#else #else
char *zNotUsed;
WCHAR *zWide;
int nByte; int nByte;
zWide = utf8ToUnicode(zRelative); void *zConverted;
if( zWide ){ zConverted = convertUtf8Filename(zRelative);
WCHAR *zTemp, *zNotUsedW; if( isNT() ){
nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1; WCHAR *zTemp;
nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) ); zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ) return 0; if( zTemp==0 ){
GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW); sqliteFree(zConverted);
sqliteFree(zWide); return 0;
}
GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
sqliteFree(zConverted);
zFull = unicodeToUtf8(zTemp); zFull = unicodeToUtf8(zTemp);
sqliteFree(zTemp); sqliteFree(zTemp);
}else{ }else{
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1; char *zTemp;
zFull = sqliteMalloc( nByte*sizeof(zFull[0]) ); nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
if( zFull==0 ) return 0; zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); if( zTemp==0 ){
sqliteFree(zConverted);
return 0;
}
GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
sqliteFree(zConverted);
zFull = mbcsToUtf8(zTemp);
sqliteFree(zTemp);
} }
#endif #endif
return zFull; return zFull;
@ -1357,6 +1508,45 @@ static int allocateWinFile(winFile *pInit, OsFile **pId){
** with other miscellanous aspects of the operating system interface ** with other miscellanous aspects of the operating system interface
****************************************************************************/ ****************************************************************************/
#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
/*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
void *sqlite3WinDlopen(const char *zFilename){
HANDLE h;
void *zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return 0;
}
if( isNT() ){
h = LoadLibraryW((WCHAR*)zConverted);
}else{
#if OS_WINCE
return 0;
#else
h = LoadLibraryA((char*)zConverted);
#endif
}
sqliteFree(zConverted);
return (void*)h;
}
void *sqlite3WinDlsym(void *pHandle, const char *zSymbol){
#if OS_WINCE
/* The GetProcAddressA() routine is only available on wince. */
return GetProcAddressA((HANDLE)pHandle, zSymbol);
#else
/* All other windows platforms expect GetProcAddress() to take
** an Ansi string regardless of the _UNICODE setting */
return GetProcAddress((HANDLE)pHandle, zSymbol);
#endif
}
int sqlite3WinDlclose(void *pHandle){
return FreeLibrary((HANDLE)pHandle);
}
#endif /* !SQLITE_OMIT_LOAD_EXTENSION */
/* /*
** Get information to seed the random number generator. The seed ** Get information to seed the random number generator. The seed
** is written into the buffer zBuf[256]. The calling function must ** is written into the buffer zBuf[256]. The calling function must

View file

@ -31,6 +31,7 @@
** Macros for troubleshooting. Normally turned off ** Macros for troubleshooting. Normally turned off
*/ */
#if 0 #if 0
#define sqlite3DebugPrintf printf
#define TRACE1(X) sqlite3DebugPrintf(X) #define TRACE1(X) sqlite3DebugPrintf(X)
#define TRACE2(X,Y) sqlite3DebugPrintf(X,Y) #define TRACE2(X,Y) sqlite3DebugPrintf(X,Y)
#define TRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z) #define TRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
@ -231,7 +232,6 @@ struct Pager {
u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 fullSync; /* Do extra syncs of the journal for robustness */
u8 full_fsync; /* Use F_FULLFSYNC when available */ u8 full_fsync; /* Use F_FULLFSYNC when available */
u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
u8 errCode; /* One of several kinds of errors */
u8 tempFile; /* zFilename is a temporary file */ u8 tempFile; /* zFilename is a temporary file */
u8 readOnly; /* True for a read-only database */ u8 readOnly; /* True for a read-only database */
u8 needSync; /* True if an fsync() is needed on the journal */ u8 needSync; /* True if an fsync() is needed on the journal */
@ -239,6 +239,7 @@ struct Pager {
u8 alwaysRollback; /* Disable dont_rollback() for all pages */ u8 alwaysRollback; /* Disable dont_rollback() for all pages */
u8 memDb; /* True to inhibit all file I/O */ u8 memDb; /* True to inhibit all file I/O */
u8 setMaster; /* True if a m-j name has been written to jrnl */ u8 setMaster; /* True if a m-j name has been written to jrnl */
int errCode; /* One of several kinds of errors */
int dbSize; /* Number of pages in the file */ int dbSize; /* Number of pages in the file */
int origDbSize; /* dbSize before the current change */ int origDbSize; /* dbSize before the current change */
int stmtSize; /* Size of database (in pages) at stmt_begin() */ int stmtSize; /* Size of database (in pages) at stmt_begin() */
@ -350,7 +351,9 @@ static const unsigned char aJournalMagic[] = {
/* /*
** The default size of a disk sector ** The default size of a disk sector
*/ */
#ifndef PAGER_SECTOR_SIZE
# define PAGER_SECTOR_SIZE 512 # define PAGER_SECTOR_SIZE 512
#endif
/* /*
** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
@ -376,8 +379,8 @@ static const unsigned char aJournalMagic[] = {
static int cnt = 0; static int cnt = 0;
if( !pager3_refinfo_enable ) return; if( !pager3_refinfo_enable ) return;
sqlite3DebugPrintf( sqlite3DebugPrintf(
"REFCNT: %4d addr=%p nRef=%d\n", "REFCNT: %4d addr=%p nRef=%-3d total=%d\n",
p->pgno, PGHDR_TO_DATA(p), p->nRef p->pgno, PGHDR_TO_DATA(p), p->nRef, p->pPager->nRef
); );
cnt++; /* Something to set a breakpoint on */ cnt++; /* Something to set a breakpoint on */
} }
@ -476,12 +479,13 @@ static u32 retrieve32bits(PgHdr *p, int offset){
** will immediately return the same error code. ** will immediately return the same error code.
*/ */
static int pager_error(Pager *pPager, int rc){ static int pager_error(Pager *pPager, int rc){
int rc2 = rc & 0xff;
assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK ); assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK );
if( if(
rc==SQLITE_FULL || rc2==SQLITE_FULL ||
rc==SQLITE_IOERR || rc2==SQLITE_IOERR ||
rc==SQLITE_CORRUPT || rc2==SQLITE_CORRUPT ||
rc==SQLITE_PROTOCOL rc2==SQLITE_PROTOCOL
){ ){
pPager->errCode = rc; pPager->errCode = rc;
} }
@ -846,6 +850,23 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
return p; return p;
} }
/*
** Unlock the database file.
**
** Once all locks have been removed from the database file, other
** processes or threads might change the file. So make sure all of
** our internal cache is invalidated.
*/
static void pager_unlock(Pager *pPager){
if( !MEMDB ){
sqlite3OsUnlock(pPager->fd, NO_LOCK);
pPager->dbSize = -1;
}
pPager->state = PAGER_UNLOCK;
assert( pPager->pAll==0 );
}
/* /*
** Unlock the database and clear the in-memory cache. This routine ** Unlock the database and clear the in-memory cache. This routine
** sets the state of the pager back to what it was when it was first ** sets the state of the pager back to what it was when it was first
@ -870,11 +891,9 @@ static void pager_reset(Pager *pPager){
if( pPager->state>=PAGER_RESERVED ){ if( pPager->state>=PAGER_RESERVED ){
sqlite3pager_rollback(pPager); sqlite3pager_rollback(pPager);
} }
sqlite3OsUnlock(pPager->fd, NO_LOCK); pager_unlock(pPager);
pPager->state = PAGER_UNLOCK;
pPager->dbSize = -1;
pPager->nRef = 0; pPager->nRef = 0;
assert( pPager->journalOpen==0 ); assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
} }
/* /*
@ -926,6 +945,7 @@ static int pager_unwritelock(Pager *pPager){
pPager->setMaster = 0; pPager->setMaster = 0;
pPager->needSync = 0; pPager->needSync = 0;
pPager->pFirstSynced = pPager->pFirst; pPager->pFirstSynced = pPager->pFirst;
pPager->dbSize = -1;
return rc; return rc;
} }
@ -1340,6 +1360,10 @@ static int pager_playback(Pager *pPager){
pPager->journalOff = szJ; pPager->journalOff = szJ;
break; break;
}else{ }else{
/* If we are unable to rollback a hot journal, then the database
** is probably not recoverable. Return CORRUPT.
*/
rc = SQLITE_CORRUPT;
goto end_playback; goto end_playback;
} }
} }
@ -1416,6 +1440,7 @@ static int pager_stmt_playback(Pager *pPager){
if( pPager->state>=PAGER_EXCLUSIVE ){ if( pPager->state>=PAGER_EXCLUSIVE ){
rc = pager_truncate(pPager, pPager->stmtSize); rc = pager_truncate(pPager, pPager->stmtSize);
} }
assert( pPager->state>=PAGER_SHARED );
pPager->dbSize = pPager->stmtSize; pPager->dbSize = pPager->stmtSize;
/* Figure out how many records are in the statement journal. /* Figure out how many records are in the statement journal.
@ -1793,15 +1818,20 @@ void enable_simulated_io_errors(void){
** response is to zero the memory at pDest and continue. A real IO error ** response is to zero the memory at pDest and continue. A real IO error
** will presumably recur and be picked up later (Todo: Think about this). ** will presumably recur and be picked up later (Todo: Think about this).
*/ */
void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){ int sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
int rc = SQLITE_OK;
memset(pDest, 0, N); memset(pDest, 0, N);
if( MEMDB==0 ){ if( MEMDB==0 ){
disable_simulated_io_errors(); disable_simulated_io_errors();
sqlite3OsSeek(pPager->fd, 0); sqlite3OsSeek(pPager->fd, 0);
sqlite3OsRead(pPager->fd, pDest, N);
enable_simulated_io_errors(); enable_simulated_io_errors();
rc = sqlite3OsRead(pPager->fd, pDest, N);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
} }
} }
return rc;
}
/* /*
** Return the total number of pages in the disk file associated with ** Return the total number of pages in the disk file associated with
@ -1814,12 +1844,13 @@ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
*/ */
int sqlite3pager_pagecount(Pager *pPager){ int sqlite3pager_pagecount(Pager *pPager){
i64 n; i64 n;
int rc;
assert( pPager!=0 ); assert( pPager!=0 );
if( pPager->dbSize>=0 ){ if( pPager->dbSize>=0 ){
n = pPager->dbSize; n = pPager->dbSize;
} else { } else {
if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){ if( (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){
pager_error(pPager, SQLITE_IOERR); pager_error(pPager, rc);
return 0; return 0;
} }
if( n>0 && n<pPager->pageSize ){ if( n>0 && n<pPager->pageSize ){
@ -1959,9 +1990,15 @@ static void memoryTruncate(Pager *pPager){
*/ */
static int pager_wait_on_lock(Pager *pPager, int locktype){ static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc; int rc;
/* The OS lock values must be the same as the Pager lock values */
assert( PAGER_SHARED==SHARED_LOCK ); assert( PAGER_SHARED==SHARED_LOCK );
assert( PAGER_RESERVED==RESERVED_LOCK ); assert( PAGER_RESERVED==RESERVED_LOCK );
assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
/* If the file is currently unlocked then the size must be unknown */
assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 || MEMDB );
if( pPager->state>=locktype ){ if( pPager->state>=locktype ){
rc = SQLITE_OK; rc = SQLITE_OK;
}else{ }else{
@ -1980,6 +2017,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
*/ */
int sqlite3pager_truncate(Pager *pPager, Pgno nPage){ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
int rc; int rc;
assert( pPager->state>=PAGER_SHARED || MEMDB );
sqlite3pager_pagecount(pPager); sqlite3pager_pagecount(pPager);
if( pPager->errCode ){ if( pPager->errCode ){
rc = pPager->errCode; rc = pPager->errCode;
@ -2026,7 +2064,6 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
** to the caller. ** to the caller.
*/ */
int sqlite3pager_close(Pager *pPager){ int sqlite3pager_close(Pager *pPager){
PgHdr *pPg, *pNext;
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to
** malloc() must have already been made by this thread before it gets ** malloc() must have already been made by this thread before it gets
@ -2038,46 +2075,10 @@ int sqlite3pager_close(Pager *pPager){
assert( pTsd && pTsd->nAlloc ); assert( pTsd && pTsd->nAlloc );
#endif #endif
switch( pPager->state ){
case PAGER_RESERVED:
case PAGER_SYNCED:
case PAGER_EXCLUSIVE: {
/* We ignore any IO errors that occur during the rollback
** operation. So disable IO error simulation so that testing
** works more easily.
*/
disable_simulated_io_errors(); disable_simulated_io_errors();
sqlite3pager_rollback(pPager); pPager->errCode = 0;
pager_reset(pPager);
enable_simulated_io_errors(); enable_simulated_io_errors();
if( !MEMDB ){
sqlite3OsUnlock(pPager->fd, NO_LOCK);
}
assert( pPager->errCode || pPager->journalOpen==0 );
break;
}
case PAGER_SHARED: {
if( !MEMDB ){
sqlite3OsUnlock(pPager->fd, NO_LOCK);
}
break;
}
default: {
/* Do nothing */
break;
}
}
for(pPg=pPager->pAll; pPg; pPg=pNext){
#ifndef NDEBUG
if( MEMDB ){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
assert( !pPg->alwaysRollback );
assert( !pHist->pOrig );
assert( !pHist->pStmt );
}
#endif
pNext = pPg->pNextAll;
sqliteFree(pPg);
}
TRACE2("CLOSE %d\n", PAGERID(pPager)); TRACE2("CLOSE %d\n", PAGERID(pPager));
assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) ); assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
if( pPager->journalOpen ){ if( pPager->journalOpen ){
@ -2578,7 +2579,7 @@ int sqlite3pager_release_memory(int nReq){
** The error will be returned to the user (or users, in the case ** The error will be returned to the user (or users, in the case
** of a shared pager cache) of the pager for which the error occured. ** of a shared pager cache) of the pager for which the error occured.
*/ */
assert( rc==SQLITE_IOERR || rc==SQLITE_FULL ); assert( (rc&0xff)==SQLITE_IOERR || rc==SQLITE_FULL );
assert( p->state>=PAGER_RESERVED ); assert( p->state>=PAGER_RESERVED );
pager_error(p, rc); pager_error(p, rc);
} }
@ -2659,8 +2660,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/ */
rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK); rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3OsUnlock(pPager->fd, NO_LOCK); pager_unlock(pPager);
pPager->state = PAGER_UNLOCK;
return pager_error(pPager, rc); return pager_error(pPager, rc);
} }
pPager->state = PAGER_EXCLUSIVE; pPager->state = PAGER_EXCLUSIVE;
@ -2675,8 +2675,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/ */
rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd); rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3OsUnlock(pPager->fd, NO_LOCK); pager_unlock(pPager);
pPager->state = PAGER_UNLOCK;
return SQLITE_BUSY; return SQLITE_BUSY;
} }
pPager->journalOpen = 1; pPager->journalOpen = 1;
@ -2783,19 +2782,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
} }
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno); TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
i64 fileSize;
int rc2 = sqlite3OsFileSize(pPager->fd, &fileSize);
if( rc2!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){
/* An IO error occured in one of the the sqlite3OsSeek() or
** sqlite3OsRead() calls above. */
pPg->pgno = 0; pPg->pgno = 0;
sqlite3pager_unref(PGHDR_TO_DATA(pPg)); sqlite3pager_unref(PGHDR_TO_DATA(pPg));
return rc; return rc;
}else{
clear_simulated_io_error();
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
}
}else{ }else{
TEST_INCR(pPager->nRead); TEST_INCR(pPager->nRead);
} }
@ -2967,8 +2957,7 @@ failed_to_open_journal:
*/ */
sqlite3OsDelete(pPager->zJournal); sqlite3OsDelete(pPager->zJournal);
}else{ }else{
sqlite3OsUnlock(pPager->fd, NO_LOCK); pager_reset(pPager);
pPager->state = PAGER_UNLOCK;
} }
return rc; return rc;
} }
@ -3227,6 +3216,7 @@ int sqlite3pager_write(void *pData){
/* Update the database size and return. /* Update the database size and return.
*/ */
assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSize<(int)pPg->pgno ){ if( pPager->dbSize<(int)pPg->pgno ){
pPager->dbSize = pPg->pgno; pPager->dbSize = pPg->pgno;
if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){ if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
@ -3302,6 +3292,7 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */ assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */
pPg->alwaysRollback = 1; pPg->alwaysRollback = 1;
if( pPg->dirty && !pPager->stmtInUse ){ if( pPg->dirty && !pPager->stmtInUse ){
assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){ if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
/* If this pages is the last page in the file and the file has grown /* If this pages is the last page in the file and the file has grown
** during the current transaction, then do NOT mark the page as clean. ** during the current transaction, then do NOT mark the page as clean.
@ -3331,7 +3322,8 @@ void sqlite3pager_dont_rollback(void *pData){
PgHdr *pPg = DATA_TO_PGHDR(pData); PgHdr *pPg = DATA_TO_PGHDR(pData);
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
if( pPager->state!=PAGER_EXCLUSIVE || pPager->journalOpen==0 ) return; assert( pPager->state>=PAGER_RESERVED );
if( pPager->journalOpen==0 ) return;
if( pPg->alwaysRollback || pPager->alwaysRollback || MEMDB ) return; if( pPg->alwaysRollback || pPager->alwaysRollback || MEMDB ) return;
if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){ if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){
assert( pPager->aInJournal!=0 ); assert( pPager->aInJournal!=0 );
@ -3399,14 +3391,12 @@ int sqlite3pager_commit(Pager *pPager){
** if there have been no changes to the database file. */ ** if there have been no changes to the database file. */
assert( pPager->needSync==0 ); assert( pPager->needSync==0 );
rc = pager_unwritelock(pPager); rc = pager_unwritelock(pPager);
pPager->dbSize = -1;
return rc; return rc;
} }
assert( pPager->journalOpen ); assert( pPager->journalOpen );
rc = sqlite3pager_sync(pPager, 0, 0); rc = sqlite3pager_sync(pPager, 0, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = pager_unwritelock(pPager); rc = pager_unwritelock(pPager);
pPager->dbSize = -1;
} }
return rc; return rc;
} }
@ -3464,7 +3454,6 @@ int sqlite3pager_rollback(Pager *pPager){
if( !pPager->dirtyCache || !pPager->journalOpen ){ if( !pPager->dirtyCache || !pPager->journalOpen ){
rc = pager_unwritelock(pPager); rc = pager_unwritelock(pPager);
pPager->dbSize = -1;
return rc; return rc;
} }
@ -3540,6 +3529,7 @@ int sqlite3pager_stmt_begin(Pager *pPager){
int rc; int rc;
char zTemp[SQLITE_TEMPNAME_SIZE]; char zTemp[SQLITE_TEMPNAME_SIZE];
assert( !pPager->stmtInUse ); assert( !pPager->stmtInUse );
assert( pPager->state>=PAGER_SHARED );
assert( pPager->dbSize>=0 ); assert( pPager->dbSize>=0 );
TRACE2("STMT-BEGIN %d\n", PAGERID(pPager)); TRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
if( MEMDB ){ if( MEMDB ){

View file

@ -75,7 +75,7 @@ void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
void sqlite3pager_set_destructor(Pager*, void(*)(void*,int)); void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int)); void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
int sqlite3pager_set_pagesize(Pager*, int); int sqlite3pager_set_pagesize(Pager*, int);
void sqlite3pager_read_fileheader(Pager*, int, unsigned char*); int sqlite3pager_read_fileheader(Pager*, int, unsigned char*);
void sqlite3pager_set_cachesize(Pager*, int); void sqlite3pager_set_cachesize(Pager*, int);
int sqlite3pager_close(Pager *pPager); int sqlite3pager_close(Pager *pPager);
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage); int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);

File diff suppressed because it is too large Load diff

View file

@ -104,7 +104,7 @@ explain ::= . { sqlite3BeginParse(pParse, 0); }
%ifndef SQLITE_OMIT_EXPLAIN %ifndef SQLITE_OMIT_EXPLAIN
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); } explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); } explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); }
%endif %endif SQLITE_OMIT_EXPLAIN
///////////////////// Begin and end transactions. //////////////////////////// ///////////////////// Begin and end transactions. ////////////////////////////
// //
@ -134,7 +134,7 @@ ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
%type temp {int} %type temp {int}
%ifndef SQLITE_OMIT_TEMPDB %ifndef SQLITE_OMIT_TEMPDB
temp(A) ::= TEMP. {A = 1;} temp(A) ::= TEMP. {A = 1;}
%endif %endif SQLITE_OMIT_TEMPDB
temp(A) ::= . {A = 0;} temp(A) ::= . {A = 0;}
create_table_args ::= LP columnlist conslist_opt(X) RP(Y). { create_table_args ::= LP columnlist conslist_opt(X) RP(Y). {
sqlite3EndTable(pParse,&X,&Y,0); sqlite3EndTable(pParse,&X,&Y,0);
@ -179,7 +179,7 @@ id(A) ::= ID(X). {A = X;}
TEMP TRIGGER VACUUM VIEW VIRTUAL TEMP TRIGGER VACUUM VIEW VIRTUAL
%ifdef SQLITE_OMIT_COMPOUND_SELECT %ifdef SQLITE_OMIT_COMPOUND_SELECT
EXCEPT INTERSECT UNION EXCEPT INTERSECT UNION
%endif %endif SQLITE_OMIT_COMPOUND_SELECT
REINDEX RENAME CTIME_KW IF REINDEX RENAME CTIME_KW IF
. .
%wildcard ANY. %wildcard ANY.
@ -249,14 +249,14 @@ carglist ::= carglist carg.
carglist ::= . carglist ::= .
carg ::= CONSTRAINT nm ccons. carg ::= CONSTRAINT nm ccons.
carg ::= ccons. carg ::= ccons.
carg ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);} ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
carg ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);} ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
carg ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);} ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
carg ::= DEFAULT MINUS term(X). { ccons ::= DEFAULT MINUS term(X). {
Expr *p = sqlite3Expr(TK_UMINUS, X, 0, 0); Expr *p = sqlite3Expr(TK_UMINUS, X, 0, 0);
sqlite3AddDefaultValue(pParse,p); sqlite3AddDefaultValue(pParse,p);
} }
carg ::= DEFAULT id(X). { ccons ::= DEFAULT id(X). {
Expr *p = sqlite3Expr(TK_STRING, 0, 0, &X); Expr *p = sqlite3Expr(TK_STRING, 0, 0, &X);
sqlite3AddDefaultValue(pParse,p); sqlite3AddDefaultValue(pParse,p);
} }
@ -355,13 +355,13 @@ ifexists(A) ::= . {A = 0;}
///////////////////// The CREATE VIEW statement ///////////////////////////// ///////////////////// The CREATE VIEW statement /////////////////////////////
// //
%ifndef SQLITE_OMIT_VIEW %ifndef SQLITE_OMIT_VIEW
cmd ::= CREATE(X) temp(T) VIEW nm(Y) dbnm(Z) AS select(S). { cmd ::= CREATE(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
sqlite3CreateView(pParse, &X, &Y, &Z, S, T); sqlite3CreateView(pParse, &X, &Y, &Z, S, T, E);
} }
cmd ::= DROP VIEW ifexists(E) fullname(X). { cmd ::= DROP VIEW ifexists(E) fullname(X). {
sqlite3DropTable(pParse, X, 1, E); sqlite3DropTable(pParse, X, 1, E);
} }
%endif // SQLITE_OMIT_VIEW %endif SQLITE_OMIT_VIEW
//////////////////////// The SELECT statement ///////////////////////////////// //////////////////////// The SELECT statement /////////////////////////////////
// //
@ -388,7 +388,7 @@ select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
multiselect_op(A) ::= UNION(OP). {A = @OP;} multiselect_op(A) ::= UNION(OP). {A = @OP;}
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;} multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
%endif // SQLITE_OMIT_COMPOUND_SELECT %endif SQLITE_OMIT_COMPOUND_SELECT
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset); A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
@ -444,7 +444,10 @@ as(X) ::= . {X.n = 0;}
// A complete FROM clause. // A complete FROM clause.
// //
from(A) ::= . {A = sqliteMalloc(sizeof(*A));} from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
from(A) ::= FROM seltablist(X). {A = X;} from(A) ::= FROM seltablist(X). {
A = X;
sqlite3SrcListShiftJoinType(A);
}
// "seltablist" is a "Select Table List" - the content of the FROM clause // "seltablist" is a "Select Table List" - the content of the FROM clause
// in a SELECT statement. "stl_prefix" is a prefix of this list. // in a SELECT statement. "stl_prefix" is a prefix of this list.
@ -455,31 +458,12 @@ stl_prefix(A) ::= seltablist(X) joinop(Y). {
} }
stl_prefix(A) ::= . {A = 0;} stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). { seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppend(X,&Y,&D); A = sqlite3SrcListAppendFromTerm(X,&Y,&D,&Z,0,N,U);
if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
if( N ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
else { sqlite3ExprDelete(N); }
}
if( U ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
else { sqlite3IdListDelete(U); }
}
} }
%ifndef SQLITE_OMIT_SUBQUERY %ifndef SQLITE_OMIT_SUBQUERY
seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
as(Z) on_opt(N) using_opt(U). { as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppend(X,0,0); A = sqlite3SrcListAppendFromTerm(X,0,0,&Z,S,N,U);
if( A && A->nSrc>0 ) A->a[A->nSrc-1].pSelect = S;
if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
if( N ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
else { sqlite3ExprDelete(N); }
}
if( U ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
else { sqlite3IdListDelete(U); }
}
} }
// A seltablist_paren nonterminal represents anything in a FROM that // A seltablist_paren nonterminal represents anything in a FROM that
@ -490,9 +474,10 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
%destructor seltablist_paren {sqlite3SelectDelete($$);} %destructor seltablist_paren {sqlite3SelectDelete($$);}
seltablist_paren(A) ::= select(S). {A = S;} seltablist_paren(A) ::= select(S). {A = S;}
seltablist_paren(A) ::= seltablist(F). { seltablist_paren(A) ::= seltablist(F). {
sqlite3SrcListShiftJoinType(F);
A = sqlite3SelectNew(0,F,0,0,0,0,0,0,0); A = sqlite3SelectNew(0,F,0,0,0,0,0,0,0);
} }
%endif // SQLITE_OMIT_SUBQUERY %endif SQLITE_OMIT_SUBQUERY
%type dbnm {Token} %type dbnm {Token}
dbnm(A) ::= . {A.z=0; A.n=0;} dbnm(A) ::= . {A.z=0; A.n=0;}
@ -600,6 +585,8 @@ cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F)
{sqlite3Insert(pParse, X, Y, 0, F, R);} {sqlite3Insert(pParse, X, Y, 0, F, R);}
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S). cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S).
{sqlite3Insert(pParse, X, 0, S, F, R);} {sqlite3Insert(pParse, X, 0, S, F, R);}
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
{sqlite3Insert(pParse, X, 0, 0, F, R);}
%type insert_cmd {int} %type insert_cmd {int}
insert_cmd(A) ::= INSERT orconf(R). {A = R;} insert_cmd(A) ::= INSERT orconf(R). {A = R;}
@ -660,7 +647,7 @@ expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
A = sqlite3Expr(TK_CAST, E, 0, &T); A = sqlite3Expr(TK_CAST, E, 0, &T);
sqlite3ExprSpan(A,&X,&Y); sqlite3ExprSpan(A,&X,&Y);
} }
%endif // SQLITE_OMIT_CAST %endif SQLITE_OMIT_CAST
expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). { expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
A = sqlite3ExprFunction(Y, &X); A = sqlite3ExprFunction(Y, &X);
sqlite3ExprSpan(A,&X,&E); sqlite3ExprSpan(A,&X,&E);
@ -676,7 +663,10 @@ term(A) ::= CTIME_KW(OP). {
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */ ** treated as functions that return constants */
A = sqlite3ExprFunction(0,&OP); A = sqlite3ExprFunction(0,&OP);
if( A ) A->op = TK_CONST_FUNC; if( A ){
A->op = TK_CONST_FUNC;
A->span = OP;
}
} }
expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);} expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);} expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
@ -805,7 +795,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
sqlite3SelectDelete(Y); sqlite3SelectDelete(Y);
} }
} }
%endif // SQLITE_OMIT_SUBQUERY %endif SQLITE_OMIT_SUBQUERY
/* CASE expressions */ /* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
@ -894,21 +884,24 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
///////////////////////////// The VACUUM command ///////////////////////////// ///////////////////////////// The VACUUM command /////////////////////////////
// //
%ifndef SQLITE_OMIT_VACUUM
cmd ::= VACUUM. {sqlite3Vacuum(pParse);} cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);} cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
%endif SQLITE_OMIT_VACUUM
///////////////////////////// The PRAGMA command ///////////////////////////// ///////////////////////////// The PRAGMA command /////////////////////////////
// //
%ifndef SQLITE_OMIT_PRAGMA %ifndef SQLITE_OMIT_PRAGMA
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nm(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);} cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);} cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ plus_num(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). { cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
sqlite3Pragma(pParse,&X,&Z,&Y,1); sqlite3Pragma(pParse,&X,&Z,&Y,1);
} }
cmd ::= PRAGMA nm(X) dbnm(Z) LP nm(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);} cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);} cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
%endif // SQLITE_OMIT_PRAGMA nmnum(A) ::= plus_num(X). {A = X;}
nmnum(A) ::= nm(X). {A = X;}
%endif SQLITE_OMIT_PRAGMA
plus_num(A) ::= plus_opt number(X). {A = X;} plus_num(A) ::= plus_opt number(X). {A = X;}
minus_num(A) ::= MINUS number(X). {A = X;} minus_num(A) ::= MINUS number(X). {A = X;}
number(A) ::= INTEGER|FLOAT(X). {A = X;} number(A) ::= INTEGER|FLOAT(X). {A = X;}
@ -926,10 +919,10 @@ cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
sqlite3FinishTrigger(pParse, S, &all); sqlite3FinishTrigger(pParse, S, &all);
} }
trigger_decl(A) ::= temp(T) TRIGGER nm(B) dbnm(Z) trigger_time(C) trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z)
trigger_event(D) trigger_time(C) trigger_event(D)
ON fullname(E) foreach_clause(F) when_clause(G). { ON fullname(E) foreach_clause(F) when_clause(G). {
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T); sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T, NOERR);
A = (Z.n==0?B:Z); A = (Z.n==0?B:Z);
} }
@ -1004,7 +997,7 @@ expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
sqlite3ExprSpan(A, &X, &Y); sqlite3ExprSpan(A, &X, &Y);
} }
} }
%endif // !SQLITE_OMIT_TRIGGER %endif !SQLITE_OMIT_TRIGGER
%type raisetype {int} %type raisetype {int}
raisetype(A) ::= ROLLBACK. {A = OE_Rollback;} raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
@ -1014,10 +1007,10 @@ raisetype(A) ::= FAIL. {A = OE_Fail;}
//////////////////////// DROP TRIGGER statement ////////////////////////////// //////////////////////// DROP TRIGGER statement //////////////////////////////
%ifndef SQLITE_OMIT_TRIGGER %ifndef SQLITE_OMIT_TRIGGER
cmd ::= DROP TRIGGER fullname(X). { cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
sqlite3DropTrigger(pParse,X); sqlite3DropTrigger(pParse,X,NOERR);
} }
%endif // !SQLITE_OMIT_TRIGGER %endif !SQLITE_OMIT_TRIGGER
//////////////////////// ATTACH DATABASE file AS name ///////////////////////// //////////////////////// ATTACH DATABASE file AS name /////////////////////////
cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). { cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
@ -1040,7 +1033,7 @@ cmd ::= DETACH database_kw_opt expr(D). {
%ifndef SQLITE_OMIT_REINDEX %ifndef SQLITE_OMIT_REINDEX
cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);} cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);}
cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);} cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);}
%endif %endif SQLITE_OMIT_REINDEX
/////////////////////////////////// ANALYZE /////////////////////////////////// /////////////////////////////////// ANALYZE ///////////////////////////////////
%ifndef SQLITE_OMIT_ANALYZE %ifndef SQLITE_OMIT_ANALYZE
@ -1061,7 +1054,7 @@ add_column_fullname ::= fullname(X). {
} }
kwcolumn_opt ::= . kwcolumn_opt ::= .
kwcolumn_opt ::= COLUMNKW. kwcolumn_opt ::= COLUMNKW.
%endif %endif SQLITE_OMIT_ALTERTABLE
//////////////////////// CREATE VIRTUAL TABLE ... ///////////////////////////// //////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
%ifndef SQLITE_OMIT_VIRTUALTABLE %ifndef SQLITE_OMIT_VIRTUALTABLE
@ -1079,4 +1072,4 @@ vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);}
lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);} lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);}
anylist ::= . anylist ::= .
anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);} anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
%endif %endif SQLITE_OMIT_VIRTUALTABLE

View file

@ -482,12 +482,17 @@ void sqlite3Pragma(
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC); sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab); sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){ for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const Token *pDflt;
sqlite3VdbeAddOp(v, OP_Integer, i, 0); sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3VdbeOp3(v, OP_String8, 0, 0,
pCol->zType ? pCol->zType : "", 0); pCol->zType ? pCol->zType : "", 0);
sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0); sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0);
sqlite3ExprCode(pParse, pCol->pDflt); if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){
sqlite3VdbeOp3(v, OP_String8, 0, 0, (char*)pDflt->z, pDflt->n);
}else{
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
}
sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0); sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0);
sqlite3VdbeAddOp(v, OP_Callback, 6, 0); sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
} }
@ -635,9 +640,13 @@ void sqlite3Pragma(
} }
}else }else
#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
#endif
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){ if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
int i, j, addr; int i, j, addr, mxErr;
/* Code that appears at the end of the integrity check. If no error /* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the ** messages have been generated, output OK. Otherwise output the
@ -655,7 +664,16 @@ void sqlite3Pragma(
if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
if( zRight ){
mxErr = atoi(zRight);
if( mxErr<=0 ){
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
}
}
sqlite3VdbeAddOp(v, OP_MemInt, mxErr, 0);
/* Do an integrity check on each database file */ /* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
@ -666,6 +684,9 @@ void sqlite3Pragma(
if( OMIT_TEMPDB && i==1 ) continue; if( OMIT_TEMPDB && i==1 ) continue;
sqlite3CodeVerifySchema(pParse, i); sqlite3CodeVerifySchema(pParse, i);
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
/* Do an integrity check of the B-Tree /* Do an integrity check of the B-Tree
*/ */
@ -680,28 +701,28 @@ void sqlite3Pragma(
cnt++; cnt++;
} }
} }
assert( cnt>0 ); if( cnt==0 ) continue;
sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i); sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i);
sqlite3VdbeAddOp(v, OP_Dup, 0, 1); addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName), sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
P3_DYNAMIC); P3_DYNAMIC);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Concat, 0, 1); sqlite3VdbeAddOp(v, OP_Concat, 0, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0); sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly. /* Make sure all the indices are constructed correctly.
*/ */
sqlite3CodeVerifySchema(pParse, i);
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x); Table *pTab = sqliteHashData(x);
Index *pIdx; Index *pIdx;
int loopTop; int loopTop;
if( pTab->pIndex==0 ) continue; if( pTab->pIndex==0 ) continue;
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1); sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0); loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
@ -709,7 +730,7 @@ void sqlite3Pragma(
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2; int jmp2;
static const VdbeOpList idxErr[] = { static const VdbeOpList idxErr[] = {
{ OP_MemIncr, 1, 0, 0}, { OP_MemIncr, -1, 0, 0},
{ OP_String8, 0, 0, "rowid "}, { OP_String8, 0, 0, "rowid "},
{ OP_Rowid, 1, 0, 0}, { OP_Rowid, 1, 0, 0},
{ OP_String8, 0, 0, " missing from index "}, { OP_String8, 0, 0, " missing from index "},
@ -734,13 +755,16 @@ void sqlite3Pragma(
{ OP_MemLoad, 1, 0, 0}, { OP_MemLoad, 1, 0, 0},
{ OP_MemLoad, 2, 0, 0}, { OP_MemLoad, 2, 0, 0},
{ OP_Eq, 0, 0, 0}, /* 6 */ { OP_Eq, 0, 0, 0}, /* 6 */
{ OP_MemIncr, 1, 0, 0}, { OP_MemIncr, -1, 0, 0},
{ OP_String8, 0, 0, "wrong # of entries in index "}, { OP_String8, 0, 0, "wrong # of entries in index "},
{ OP_String8, 0, 0, 0}, /* 9 */ { OP_String8, 0, 0, 0}, /* 9 */
{ OP_Concat, 0, 0, 0}, { OP_Concat, 0, 0, 0},
{ OP_Callback, 1, 0, 0}, { OP_Callback, 1, 0, 0},
}; };
if( pIdx->tnum==0 ) continue; if( pIdx->tnum==0 ) continue;
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx); addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
sqlite3VdbeChangeP1(v, addr+1, j+2); sqlite3VdbeChangeP1(v, addr+1, j+2);
sqlite3VdbeChangeP2(v, addr+1, addr+4); sqlite3VdbeChangeP2(v, addr+1, addr+4);
@ -752,6 +776,7 @@ void sqlite3Pragma(
} }
} }
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
sqlite3VdbeChangeP1(v, addr+1, mxErr);
sqlite3VdbeJumpHere(v, addr+2); sqlite3VdbeJumpHere(v, addr+2);
}else }else
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@ -889,6 +914,7 @@ void sqlite3Pragma(
sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP2(v, addr, iCookie); sqlite3VdbeChangeP2(v, addr, iCookie);
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, P3_TRANSIENT);
} }
} }
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */ #endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
@ -940,6 +966,22 @@ void sqlite3Pragma(
sqlite3_key(db, zRight, strlen(zRight)); sqlite3_key(db, zRight, strlen(zRight));
}else }else
#endif #endif
#if SQLITE_HAS_CODEC || defined(SQLITE_ENABLE_CEROD)
if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
#if SQLITE_HAS_CODEC
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
extern void sqlite3_activate_see(const char*);
sqlite3_activate_see(&zRight[4]);
}
#endif
#ifdef SQLITE_ENABLE_CEROD
if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
extern void sqlite3_activate_cerod(const char*);
sqlite3_activate_cerod(&zRight[6]);
}
#endif
}
#endif
{} {}

View file

@ -41,28 +41,26 @@ static void corruptSchema(InitData *pData, const char *zExtra){
** argv[0] = name of thing being created ** argv[0] = name of thing being created
** argv[1] = root page number for table or index. 0 for trigger or view. ** argv[1] = root page number for table or index. 0 for trigger or view.
** argv[2] = SQL text for the CREATE statement. ** argv[2] = SQL text for the CREATE statement.
** argv[3] = "1" for temporary files, "0" for main database, "2" or more
** for auxiliary database files.
** **
*/ */
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
InitData *pData = (InitData*)pInit; InitData *pData = (InitData*)pInit;
sqlite3 *db = pData->db; sqlite3 *db = pData->db;
int iDb; int iDb = pData->iDb;
pData->rc = SQLITE_OK; pData->rc = SQLITE_OK;
DbClearProperty(db, iDb, DB_Empty);
if( sqlite3MallocFailed() ){ if( sqlite3MallocFailed() ){
corruptSchema(pData, 0); corruptSchema(pData, 0);
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
assert( argc==4 ); assert( argc==3 );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[1]==0 || argv[3]==0 ){ if( argv[1]==0 ){
corruptSchema(pData, 0); corruptSchema(pData, 0);
return 1; return 1;
} }
iDb = atoi(argv[3]);
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
if( argv[2] && argv[2][0] ){ if( argv[2] && argv[2][0] ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW. /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
@ -125,8 +123,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
int size; int size;
Table *pTab; Table *pTab;
Db *pDb; Db *pDb;
char const *azArg[5]; char const *azArg[4];
char zDbNum[30];
int meta[10]; int meta[10];
InitData initData; InitData initData;
char const *zMasterSchema; char const *zMasterSchema;
@ -177,12 +174,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
azArg[0] = zMasterName; azArg[0] = zMasterName;
azArg[1] = "1"; azArg[1] = "1";
azArg[2] = zMasterSchema; azArg[2] = zMasterSchema;
sprintf(zDbNum, "%d", iDb); azArg[3] = 0;
azArg[3] = zDbNum;
azArg[4] = 0;
initData.db = db; initData.db = db;
initData.iDb = iDb;
initData.pzErrMsg = pzErrMsg; initData.pzErrMsg = pzErrMsg;
rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0); rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
if( rc ){ if( rc ){
sqlite3SafetyOn(db); sqlite3SafetyOn(db);
return initData.rc; return initData.rc;
@ -295,8 +291,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}else{ }else{
char *zSql; char *zSql;
zSql = sqlite3MPrintf( zSql = sqlite3MPrintf(
"SELECT name, rootpage, sql, '%s' FROM '%q'.%s", "SELECT name, rootpage, sql FROM '%q'.%s",
zDbNum, db->aDb[iDb].zName, zMasterName); db->aDb[iDb].zName, zMasterName);
sqlite3SafetyOff(db); sqlite3SafetyOff(db);
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_ABORT ) rc = initData.rc; if( rc==SQLITE_ABORT ) rc = initData.rc;
@ -449,10 +445,11 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
/* /*
** Compile the UTF-8 encoded SQL statement zSql into a statement handle. ** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/ */
int sqlite3_prepare( int sqlite3Prepare(
sqlite3 *db, /* Database handle. */ sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */ const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */ int nBytes, /* Length of zSql in bytes. */
int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */ const char **pzTail /* OUT: End of parsed string */
){ ){
@ -507,7 +504,9 @@ int sqlite3_prepare(
if( sqlite3MallocFailed() ){ if( sqlite3MallocFailed() ){
sParse.rc = SQLITE_NOMEM; sParse.rc = SQLITE_NOMEM;
} }
if( pzTail ) *pzTail = sParse.zTail; if( pzTail ){
*pzTail = sParse.zTail;
}
rc = sParse.rc; rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN #ifndef SQLITE_OMIT_EXPLAIN
@ -532,6 +531,9 @@ int sqlite3_prepare(
rc = SQLITE_MISUSE; rc = SQLITE_MISUSE;
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
if( saveSqlFlag ){
sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql);
}
*ppStmt = (sqlite3_stmt*)sParse.pVdbe; *ppStmt = (sqlite3_stmt*)sParse.pVdbe;
}else if( sParse.pVdbe ){ }else if( sParse.pVdbe ){
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
@ -546,17 +548,78 @@ int sqlite3_prepare(
rc = sqlite3ApiExit(db, rc); rc = sqlite3ApiExit(db, rc);
sqlite3ReleaseThreadData(); sqlite3ReleaseThreadData();
assert( (rc&db->errMask)==rc );
return rc; return rc;
} }
/*
** 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.
*/
int sqlite3Reprepare(Vdbe *p){
int rc;
Vdbe *pNew;
const char *zSql;
sqlite3 *db;
zSql = sqlite3VdbeGetSql(p);
if( zSql==0 ){
return 0;
}
db = sqlite3VdbeDb(p);
rc = sqlite3Prepare(db, zSql, -1, 0, (sqlite3_stmt**)&pNew, 0);
if( rc ){
assert( pNew==0 );
return 0;
}else{
assert( pNew!=0 );
}
sqlite3VdbeSwap(pNew, p);
sqlite3_transfer_bindings((sqlite3_stmt*)pNew, (sqlite3_stmt*)p);
sqlite3VdbeResetStepResult(pNew);
sqlite3VdbeFinalize(pNew);
return 1;
}
/*
** Two versions of the official API. Legacy and new use. In the legacy
** version, the original SQL text is not saved in the prepared statement
** and so if a schema change occurs, SQLITE_SCHEMA is returned by
** sqlite3_step(). In the new version, the original SQL text is retained
** and the statement is automatically recompiled if an schema change
** occurs.
*/
int sqlite3_prepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
return sqlite3Prepare(db,zSql,nBytes,0,ppStmt,pzTail);
}
int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
return sqlite3Prepare(db,zSql,nBytes,1,ppStmt,pzTail);
}
#ifndef SQLITE_OMIT_UTF16 #ifndef SQLITE_OMIT_UTF16
/* /*
** Compile the UTF-16 encoded SQL statement zSql into a statement handle. ** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
*/ */
int sqlite3_prepare16( static int sqlite3Prepare16(
sqlite3 *db, /* Database handle. */ sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-8 encoded SQL statement. */ const void *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */ int nBytes, /* Length of zSql in bytes. */
int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */ const void **pzTail /* OUT: End of parsed string */
){ ){
@ -573,7 +636,7 @@ int sqlite3_prepare16(
} }
zSql8 = sqlite3utf16to8(zSql, nBytes); zSql8 = sqlite3utf16to8(zSql, nBytes);
if( zSql8 ){ if( zSql8 ){
rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8); rc = sqlite3Prepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8);
} }
if( zTail8 && pzTail ){ if( zTail8 && pzTail ){
@ -588,4 +651,32 @@ int sqlite3_prepare16(
sqliteFree(zSql8); sqliteFree(zSql8);
return sqlite3ApiExit(db, rc); return sqlite3ApiExit(db, rc);
} }
/*
** Two versions of the official API. Legacy and new use. In the legacy
** version, the original SQL text is not saved in the prepared statement
** and so if a schema change occurs, SQLITE_SCHEMA is returned by
** sqlite3_step(). In the new version, the original SQL text is retained
** and the statement is automatically recompiled if an schema change
** occurs.
*/
int sqlite3_prepare16(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
){
return sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail);
}
int sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
){
return sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
}
#endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_UTF16 */

View file

@ -857,7 +857,7 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
va_start(ap, zFormat); va_start(ap, zFormat);
base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap); base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap); va_end(ap);
fprintf(stdout,"%d: %s", getpid(), zBuf); fprintf(stdout,"%s", zBuf);
fflush(stdout); fflush(stdout);
} }
#endif #endif

View file

@ -37,7 +37,7 @@
** (Later): Actually, OP_NewRowid does not depend on a good source of ** (Later): Actually, OP_NewRowid does not depend on a good source of
** randomness any more. But we will leave this code in all the same. ** randomness any more. But we will leave this code in all the same.
*/ */
static int randomByte(){ static int randomByte(void){
unsigned char t; unsigned char t;
/* All threads share a single random number generator. /* All threads share a single random number generator.

View file

@ -299,8 +299,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* When the NATURAL keyword is present, add WHERE clause terms for /* When the NATURAL keyword is present, add WHERE clause terms for
** every column that the two tables have in common. ** every column that the two tables have in common.
*/ */
if( pLeft->jointype & JT_NATURAL ){ if( pRight->jointype & JT_NATURAL ){
if( pLeft->pOn || pLeft->pUsing ){ if( pRight->pOn || pRight->pUsing ){
sqlite3ErrorMsg(pParse, "a NATURAL join may not have " sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
"an ON or USING clause", 0); "an ON or USING clause", 0);
return 1; return 1;
@ -318,7 +318,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* Disallow both ON and USING clauses in the same join /* Disallow both ON and USING clauses in the same join
*/ */
if( pLeft->pOn && pLeft->pUsing ){ if( pRight->pOn && pRight->pUsing ){
sqlite3ErrorMsg(pParse, "cannot have both ON and USING " sqlite3ErrorMsg(pParse, "cannot have both ON and USING "
"clauses in the same join"); "clauses in the same join");
return 1; return 1;
@ -327,10 +327,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* Add the ON clause to the end of the WHERE clause, connected by /* Add the ON clause to the end of the WHERE clause, connected by
** an AND operator. ** an AND operator.
*/ */
if( pLeft->pOn ){ if( pRight->pOn ){
setJoinExpr(pLeft->pOn, pRight->iCursor); setJoinExpr(pRight->pOn, pRight->iCursor);
p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn); p->pWhere = sqlite3ExprAnd(p->pWhere, pRight->pOn);
pLeft->pOn = 0; pRight->pOn = 0;
} }
/* Create extra terms on the WHERE clause for each column named /* Create extra terms on the WHERE clause for each column named
@ -340,8 +340,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
** Report an error if any column mentioned in the USING clause is ** Report an error if any column mentioned in the USING clause is
** not contained in both tables to be joined. ** not contained in both tables to be joined.
*/ */
if( pLeft->pUsing ){ if( pRight->pUsing ){
IdList *pList = pLeft->pUsing; IdList *pList = pRight->pUsing;
for(j=0; j<pList->nId; j++){ for(j=0; j<pList->nId; j++){
char *zName = pList->a[j].zName; char *zName = pList->a[j].zName;
if( columnIndex(pLeftTab, zName)<0 || columnIndex(pRightTab, zName)<0 ){ if( columnIndex(pLeftTab, zName)<0 || columnIndex(pRightTab, zName)<0 ){
@ -1069,7 +1069,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
Expr *p, *pR; Expr *p, *pR;
char *zType; char *zType;
char *zName; char *zName;
char *zBasename; int nName;
CollSeq *pColl; CollSeq *pColl;
int cnt; int cnt;
NameContext sNC; NameContext sNC;
@ -1102,17 +1102,15 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
/* Make sure the column name is unique. If the name is not unique, /* Make sure the column name is unique. If the name is not unique,
** append a integer to the name so that it becomes unique. ** append a integer to the name so that it becomes unique.
*/ */
zBasename = zName; nName = strlen(zName);
for(j=cnt=0; j<i; j++){ for(j=cnt=0; j<i; j++){
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){ if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
zName = sqlite3MPrintf("%s:%d", zBasename, ++cnt); zName[nName] = 0;
zName = sqlite3MPrintf("%z:%d", zName, ++cnt);
j = -1; j = -1;
if( zName==0 ) break; if( zName==0 ) break;
} }
} }
if( zBasename!=zName ){
sqliteFree(zBasename);
}
pCol->zName = zName; pCol->zName = zName;
/* Get the typename, type affinity, and collating sequence for the /* Get the typename, type affinity, and collating sequence for the
@ -1309,13 +1307,13 @@ static int prepSelectStmt(Parse *pParse, Select *p){
if( i>0 ){ if( i>0 ){
struct SrcList_item *pLeft = &pTabList->a[i-1]; struct SrcList_item *pLeft = &pTabList->a[i-1];
if( (pLeft->jointype & JT_NATURAL)!=0 && if( (pLeft[1].jointype & JT_NATURAL)!=0 &&
columnIndex(pLeft->pTab, zName)>=0 ){ columnIndex(pLeft->pTab, zName)>=0 ){
/* In a NATURAL join, omit the join columns from the /* In a NATURAL join, omit the join columns from the
** table on the right */ ** table on the right */
continue; continue;
} }
if( sqlite3IdListIndex(pLeft->pUsing, zName)>=0 ){ if( sqlite3IdListIndex(pLeft[1].pUsing, zName)>=0 ){
/* In a join with a USING clause, omit columns in the /* In a join with a USING clause, omit columns in the
** using clause from the table on the right. */ ** using clause from the table on the right. */
continue; continue;
@ -1936,6 +1934,7 @@ static int multiSelect(
} }
sqlite3VdbeChangeP2(v, addr, nCol); sqlite3VdbeChangeP2(v, addr, nCol);
sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO); sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO);
pLoop->addrOpenEphm[i] = -1;
} }
} }
@ -2175,7 +2174,7 @@ static int flattenSubquery(
** **
** which is not at all the same thing. ** which is not at all the same thing.
*/ */
if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){ if( pSubSrc->nSrc>1 && (pSubitem->jointype & JT_OUTER)!=0 ){
return 0; return 0;
} }
@ -2192,8 +2191,7 @@ static int flattenSubquery(
** But the t2.x>0 test will always fail on a NULL row of t2, which ** But the t2.x>0 test will always fail on a NULL row of t2, which
** effectively converts the OUTER JOIN into an INNER JOIN. ** effectively converts the OUTER JOIN into an INNER JOIN.
*/ */
if( iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 if( (pSubitem->jointype & JT_OUTER)!=0 && pSub->pWhere!=0 ){
&& pSub->pWhere!=0 ){
return 0; return 0;
} }
@ -2232,7 +2230,7 @@ static int flattenSubquery(
pSrc->a[i+iFrom] = pSubSrc->a[i]; pSrc->a[i+iFrom] = pSubSrc->a[i];
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
} }
pSrc->a[iFrom+nSubSrc-1].jointype = jointype; pSrc->a[iFrom].jointype = jointype;
} }
/* Now begin substituting subquery result set expressions for /* Now begin substituting subquery result set expressions for
@ -2605,8 +2603,15 @@ int sqlite3SelectResolve(
} }
} }
/* If this is one SELECT of a compound, be sure to resolve names
** in the other SELECTs.
*/
if( p->pPrior ){
return sqlite3SelectResolve(pParse, p->pPrior, pOuterNC);
}else{
return SQLITE_OK; return SQLITE_OK;
} }
}
/* /*
** Reset the aggregate accumulator. ** Reset the aggregate accumulator.
@ -3293,3 +3298,99 @@ select_end:
sqliteFree(sAggInfo.aFunc); sqliteFree(sAggInfo.aFunc);
return rc; return rc;
} }
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
*******************************************************************************
** The following code is used for testing and debugging only. The code
** that follows does not appear in normal builds.
**
** These routines are used to print out the content of all or part of a
** parse structures such as Select or Expr. Such printouts are useful
** for helping to understand what is happening inside the code generator
** during the execution of complex SELECT statements.
**
** These routine are not called anywhere from within the normal
** code base. Then are intended to be called from within the debugger
** or from temporary "printf" statements inserted for debugging.
*/
void sqlite3PrintExpr(Expr *p){
if( p->token.z && p->token.n>0 ){
sqlite3DebugPrintf("(%.*s", p->token.n, p->token.z);
}else{
sqlite3DebugPrintf("(%d", p->op);
}
if( p->pLeft ){
sqlite3DebugPrintf(" ");
sqlite3PrintExpr(p->pLeft);
}
if( p->pRight ){
sqlite3DebugPrintf(" ");
sqlite3PrintExpr(p->pRight);
}
sqlite3DebugPrintf(")");
}
void sqlite3PrintExprList(ExprList *pList){
int i;
for(i=0; i<pList->nExpr; i++){
sqlite3PrintExpr(pList->a[i].pExpr);
if( i<pList->nExpr-1 ){
sqlite3DebugPrintf(", ");
}
}
}
void sqlite3PrintSelect(Select *p, int indent){
sqlite3DebugPrintf("%*sSELECT(%p) ", indent, "", p);
sqlite3PrintExprList(p->pEList);
sqlite3DebugPrintf("\n");
if( p->pSrc ){
char *zPrefix;
int i;
zPrefix = "FROM";
for(i=0; i<p->pSrc->nSrc; i++){
struct SrcList_item *pItem = &p->pSrc->a[i];
sqlite3DebugPrintf("%*s ", indent+6, zPrefix);
zPrefix = "";
if( pItem->pSelect ){
sqlite3DebugPrintf("(\n");
sqlite3PrintSelect(pItem->pSelect, indent+10);
sqlite3DebugPrintf("%*s)", indent+8, "");
}else if( pItem->zName ){
sqlite3DebugPrintf("%s", pItem->zName);
}
if( pItem->pTab ){
sqlite3DebugPrintf("(table: %s)", pItem->pTab->zName);
}
if( pItem->zAlias ){
sqlite3DebugPrintf(" AS %s", pItem->zAlias);
}
if( i<p->pSrc->nSrc-1 ){
sqlite3DebugPrintf(",");
}
sqlite3DebugPrintf("\n");
}
}
if( p->pWhere ){
sqlite3DebugPrintf("%*s WHERE ", indent, "");
sqlite3PrintExpr(p->pWhere);
sqlite3DebugPrintf("\n");
}
if( p->pGroupBy ){
sqlite3DebugPrintf("%*s GROUP BY ", indent, "");
sqlite3PrintExprList(p->pGroupBy);
sqlite3DebugPrintf("\n");
}
if( p->pHaving ){
sqlite3DebugPrintf("%*s HAVING ", indent, "");
sqlite3PrintExpr(p->pHaving);
sqlite3DebugPrintf("\n");
}
if( p->pOrderBy ){
sqlite3DebugPrintf("%*s ORDER BY ", indent, "");
sqlite3PrintExprList(p->pOrderBy);
sqlite3DebugPrintf("\n");
}
}
/* End of the structure debug printing code
*****************************************************************************/
#endif /* defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */

View file

@ -52,9 +52,25 @@
# define stifle_history(X) # define stifle_history(X)
#endif #endif
#if defined(_WIN32) || defined(WIN32)
# include <io.h>
#else
/* Make sure isatty() has a prototype. /* Make sure isatty() has a prototype.
*/ */
extern int isatty(); extern int isatty();
#endif
/*
** If the following flag is set, then command execution stops
** at an error if we are not interactive.
*/
static int bail_on_error = 0;
/*
** Threat stdin as an interactive input if the following variable
** is true. Otherwise, assume stdin is connected to a file or pipe.
*/
static int stdin_is_interactive = 1;
/* /*
** The following is the open SQLite database. We make a pointer ** The following is the open SQLite database. We make a pointer
@ -180,10 +196,7 @@ static char *local_getline(char *zPrompt, FILE *in){
} }
/* /*
** Retrieve a single line of input text. "isatty" is true if text ** Retrieve a single line of input text.
** is coming from a terminal. In that case, we issue a prompt and
** attempt to use "readline" for command-line editing. If "isatty"
** is false, use "local_getline" instead of "readline" and issue no prompt.
** **
** zPrior is a string of prior text retrieved. If not the empty ** zPrior is a string of prior text retrieved. If not the empty
** string, then issue a continuation prompt. ** string, then issue a continuation prompt.
@ -212,6 +225,7 @@ struct previous_mode_data {
int showHeader; int showHeader;
int colWidth[100]; int colWidth[100];
}; };
/* /*
** An pointer to an instance of this structure is passed from ** An pointer to an instance of this structure is passed from
** the main program to the callback. This is used to communicate ** the main program to the callback. This is used to communicate
@ -223,6 +237,7 @@ struct callback_data {
int cnt; /* Number of records displayed so far */ int cnt; /* Number of records displayed so far */
FILE *out; /* Write results here */ FILE *out; /* Write results here */
int mode; /* An output mode setting */ int mode; /* An output mode setting */
int writableSchema; /* True if PRAGMA writable_schema=ON */
int showHeader; /* True to show column names in List or Column mode */ int showHeader; /* True to show column names in List or Column mode */
char *zDestTable; /* Name of destination table when MODE_Insert */ char *zDestTable; /* Name of destination table when MODE_Insert */
char separator[20]; /* Separator character for MODE_List */ char separator[20]; /* Separator character for MODE_List */
@ -235,7 +250,6 @@ struct callback_data {
** .explain ON */ ** .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */ char outfile[FILENAME_MAX]; /* Filename for *out */
const char *zDbFilename; /* name of the database file */ const char *zDbFilename; /* name of the database file */
char *zKey; /* Encryption key */
}; };
/* /*
@ -347,6 +361,29 @@ static void output_html_string(FILE *out, const char *z){
} }
} }
/*
** If a field contains any character identified by a 1 in the following
** array, then the string must be quoted for CSV.
*/
static const char needCsvQuote[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
/* /*
** Output a single term of CSV. Actually, p->separator is used for ** Output a single term of CSV. Actually, p->separator is used for
** the separator, which may or may not be a comma. p->nullvalue is ** the separator, which may or may not be a comma. p->nullvalue is
@ -354,12 +391,27 @@ static void output_html_string(FILE *out, const char *z){
** appear outside of quotes. ** appear outside of quotes.
*/ */
static void output_csv(struct callback_data *p, const char *z, int bSep){ static void output_csv(struct callback_data *p, const char *z, int bSep){
FILE *out = p->out;
if( z==0 ){ if( z==0 ){
fprintf(p->out,"%s",p->nullvalue); fprintf(out,"%s",p->nullvalue);
}else if( isNumber(z, 0) ){
fprintf(p->out,"%s",z);
}else{ }else{
output_c_string(p->out, z); int i;
for(i=0; z[i]; i++){
if( needCsvQuote[((unsigned char*)z)[i]] ){
i = 0;
break;
}
}
if( i==0 ){
putc('"', out);
for(i=0; z[i]; i++){
if( z[i]=='"' ) putc('"', out);
putc(z[i], out);
}
putc('"', out);
}else{
fprintf(out, "%s", z);
}
} }
if( bSep ){ if( bSep ){
fprintf(p->out, p->separator); fprintf(p->out, p->separator);
@ -625,6 +677,9 @@ static char * appendText(char *zIn, char const *zAppend, char quote){
/* /*
** Execute a query statement that has a single result column. Print ** Execute a query statement that has a single result column. Print
** that result column on a line by itself with a semicolon terminator. ** that result column on a line by itself with a semicolon terminator.
**
** This is used, for example, to show the schema of the database by
** querying the SQLITE_MASTER table.
*/ */
static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){ static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
sqlite3_stmt *pSelect; sqlite3_stmt *pSelect;
@ -666,6 +721,19 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
fprintf(p->out, "ANALYZE sqlite_master;\n"); fprintf(p->out, "ANALYZE sqlite_master;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){ }else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0; return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
char *zIns;
if( !p->writableSchema ){
fprintf(p->out, "PRAGMA writable_schema=ON;\n");
p->writableSchema = 1;
}
zIns = sqlite3_mprintf(
"INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
fprintf(p->out, "%s\n", zIns);
sqlite3_free(zIns);
return 0;
}else{ }else{
fprintf(p->out, "%s;\n", zSql); fprintf(p->out, "%s;\n", zSql);
} }
@ -718,15 +786,14 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
rc = run_table_dump_query(p->out, p->db, zSelect); rc = run_table_dump_query(p->out, p->db, zSelect);
} }
if( zSelect ) free(zSelect); if( zSelect ) free(zSelect);
if( rc!=SQLITE_OK ){
return 1;
}
} }
return 0; return 0;
} }
/* /*
** Run zQuery. Update dump_callback() as the callback routine. ** Run zQuery. Use dump_callback() as the callback routine so that
** the contents of the query are output as SQL statements.
**
** If we get a SQLITE_CORRUPT error, rerun the query after appending ** If we get a SQLITE_CORRUPT error, rerun the query after appending
** "ORDER BY rowid DESC" to the end. ** "ORDER BY rowid DESC" to the end.
*/ */
@ -754,6 +821,7 @@ static int run_schema_dump_query(
** Text of a help message ** Text of a help message
*/ */
static char zHelp[] = static char zHelp[] =
".bail ON|OFF Stop after hitting an error. Default OFF\n"
".databases List names and files of attached databases\n" ".databases List names and files of attached databases\n"
".dump ?TABLE? ... Dump the database in an SQL text format\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n"
".echo ON|OFF Turn command echo on or off\n" ".echo ON|OFF Turn command echo on or off\n"
@ -790,7 +858,7 @@ static char zHelp[] =
; ;
/* Forward reference */ /* Forward reference */
static void process_input(struct callback_data *p, FILE *in); static int process_input(struct callback_data *p, FILE *in);
/* /*
** Make sure the database is open. If it is not, then open it. If ** Make sure the database is open. If it is not, then open it. If
@ -850,11 +918,28 @@ static void resolve_backslashes(char *z){
z[j] = 0; z[j] = 0;
} }
/*
** Interpret zArg as a boolean value. Return either 0 or 1.
*/
static int booleanValue(char *zArg){
int val = atoi(zArg);
int j;
for(j=0; zArg[j]; j++){
zArg[j] = tolower(zArg[j]);
}
if( strcmp(zArg,"on")==0 ){
val = 1;
}else if( strcmp(zArg,"yes")==0 ){
val = 1;
}
return val;
}
/* /*
** If an input line begins with "." then invoke this routine to ** If an input line begins with "." then invoke this routine to
** process that line. ** process that line.
** **
** Return 1 to exit and 0 to continue. ** Return 1 on error, 2 to exit, and 0 otherwise.
*/ */
static int do_meta_command(char *zLine, struct callback_data *p){ static int do_meta_command(char *zLine, struct callback_data *p){
int i = 1; int i = 1;
@ -889,6 +974,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( nArg==0 ) return rc; if( nArg==0 ) return rc;
n = strlen(azArg[0]); n = strlen(azArg[0]);
c = azArg[0][0]; c = azArg[0][0];
if( c=='b' && n>1 && strncmp(azArg[0], "bail", n)==0 && nArg>1 ){
bail_on_error = booleanValue(azArg[1]);
}else
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
struct callback_data data; struct callback_data data;
char *zErrMsg = 0; char *zErrMsg = 0;
@ -911,14 +1000,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
char *zErrMsg = 0; char *zErrMsg = 0;
open_db(p); open_db(p);
fprintf(p->out, "BEGIN TRANSACTION;\n"); fprintf(p->out, "BEGIN TRANSACTION;\n");
p->writableSchema = 0;
if( nArg==1 ){ if( nArg==1 ){
run_schema_dump_query(p, run_schema_dump_query(p,
"SELECT name, type, sql FROM sqlite_master " "SELECT name, type, sql FROM sqlite_master "
"WHERE sql NOT NULL AND type=='table'", 0 "WHERE sql NOT NULL AND type=='table'", 0
); );
run_schema_dump_query(p, run_table_dump_query(p->out, p->db,
"SELECT name, type, sql FROM sqlite_master " "SELECT sql FROM sqlite_master "
"WHERE sql NOT NULL AND type!='table' AND type!='meta'", 0 "WHERE sql NOT NULL AND type IN ('index','trigger','view')"
); );
}else{ }else{
int i; int i;
@ -928,13 +1018,19 @@ static int do_meta_command(char *zLine, struct callback_data *p){
"SELECT name, type, sql FROM sqlite_master " "SELECT name, type, sql FROM sqlite_master "
"WHERE tbl_name LIKE shellstatic() AND type=='table'" "WHERE tbl_name LIKE shellstatic() AND type=='table'"
" AND sql NOT NULL", 0); " AND sql NOT NULL", 0);
run_schema_dump_query(p, run_table_dump_query(p->out, p->db,
"SELECT name, type, sql FROM sqlite_master " "SELECT sql FROM sqlite_master "
"WHERE tbl_name LIKE shellstatic() AND type!='table'" "WHERE sql NOT NULL"
" AND type!='meta' AND sql NOT NULL", 0); " AND type IN ('index','trigger','view')"
" AND tbl_name LIKE shellstatic()"
);
zShellStatic = 0; zShellStatic = 0;
} }
} }
if( p->writableSchema ){
fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
p->writableSchema = 0;
}
if( zErrMsg ){ if( zErrMsg ){
fprintf(stderr,"Error: %s\n", zErrMsg); fprintf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg); sqlite3_free(zErrMsg);
@ -944,37 +1040,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}else }else
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){ if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
int j; p->echoOn = booleanValue(azArg[1]);
char *z = azArg[1];
int val = atoi(azArg[1]);
for(j=0; z[j]; j++){
z[j] = tolower((unsigned char)z[j]);
}
if( strcmp(z,"on")==0 ){
val = 1;
}else if( strcmp(z,"yes")==0 ){
val = 1;
}
p->echoOn = val;
}else }else
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
rc = 1; rc = 2;
}else }else
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
int j; int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
static char zOne[] = "1";
char *z = nArg>=2 ? azArg[1] : zOne;
int val = atoi(z);
for(j=0; z[j]; j++){
z[j] = tolower((unsigned char)z[j]);
}
if( strcmp(z,"on")==0 ){
val = 1;
}else if( strcmp(z,"yes")==0 ){
val = 1;
}
if(val == 1) { if(val == 1) {
if(!p->explainPrev.valid) { if(!p->explainPrev.valid) {
p->explainPrev.valid = 1; p->explainPrev.valid = 1;
@ -1005,21 +1079,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
} }
}else }else
if( c=='h' && (strncmp(azArg[0], "header", n)==0 if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
||
strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){ strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
int j; p->showHeader = booleanValue(azArg[1]);
char *z = azArg[1];
int val = atoi(azArg[1]);
for(j=0; z[j]; j++){
z[j] = tolower((unsigned char)z[j]);
}
if( strcmp(z,"on")==0 ){
val = 1;
}else if( strcmp(z,"yes")==0 ){
val = 1;
}
p->showHeader = val;
}else }else
if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
@ -1056,6 +1118,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc ){ if( rc ){
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
nCol = 0; nCol = 0;
rc = 1;
}else{ }else{
nCol = sqlite3_column_count(pStmt); nCol = sqlite3_column_count(pStmt);
} }
@ -1076,7 +1139,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc ){ if( rc ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(pStmt); sqlite3_finalize(pStmt);
return 0; return 1;
} }
in = fopen(zFile, "rb"); in = fopen(zFile, "rb");
if( in==0 ){ if( in==0 ){
@ -1122,6 +1185,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
zCommit = "ROLLBACK"; zCommit = "ROLLBACK";
rc = 1;
break; break;
} }
} }
@ -1167,6 +1231,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
fprintf(stderr, "%s\n", zErrMsg); fprintf(stderr, "%s\n", zErrMsg);
sqlite3_free(zErrMsg); sqlite3_free(zErrMsg);
rc = 1;
} }
}else }else
#endif #endif
@ -1201,7 +1266,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
set_table_name(p, "table"); set_table_name(p, "table");
} }
}else { }else {
fprintf(stderr,"mode should be on of: " fprintf(stderr,"mode should be one of: "
"column csv html insert line list tabs tcl\n"); "column csv html insert line list tabs tcl\n");
} }
}else }else
@ -1238,7 +1303,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}else }else
if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){ if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
rc = 1; rc = 2;
}else }else
if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){ if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
@ -1390,6 +1455,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
} }
printf("\n"); printf("\n");
} }
}else{
rc = 1;
} }
sqlite3_free_table(azResult); sqlite3_free_table(azResult);
}else }else
@ -1469,24 +1536,40 @@ static int _is_command_terminator(const char *zLine){
** is coming from a file or device. A prompt is issued and history ** is coming from a file or device. A prompt is issued and history
** is saved only if input is interactive. An interrupt signal will ** is saved only if input is interactive. An interrupt signal will
** cause this routine to exit immediately, unless input is interactive. ** cause this routine to exit immediately, unless input is interactive.
**
** Return the number of errors.
*/ */
static void process_input(struct callback_data *p, FILE *in){ static int process_input(struct callback_data *p, FILE *in){
char *zLine; char *zLine;
char *zSql = 0; char *zSql = 0;
int nSql = 0; int nSql = 0;
char *zErrMsg; char *zErrMsg;
int rc; int rc;
while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){ int errCnt = 0;
int lineno = 0;
int startline = 0;
while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
fflush(p->out);
zLine = one_input_line(zSql, in);
if( zLine==0 ){
break; /* We have reached EOF */
}
if( seenInterrupt ){ if( seenInterrupt ){
if( in!=0 ) break; if( in!=0 ) break;
seenInterrupt = 0; seenInterrupt = 0;
} }
lineno++;
if( p->echoOn ) printf("%s\n", zLine); if( p->echoOn ) printf("%s\n", zLine);
if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue; if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
if( zLine && zLine[0]=='.' && nSql==0 ){ if( zLine && zLine[0]=='.' && nSql==0 ){
int rc = do_meta_command(zLine, p); rc = do_meta_command(zLine, p);
free(zLine); free(zLine);
if( rc ) break; if( rc==2 ){
break;
}else if( rc ){
errCnt++;
}
continue; continue;
} }
if( _is_command_terminator(zLine) ){ if( _is_command_terminator(zLine) ){
@ -1503,6 +1586,7 @@ static void process_input(struct callback_data *p, FILE *in){
exit(1); exit(1);
} }
strcpy(zSql, zLine); strcpy(zSql, zLine);
startline = lineno;
} }
}else{ }else{
int len = strlen(zLine); int len = strlen(zLine);
@ -1521,14 +1605,20 @@ static void process_input(struct callback_data *p, FILE *in){
open_db(p); open_db(p);
rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg); rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
if( rc || zErrMsg ){ if( rc || zErrMsg ){
/* if( in!=0 && !p->echoOn ) printf("%s\n",zSql); */ char zPrefix[100];
if( in!=0 || !stdin_is_interactive ){
sprintf(zPrefix, "SQL error near line %d:", startline);
}else{
sprintf(zPrefix, "SQL error:");
}
if( zErrMsg!=0 ){ if( zErrMsg!=0 ){
printf("SQL error: %s\n", zErrMsg); printf("%s %s\n", zPrefix, zErrMsg);
sqlite3_free(zErrMsg); sqlite3_free(zErrMsg);
zErrMsg = 0; zErrMsg = 0;
}else{ }else{
printf("SQL error: %s\n", sqlite3_errmsg(p->db)); printf("%s %s\n", zPrefix, sqlite3_errmsg(p->db));
} }
errCnt++;
} }
free(zSql); free(zSql);
zSql = 0; zSql = 0;
@ -1539,6 +1629,7 @@ static void process_input(struct callback_data *p, FILE *in){
if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql); if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
free(zSql); free(zSql);
} }
return errCnt;
} }
/* /*
@ -1563,16 +1654,30 @@ static char *find_home_dir(void){
home_dir = getcwd(home_path, _MAX_PATH); home_dir = getcwd(home_path, _MAX_PATH);
#endif #endif
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
if (!home_dir) {
home_dir = getenv("USERPROFILE");
}
#endif
if (!home_dir) { if (!home_dir) {
home_dir = getenv("HOME"); home_dir = getenv("HOME");
if (!home_dir) {
home_dir = getenv("HOMEPATH"); /* Windows? */
}
} }
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__) #if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
if (!home_dir) { if (!home_dir) {
home_dir = "c:"; char *zDrive, *zPath;
int n;
zDrive = getenv("HOMEDRIVE");
zPath = getenv("HOMEPATH");
if( zDrive && zPath ){
n = strlen(zDrive) + strlen(zPath) + 1;
home_dir = malloc( n );
if( home_dir==0 ) return 0;
sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
return home_dir;
}
home_dir = "c:\\";
} }
#endif #endif
@ -1615,7 +1720,7 @@ static void process_sqliterc(
} }
in = fopen(sqliterc,"rb"); in = fopen(sqliterc,"rb");
if( in ){ if( in ){
if( isatty(fileno(stdout)) ){ if( stdin_is_interactive ){
printf("Loading resources from %s\n",sqliterc); printf("Loading resources from %s\n",sqliterc);
} }
process_input(p,in); process_input(p,in);
@ -1632,19 +1737,25 @@ static const char zOptions[] =
" -init filename read/process named file\n" " -init filename read/process named file\n"
" -echo print commands before execution\n" " -echo print commands before execution\n"
" -[no]header turn headers on or off\n" " -[no]header turn headers on or off\n"
" -bail stop after hitting an error\n"
" -interactive force interactive I/O\n"
" -batch force batch I/O\n"
" -column set output mode to 'column'\n" " -column set output mode to 'column'\n"
" -csv set output mode to 'csv'\n"
" -html set output mode to HTML\n" " -html set output mode to HTML\n"
" -line set output mode to 'line'\n" " -line set output mode to 'line'\n"
" -list set output mode to 'list'\n" " -list set output mode to 'list'\n"
" -separator 'x' set output field separator (|)\n" " -separator 'x' set output field separator (|)\n"
" -nullvalue 'text' set text string for NULL values\n" " -nullvalue 'text' set text string for NULL values\n"
" -version show SQLite version\n" " -version show SQLite version\n"
" -help show this text, also show dot-commands\n"
; ;
static void usage(int showDetail){ static void usage(int showDetail){
fprintf(stderr, "Usage: %s [OPTIONS] FILENAME [SQL]\n", Argv0); fprintf(stderr,
"Usage: %s [OPTIONS] FILENAME [SQL]\n"
"FILENAME is the name of an SQLite database. A new database is created\n"
"if the file does not previously exist.\n", Argv0);
if( showDetail ){ if( showDetail ){
fprintf(stderr, "Options are:\n%s", zOptions); fprintf(stderr, "OPTIONS include:\n%s", zOptions);
}else{ }else{
fprintf(stderr, "Use the -help option for additional information\n"); fprintf(stderr, "Use the -help option for additional information\n");
} }
@ -1669,6 +1780,7 @@ int main(int argc, char **argv){
const char *zInitFile = 0; const char *zInitFile = 0;
char *zFirstCmd = 0; char *zFirstCmd = 0;
int i; int i;
int rc = 0;
#ifdef __MACOS__ #ifdef __MACOS__
argc = ccommand(&argv); argc = ccommand(&argv);
@ -1676,6 +1788,7 @@ int main(int argc, char **argv){
Argv0 = argv[0]; Argv0 = argv[0];
main_init(&data); main_init(&data);
stdin_is_interactive = isatty(0);
/* Make sure we have a valid signal handler early, before anything /* Make sure we have a valid signal handler early, before anything
** else is done. ** else is done.
@ -1689,15 +1802,15 @@ int main(int argc, char **argv){
** and the first command to execute. ** and the first command to execute.
*/ */
for(i=1; i<argc-1; i++){ for(i=1; i<argc-1; i++){
char *z;
if( argv[i][0]!='-' ) break; if( argv[i][0]!='-' ) break;
z = argv[i];
if( z[0]=='-' && z[1]=='-' ) z++;
if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){ if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
i++; i++;
}else if( strcmp(argv[i],"-init")==0 ){ }else if( strcmp(argv[i],"-init")==0 ){
i++; i++;
zInitFile = argv[i]; zInitFile = argv[i];
}else if( strcmp(argv[i],"-key")==0 ){
i++;
data.zKey = sqlite3_mprintf("%s",argv[i]);
} }
} }
if( i<argc ){ if( i<argc ){
@ -1743,7 +1856,8 @@ int main(int argc, char **argv){
*/ */
for(i=1; i<argc && argv[i][0]=='-'; i++){ for(i=1; i<argc && argv[i][0]=='-'; i++){
char *z = argv[i]; char *z = argv[i];
if( strcmp(z,"-init")==0 || strcmp(z,"-key")==0 ){ if( z[1]=='-' ){ z++; }
if( strcmp(z,"-init")==0 ){
i++; i++;
}else if( strcmp(z,"-html")==0 ){ }else if( strcmp(z,"-html")==0 ){
data.mode = MODE_Html; data.mode = MODE_Html;
@ -1753,6 +1867,9 @@ int main(int argc, char **argv){
data.mode = MODE_Line; data.mode = MODE_Line;
}else if( strcmp(z,"-column")==0 ){ }else if( strcmp(z,"-column")==0 ){
data.mode = MODE_Column; data.mode = MODE_Column;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
strcpy(data.separator,",");
}else if( strcmp(z,"-separator")==0 ){ }else if( strcmp(z,"-separator")==0 ){
i++; i++;
sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]); sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
@ -1765,10 +1882,16 @@ int main(int argc, char **argv){
data.showHeader = 0; data.showHeader = 0;
}else if( strcmp(z,"-echo")==0 ){ }else if( strcmp(z,"-echo")==0 ){
data.echoOn = 1; data.echoOn = 1;
}else if( strcmp(z,"-bail")==0 ){
bail_on_error = 1;
}else if( strcmp(z,"-version")==0 ){ }else if( strcmp(z,"-version")==0 ){
printf("%s\n", sqlite3_libversion()); printf("%s\n", sqlite3_libversion());
return 0; return 0;
}else if( strcmp(z,"-help")==0 ){ }else if( strcmp(z,"-interactive")==0 ){
stdin_is_interactive = 1;
}else if( strcmp(z,"-batch")==0 ){
stdin_is_interactive = 0;
}else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
usage(1); usage(1);
}else{ }else{
fprintf(stderr,"%s: unknown option: %s\n", Argv0, z); fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
@ -1795,7 +1918,7 @@ int main(int argc, char **argv){
}else{ }else{
/* Run commands received from standard input /* Run commands received from standard input
*/ */
if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){ if( stdin_is_interactive ){
char *zHome; char *zHome;
char *zHistory = 0; char *zHistory = 0;
printf( printf(
@ -1810,7 +1933,7 @@ int main(int argc, char **argv){
#if defined(HAVE_READLINE) && HAVE_READLINE==1 #if defined(HAVE_READLINE) && HAVE_READLINE==1
if( zHistory ) read_history(zHistory); if( zHistory ) read_history(zHistory);
#endif #endif
process_input(&data, 0); rc = process_input(&data, 0);
if( zHistory ){ if( zHistory ){
stifle_history(100); stifle_history(100);
write_history(zHistory); write_history(zHistory);
@ -1818,7 +1941,7 @@ int main(int argc, char **argv){
} }
free(zHome); free(zHome);
}else{ }else{
process_input(&data, stdin); rc = process_input(&data, stdin);
} }
} }
set_table_name(&data, 0); set_table_name(&data, 0);
@ -1827,5 +1950,5 @@ int main(int argc, char **argv){
fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db)); fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
} }
} }
return 0; return rc;
} }

View file

@ -125,7 +125,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** value then the query is aborted, all subsequent SQL statements ** value then the query is aborted, all subsequent SQL statements
** are skipped and the sqlite3_exec() function returns the SQLITE_ABORT. ** are skipped and the sqlite3_exec() function returns the SQLITE_ABORT.
** **
** The 4th parameter is an arbitrary pointer that is passed ** The 1st parameter is an arbitrary pointer that is passed
** to the callback function as its first parameter. ** to the callback function as its first parameter.
** **
** The 2nd parameter to the callback function is the number of ** The 2nd parameter to the callback function is the number of
@ -198,6 +198,44 @@ int sqlite3_exec(
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */ /* end-of-error-codes */
/*
** Using the sqlite3_extended_result_codes() API, you can cause
** SQLite to return result codes with additional information in
** their upper bits. The lower 8 bits will be the same as the
** primary result codes above. But the upper bits might contain
** more specific error information.
**
** To extract the primary result code from an extended result code,
** simply mask off the lower 8 bits.
**
** primary = extended & 0xff;
**
** New result error codes may be added from time to time. Software
** that uses the extended result codes should plan accordingly and be
** sure to always handle new unknown codes gracefully.
**
** The SQLITE_OK result code will never be extended. It will always
** be exactly zero.
**
** The extended result codes always have the primary result code
** as a prefix. Primary result codes only contain a single "_"
** character. Extended result codes contain two or more "_" characters.
*/
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))
#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))
#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))
/*
** Enable or disable the extended result codes.
*/
int sqlite3_extended_result_codes(sqlite3*, int onoff);
/* /*
** Each entry in an SQLite table has a unique integer key. (The key is ** Each entry in an SQLite table has a unique integer key. (The key is
** the value of the INTEGER PRIMARY KEY column if there is such a column, ** the value of the INTEGER PRIMARY KEY column if there is such a column,
@ -277,13 +315,30 @@ int sqlite3_complete16(const void *sql);
** currently locked by another process or thread. If the busy callback ** currently locked by another process or thread. If the busy callback
** is NULL, then sqlite3_exec() returns SQLITE_BUSY immediately if ** is NULL, then sqlite3_exec() returns SQLITE_BUSY immediately if
** it finds a locked table. If the busy callback is not NULL, then ** it finds a locked table. If the busy callback is not NULL, then
** sqlite3_exec() invokes the callback with three arguments. The ** sqlite3_exec() invokes the callback with two arguments. The
** second argument is the name of the locked table and the third ** first argument to the handler is a copy of the void* pointer which
** argument is the number of times the table has been busy. If the ** is the third argument to this routine. The second argument to
** the handler is the number of times that the busy handler has
** been invoked for this locking event. If the
** busy callback returns 0, then sqlite3_exec() immediately returns ** busy callback returns 0, then sqlite3_exec() immediately returns
** SQLITE_BUSY. If the callback returns non-zero, then sqlite3_exec() ** SQLITE_BUSY. If the callback returns non-zero, then sqlite3_exec()
** tries to open the table again and the cycle repeats. ** tries to open the table again and the cycle repeats.
** **
** The presence of a busy handler does not guarantee that
** it will be invoked when there is lock contention.
** If SQLite determines that invoking the busy handler could result in
** a deadlock, it will return SQLITE_BUSY instead.
** Consider a scenario where one process is holding a read lock that
** it is trying to promote to a reserved lock and
** a second process is holding a reserved lock that it is trying
** to promote to an exclusive lock. The first process cannot proceed
** because it is blocked by the second and the second process cannot
** proceed because it is blocked by the first. If both processes
** invoke the busy handlers, neither will make any progress. Therefore,
** SQLite returns SQLITE_BUSY for the first process, hoping that this
** will induce the first process to release its read lock and allow
** the second process to proceed.
**
** The default busy callback is NULL. ** The default busy callback is NULL.
** **
** Sqlite is re-entrant, so the busy handler may start a new query. ** Sqlite is re-entrant, so the busy handler may start a new query.
@ -478,6 +533,7 @@ int sqlite3_set_authorizer(
#define SQLITE_ANALYZE 28 /* Table Name NULL */ #define SQLITE_ANALYZE 28 /* Table Name NULL */
#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */
#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */
#define SQLITE_FUNCTION 31 /* Function Name NULL */
/* /*
** The return value of the authorization function should be one of the ** The return value of the authorization function should be one of the
@ -653,6 +709,31 @@ int sqlite3_prepare16(
const void **pzTail /* OUT: Pointer to unused portion of zSql */ const void **pzTail /* OUT: Pointer to unused portion of zSql */
); );
/*
** Newer versions of the prepare API work just like the legacy versions
** but with one exception: The a copy of the SQL text is saved in the
** sqlite3_stmt structure that is returned. If this copy exists, it
** modifieds the behavior of sqlite3_step() slightly. First, sqlite3_step()
** will no longer return an SQLITE_SCHEMA error but will instead automatically
** rerun the compiler to rebuild the prepared statement. Secondly,
** sqlite3_step() now turns a full result code - the result code that
** use used to have to call sqlite3_reset() to get.
*/
int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
int sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
/* /*
** Pointers to the following two opaque structures are used to communicate ** Pointers to the following two opaque structures are used to communicate
** with the implementations of user-defined functions. ** with the implementations of user-defined functions.
@ -1104,9 +1185,13 @@ void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
** SQLITE_TRANSIENT value means that the content will likely change in ** SQLITE_TRANSIENT value means that the content will likely change in
** the near future and that SQLite should make its own private copy of ** the near future and that SQLite should make its own private copy of
** the content before returning. ** the content before returning.
**
** The typedef is necessary to work around problems in certain
** C++ compilers. See ticket #2191.
*/ */
#define SQLITE_STATIC ((void(*)(void *))0) typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_TRANSIENT ((void(*)(void *))-1) #define SQLITE_STATIC ((sqlite3_destructor_type)0)
#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
/* /*
** User-defined functions invoke the following routines in order to ** User-defined functions invoke the following routines in order to
@ -1517,6 +1602,42 @@ int sqlite3_load_extension(
*/ */
int sqlite3_enable_load_extension(sqlite3 *db, int onoff); int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
****** EXPERIMENTAL - subject to change without notice **************
**
** Register an extension entry point that is automatically invoked
** whenever a new database connection is opened.
**
** This API can be invoked at program startup in order to register
** one or more statically linked extensions that will be available
** to all new database connections.
**
** Duplicate extensions are detected so calling this routine multiple
** times with the same extension is harmless.
**
** This routine stores a pointer to the extension in an array
** that is obtained from malloc(). If you run a memory leak
** checker on your program and it reports a leak because of this
** array, then invoke sqlite3_automatic_extension_reset() prior
** to shutdown to free the memory.
**
** Automatic extensions apply across all threads.
*/
int sqlite3_auto_extension(void *xEntryPoint);
/*
****** EXPERIMENTAL - subject to change without notice **************
**
** Disable all previously registered automatic extensions. This
** routine undoes the effect of all prior sqlite3_automatic_extension()
** calls.
**
** This call disabled automatic extensions in all threads.
*/
void sqlite3_reset_auto_extension(void);
/* /*
****** EXPERIMENTAL - subject to change without notice ************** ****** EXPERIMENTAL - subject to change without notice **************
** **
@ -1544,11 +1665,11 @@ typedef struct sqlite3_module sqlite3_module;
struct sqlite3_module { struct sqlite3_module {
int iVersion; int iVersion;
int (*xCreate)(sqlite3*, void *pAux, int (*xCreate)(sqlite3*, void *pAux,
int argc, char **argv, int argc, const char *const*argv,
sqlite3_vtab **ppVTab); sqlite3_vtab **ppVTab, char**);
int (*xConnect)(sqlite3*, void *pAux, int (*xConnect)(sqlite3*, void *pAux,
int argc, char **argv, int argc, const char *const*argv,
sqlite3_vtab **ppVTab); sqlite3_vtab **ppVTab, char**);
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
int (*xDisconnect)(sqlite3_vtab *pVTab); int (*xDisconnect)(sqlite3_vtab *pVTab);
int (*xDestroy)(sqlite3_vtab *pVTab); int (*xDestroy)(sqlite3_vtab *pVTab);
@ -1668,10 +1789,21 @@ int sqlite3_create_module(
** be taylored to the specific needs of the module implementation. The ** be taylored to the specific needs of the module implementation. The
** purpose of this superclass is to define certain fields that are common ** purpose of this superclass is to define certain fields that are common
** to all module implementations. ** to all module implementations.
**
** Virtual tables methods can set an error message by assigning a
** string obtained from sqlite3_mprintf() to zErrMsg. The method should
** take care that any prior string is freed by a call to sqlite3_free()
** prior to assigning a new string to zErrMsg. After the error message
** is delivered up to the client application, the string will be automatically
** freed by sqlite3_free() and the zErrMsg field will be zeroed. Note
** that sqlite3_mprintf() and sqlite3_free() are used on the zErrMsg field
** since virtual tables are commonly implemented in loadable extensions which
** do not have access to sqlite3MPrintf() or sqlite3Free().
*/ */
struct sqlite3_vtab { struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */ const sqlite3_module *pModule; /* The module for this virtual table */
int nRef; /* Used internally */ int nRef; /* Used internally */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */ /* Virtual table implementations will typically add additional fields */
}; };
@ -1696,6 +1828,24 @@ struct sqlite3_vtab_cursor {
*/ */
int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable); int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);
/*
** Virtual tables can provide alternative implementations of functions
** using the xFindFunction method. But global versions of those functions
** must exist in order to be overloaded.
**
** This API makes sure a global version of a function with a particular
** name and number of parameters exists. If no such function exists
** before this API is called, a new function is created. The implementation
** of the new function always causes an exception to be thrown. So
** the new function is not good for anything by itself. Its only
** purpose is to be a place-holder function that can be overloaded
** by virtual tables.
**
** This API should be considered part of the virtual table interface,
** which is experimental and subject to change.
*/
int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/* /*
** The interface to the virtual-table mechanism defined above (back up ** The interface to the virtual-table mechanism defined above (back up
** to a comment remarkably similar to this one) is currently considered ** to a comment remarkably similar to this one) is currently considered

View file

@ -19,7 +19,7 @@
*/ */
#ifndef _SQLITE3EXT_H_ #ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_ #define _SQLITE3EXT_H_
#include <sqlite3.h> #include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines; typedef struct sqlite3_api_routines sqlite3_api_routines;
@ -92,7 +92,7 @@ struct sqlite3_api_routines {
void * (*get_auxdata)(sqlite3_context*,int); void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void); int (*global_recover)(void);
void (*interrupt)(sqlite3*); void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*); sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void); const char * (*libversion)(void);
int (*libversion_number)(void); int (*libversion_number)(void);
@ -143,6 +143,7 @@ struct sqlite3_api_routines {
const void * (*value_text16le)(sqlite3_value*); const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*); int (*value_type)(sqlite3_value*);
char * (*vmprintf)(const char*,va_list); char * (*vmprintf)(const char*,va_list);
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
}; };
/* /*
@ -221,7 +222,7 @@ struct sqlite3_api_routines {
#define sqlite3_get_auxdata sqlite3_api->get_auxdata #define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table #define sqlite3_get_table sqlite3_api->get_table
#define sqlite3_global_recover sqlite3_api->global_recover #define sqlite3_global_recover sqlite3_api->global_recover
#define sqlite3_interrupt sqlite3_api->interrupt #define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid #define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion #define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number #define sqlite3_libversion_number sqlite3_api->libversion_number
@ -272,6 +273,7 @@ struct sqlite3_api_routines {
#define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type #define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf #define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#endif /* SQLITE_CORE */ #endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api; #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api;

View file

@ -447,6 +447,7 @@ struct sqlite3 {
Db *aDb; /* All backends */ Db *aDb; /* All backends */
int flags; /* Miscellanous flags. See below */ int flags; /* Miscellanous flags. See below */
int errCode; /* Most recent error code (SQLITE_*) */ int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
u8 autoCommit; /* The auto-commit flag. */ u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */ u8 temp_store; /* 1: file 2: memory 0: default */
int nTable; /* Number of tables in the database */ int nTable; /* Number of tables in the database */
@ -462,7 +463,7 @@ struct sqlite3 {
u8 busy; /* TRUE if currently initializing */ u8 busy; /* TRUE if currently initializing */
} init; } init;
int nExtension; /* Number of loaded extensions */ int nExtension; /* Number of loaded extensions */
void *aExtension; /* Array of shared libraray handles */ void **aExtension; /* Array of shared libraray handles */
struct Vdbe *pVdbe; /* List of active virtual machines */ struct Vdbe *pVdbe; /* List of active virtual machines */
int activeVdbeCnt; /* Number of vdbes currently executing */ int activeVdbeCnt; /* Number of vdbes currently executing */
void (*xTrace)(void*,const char*); /* Trace function */ void (*xTrace)(void*,const char*); /* Trace function */
@ -1090,6 +1091,11 @@ typedef unsigned int Bitmask;
** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL, ** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
** such a table must be a simple name: ID. But in SQLite, the table can ** such a table must be a simple name: ID. But in SQLite, the table can
** now be identified by a database name, a dot, then the table name: ID.ID. ** now be identified by a database name, a dot, then the table name: ID.ID.
**
** The jointype starts out showing the join type between the current table
** and the next table on the list. The parser builds the list this way.
** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
** jointype expresses the join between the table and the previous table.
*/ */
struct SrcList { struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */ i16 nSrc; /* Number of tables or subqueries in the FROM clause */
@ -1101,7 +1107,7 @@ struct SrcList {
Table *pTab; /* An SQL table corresponding to zName */ Table *pTab; /* An SQL table corresponding to zName */
Select *pSelect; /* A SELECT statement used in place of a table name */ Select *pSelect; /* A SELECT statement used in place of a table name */
u8 isPopulated; /* Temporary table associated with SELECT is populated */ u8 isPopulated; /* Temporary table associated with SELECT is populated */
u8 jointype; /* Type of join between this table and the next */ u8 jointype; /* Type of join between this able and the previous */
i16 iCursor; /* The VDBE cursor number used to access this table */ i16 iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */ Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */ IdList *pUsing; /* The USING clause of a join */
@ -1512,6 +1518,7 @@ struct DbFixer {
*/ */
typedef struct { typedef struct {
sqlite3 *db; /* The database being initialized */ sqlite3 *db; /* The database being initialized */
int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
char **pzErrMsg; /* Error message stored here */ char **pzErrMsg; /* Error message stored here */
int rc; /* Result code stored here */ int rc; /* Result code stored here */
} InitData; } InitData;
@ -1600,7 +1607,7 @@ void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, const char*, int); void sqlite3AddCollateType(Parse*, const char*, int);
void sqlite3EndTable(Parse*,Token*,Token*,Select*); void sqlite3EndTable(Parse*,Token*,Token*,Select*);
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int); void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
int sqlite3ViewGetColumnNames(Parse*,Table*); int sqlite3ViewGetColumnNames(Parse*,Table*);
@ -1615,7 +1622,9 @@ int sqlite3ArrayAllocate(void**,int,int);
IdList *sqlite3IdListAppend(IdList*, Token*); IdList *sqlite3IdListAppend(IdList*, Token*);
int sqlite3IdListIndex(IdList*,const char*); int sqlite3IdListIndex(IdList*,const char*);
SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
void sqlite3SrcListAddAlias(SrcList*, Token*); SrcList *sqlite3SrcListAppendFromTerm(SrcList*, Token*, Token*, Token*,
Select*, Expr*, IdList*);
void sqlite3SrcListShiftJoinType(SrcList*);
void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*);
void sqlite3IdListDelete(IdList*); void sqlite3IdListDelete(IdList*);
void sqlite3SrcListDelete(SrcList*); void sqlite3SrcListDelete(SrcList*);
@ -1691,9 +1700,9 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*, void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
int,Expr*,int); int,Expr*,int, int);
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*); void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
void sqlite3DropTrigger(Parse*, SrcList*); void sqlite3DropTrigger(Parse*, SrcList*, int);
void sqlite3DropTriggerPtr(Parse*, Trigger*); void sqlite3DropTriggerPtr(Parse*, Trigger*);
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*); int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int, int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
@ -1821,8 +1830,10 @@ int sqlite3OpenTempDatabase(Parse *);
#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifndef SQLITE_OMIT_LOAD_EXTENSION
void sqlite3CloseExtensions(sqlite3*); void sqlite3CloseExtensions(sqlite3*);
int sqlite3AutoLoadExtensions(sqlite3*);
#else #else
# define sqlite3CloseExtensions(X) # define sqlite3CloseExtensions(X)
# define sqlite3AutoLoadExtensions(X) SQLITE_OK
#endif #endif
#ifndef SQLITE_OMIT_SHARED_CACHE #ifndef SQLITE_OMIT_SHARED_CACHE
@ -1860,6 +1871,8 @@ int sqlite3OpenTempDatabase(Parse *);
int sqlite3VtabRollback(sqlite3 *db); int sqlite3VtabRollback(sqlite3 *db);
int sqlite3VtabCommit(sqlite3 *db); int sqlite3VtabCommit(sqlite3 *db);
#endif #endif
void sqlite3VtabLock(sqlite3_vtab*);
void sqlite3VtabUnlock(sqlite3_vtab*);
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*); void sqlite3VtabArgInit(Parse*);
@ -1869,6 +1882,8 @@ int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *); int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *); int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*); FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
int sqlite3Reprepare(Vdbe*);
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
#include "sseInt.h" #include "sseInt.h"

View file

@ -146,7 +146,7 @@ int sqlite3_get_table(
assert( sizeof(res.azResult[0])>= sizeof(res.nData) ); assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
res.azResult[0] = (char*)res.nData; res.azResult[0] = (char*)res.nData;
} }
if( rc==SQLITE_ABORT ){ if( (rc&0xff)==SQLITE_ABORT ){
sqlite3_free_table(&res.azResult[1]); sqlite3_free_table(&res.azResult[1]);
if( res.zErrMsg ){ if( res.zErrMsg ){
if( pzErrMsg ){ if( pzErrMsg ){
@ -156,12 +156,12 @@ int sqlite3_get_table(
sqliteFree(res.zErrMsg); sqliteFree(res.zErrMsg);
} }
db->errCode = res.rc; db->errCode = res.rc;
return res.rc; return res.rc & db->errMask;
} }
sqliteFree(res.zErrMsg); sqliteFree(res.zErrMsg);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3_free_table(&res.azResult[1]); sqlite3_free_table(&res.azResult[1]);
return rc; return rc & db->errMask;
} }
if( res.nAlloc>res.nData ){ if( res.nAlloc>res.nData ){
char **azNew; char **azNew;
@ -176,7 +176,7 @@ int sqlite3_get_table(
*pazResult = &res.azResult[1]; *pazResult = &res.azResult[1];
if( pnColumn ) *pnColumn = res.nColumn; if( pnColumn ) *pnColumn = res.nColumn;
if( pnRow ) *pnRow = res.nRow; if( pnRow ) *pnRow = res.nRow;
return rc; return rc & db->errMask;
} }
/* /*

View file

@ -553,6 +553,7 @@ static int auth_callback(
case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break; case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break;
case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break; case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break;
case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break;
default : zCode="????"; break; default : zCode="????"; break;
} }
Tcl_DStringInit(&str); Tcl_DStringInit(&str);
@ -1172,6 +1173,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** default. ** default.
*/ */
case DB_ENABLE_LOAD_EXTENSION: { case DB_ENABLE_LOAD_EXTENSION: {
#ifndef SQLITE_OMIT_LOAD_EXTENSION
int onoff; int onoff;
if( objc!=3 ){ if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN"); Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
@ -1182,6 +1184,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
} }
sqlite3_enable_load_extension(pDb->db, onoff); sqlite3_enable_load_extension(pDb->db, onoff);
break; break;
#else
Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
0);
return TCL_ERROR;
#endif
} }
/* /*
@ -2001,6 +2008,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
const char *zArg; const char *zArg;
char *zErrMsg; char *zErrMsg;
const char *zFile; const char *zFile;
Tcl_DString translatedFilename;
if( objc==2 ){ if( objc==2 ){
zArg = Tcl_GetStringFromObj(objv[1], 0); zArg = Tcl_GetStringFromObj(objv[1], 0);
if( strcmp(zArg,"-version")==0 ){ if( strcmp(zArg,"-version")==0 ){
@ -2049,9 +2057,11 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
} }
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
zFile = Tcl_GetStringFromObj(objv[2], 0); zFile = Tcl_GetStringFromObj(objv[2], 0);
zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
sqlite3_open(zFile, &p->db); sqlite3_open(zFile, &p->db);
Tcl_DStringFree(&translatedFilename);
if( SQLITE_OK!=sqlite3_errcode(p->db) ){ if( SQLITE_OK!=sqlite3_errcode(p->db) ){
zErrMsg = strdup(sqlite3_errmsg(p->db)); zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
sqlite3_close(p->db); sqlite3_close(p->db);
p->db = 0; p->db = 0;
} }
@ -2061,10 +2071,11 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( p->db==0 ){ if( p->db==0 ){
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
Tcl_Free((char*)p); Tcl_Free((char*)p);
free(zErrMsg); sqlite3_free(zErrMsg);
return TCL_ERROR; return TCL_ERROR;
} }
p->maxStmt = NUM_PREPARED_STMTS; p->maxStmt = NUM_PREPARED_STMTS;
p->interp = interp;
zArg = Tcl_GetStringFromObj(objv[1], 0); zArg = Tcl_GetStringFromObj(objv[1], 0);
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
@ -2084,7 +2095,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
#endif #endif
} }
#endif #endif
p->interp = interp;
return TCL_OK; return TCL_OK;
} }
@ -2200,6 +2210,7 @@ int TCLSH_MAIN(int argc, char **argv){
extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*);
extern int Sqlitetesttclvar_Init(Tcl_Interp*); extern int Sqlitetesttclvar_Init(Tcl_Interp*);
extern int Sqlitetestschema_Init(Tcl_Interp*); extern int Sqlitetestschema_Init(Tcl_Interp*);
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
Sqlitetest1_Init(interp); Sqlitetest1_Init(interp);
Sqlitetest2_Init(interp); Sqlitetest2_Init(interp);
@ -2212,6 +2223,7 @@ int TCLSH_MAIN(int argc, char **argv){
Sqlitetestasync_Init(interp); Sqlitetestasync_Init(interp);
Sqlitetesttclvar_Init(interp); Sqlitetesttclvar_Init(interp);
Sqlitetestschema_Init(interp); Sqlitetestschema_Init(interp);
Sqlitetest_autoext_Init(interp);
Md5_Init(interp); Md5_Init(interp);
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
Sqlitetestsse_Init(interp); Sqlitetestsse_Init(interp);
@ -2220,6 +2232,9 @@ int TCLSH_MAIN(int argc, char **argv){
#endif #endif
if( argc>=2 || TCLSH==2 ){ if( argc>=2 || TCLSH==2 ){
int i; int i;
char zArgc[32];
sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY); Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
for(i=3-TCLSH; i<argc; i++){ for(i=3-TCLSH; i<argc; i++){

View file

@ -63,9 +63,25 @@ static int get_sqlite_pointer(
return TCL_OK; return TCL_OK;
} }
/*
** Decode a pointer to an sqlite3 object.
*/
static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
struct SqliteDb *p;
Tcl_CmdInfo cmdInfo;
if( Tcl_GetCommandInfo(interp, zA, &cmdInfo) ){
p = (struct SqliteDb*)cmdInfo.objClientData;
*ppDb = p->db;
}else{
*ppDb = (sqlite3*)sqlite3TextToPtr(zA);
}
return TCL_OK;
}
const char *sqlite3TestErrorName(int rc){ const char *sqlite3TestErrorName(int rc){
const char *zName = 0; const char *zName = 0;
switch( rc ){ switch( rc & 0xff ){
case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break;
@ -121,14 +137,6 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
return 0; return 0;
} }
/*
** Decode a pointer to an sqlite3 object.
*/
static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
*ppDb = (sqlite3*)sqlite3TextToPtr(zA);
return TCL_OK;
}
/* /*
** Decode a pointer to an sqlite3_stmt object. ** Decode a pointer to an sqlite3_stmt object.
*/ */
@ -227,6 +235,65 @@ static int test_exec_printf(
return TCL_OK; return TCL_OK;
} }
/*
** Usage: sqlite3_exec DB SQL
**
** Invoke the sqlite3_exec interface using the open database DB
*/
static int test_exec(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
char **argv /* Text of each argument */
){
sqlite3 *db;
Tcl_DString str;
int rc;
char *zErr = 0;
char zBuf[30];
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB SQL", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
Tcl_DStringInit(&str);
rc = sqlite3_exec(db, argv[2], exec_printf_cb, &str, &zErr);
sprintf(zBuf, "%d", rc);
Tcl_AppendElement(interp, zBuf);
Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
Tcl_DStringFree(&str);
if( zErr ) sqlite3_free(zErr);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
}
/*
** Usage: sqlite3_exec_nr DB SQL
**
** Invoke the sqlite3_exec interface using the open database DB. Discard
** all results
*/
static int test_exec_nr(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
char **argv /* Text of each argument */
){
sqlite3 *db;
int rc;
char *zErr = 0;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB SQL", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
}
/* /*
** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ... ** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ...
** **
@ -442,6 +509,34 @@ static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
} }
} }
/*
** These are test functions. hex8() interprets its argument as
** UTF8 and returns a hex encoding. hex16le() interprets its argument
** as UTF16le and returns a hex encoding.
*/
static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){
const unsigned char *z;
int i;
char zBuf[200];
z = sqlite3_value_text(argv[0]);
for(i=0; i<sizeof(zBuf)/2 - 2 && z[i]; i++){
sprintf(&zBuf[i*2], "%02x", z[i]&0xff);
}
zBuf[i*2] = 0;
sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
}
static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){
const unsigned short int *z;
int i;
char zBuf[400];
z = sqlite3_value_text16(argv[0]);
for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){
sprintf(&zBuf[i*4], "%04x", z[i]&0xff);
}
zBuf[i*4] = 0;
sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
}
/* /*
** A structure into which to accumulate text. ** A structure into which to accumulate text.
*/ */
@ -548,6 +643,14 @@ static int test_create_function(
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0, rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0,
ifnullFunc, 0, 0); ifnullFunc, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0,
hex8Func, 0, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0,
hex16Func, 0, 0);
}
#ifndef SQLITE_OMIT_UTF16 #ifndef SQLITE_OMIT_UTF16
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also /* Use the sqlite3_create_function16() API here. Mainly for fun, but also
@ -657,6 +760,30 @@ static int test_create_aggregate(
} }
/*
** Usage: printf TEXT
**
** Send output to printf. Use this rather than puts to merge the output
** in the correct sequence with debugging printfs inserted into C code.
** Puts uses a separate buffer and debugging statements will be out of
** sequence if it is used.
*/
static int test_printf(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
char **argv /* Text of each argument */
){
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" TEXT\"", 0);
return TCL_ERROR;
}
printf("%s\n", argv[1]);
return TCL_OK;
}
/* /*
** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER ** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
@ -1025,6 +1152,29 @@ static int test_enable_shared(
} }
#endif #endif
/*
** Usage: sqlite3_extended_result_codes DB BOOLEAN
**
*/
static int test_extended_result_codes(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
int enable;
sqlite3 *db;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
if( Tcl_GetBooleanFromObj(interp, objv[2], &enable) ) return TCL_ERROR;
sqlite3_extended_result_codes(db, enable);
return TCL_OK;
}
/* /*
** Usage: sqlite3_libversion_number ** Usage: sqlite3_libversion_number
** **
@ -1289,7 +1439,7 @@ static int test_finalize(
){ ){
sqlite3_stmt *pStmt; sqlite3_stmt *pStmt;
int rc; int rc;
sqlite3 *db; sqlite3 *db = 0;
if( objc!=2 ){ if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_AppendResult(interp, "wrong # args: should be \"",
@ -1417,6 +1567,7 @@ static int test_changes(
** the FLAG option of sqlite3_bind is "static" ** the FLAG option of sqlite3_bind is "static"
*/ */
static char *sqlite_static_bind_value = 0; static char *sqlite_static_bind_value = 0;
static int sqlite_static_bind_nbyte = 0;
/* /*
** Usage: sqlite3_bind VM IDX VALUE FLAGS ** Usage: sqlite3_bind VM IDX VALUE FLAGS
@ -1449,6 +1600,9 @@ static int test_bind(
rc = sqlite3_bind_null(pStmt, idx); rc = sqlite3_bind_null(pStmt, idx);
}else if( strcmp(argv[4],"static")==0 ){ }else if( strcmp(argv[4],"static")==0 ){
rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0); rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
}else if( strcmp(argv[4],"static-nbytes")==0 ){
rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value,
sqlite_static_bind_nbyte, 0);
}else if( strcmp(argv[4],"normal")==0 ){ }else if( strcmp(argv[4],"normal")==0 ){
rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT); rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
}else if( strcmp(argv[4],"blob10")==0 ){ }else if( strcmp(argv[4],"blob10")==0 ){
@ -2291,6 +2445,8 @@ static int test_errcode(
Tcl_Obj *CONST objv[] Tcl_Obj *CONST objv[]
){ ){
sqlite3 *db; sqlite3 *db;
int rc;
char zBuf[30];
if( objc!=2 ){ if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_AppendResult(interp, "wrong # args: should be \"",
@ -2298,7 +2454,13 @@ static int test_errcode(
return TCL_ERROR; return TCL_ERROR;
} }
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0); rc = sqlite3_errcode(db);
if( (rc&0xff)==rc ){
zBuf[0] = 0;
}else{
sprintf(zBuf,"+%d", rc>>8);
}
Tcl_AppendResult(interp, (char *)errorName(rc), zBuf, 0);
return TCL_OK; return TCL_OK;
} }
@ -2418,7 +2580,60 @@ static int test_prepare(
} }
/* /*
** Usage: sqlite3_prepare DB sql bytes tailvar ** Usage: sqlite3_prepare_v2 DB sql bytes tailvar
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
** variable that is set to the unused portion of <sql> (if any). A
** STMT handle is returned.
*/
static int test_prepare_v2(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
const char *zSql;
int bytes;
const char *zTail = 0;
sqlite3_stmt *pStmt = 0;
char zBuf[50];
int rc;
if( objc!=5 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
zSql = Tcl_GetString(objv[2]);
if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
if( zTail ){
if( bytes>=0 ){
bytes = bytes - (zTail-zSql);
}
Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
}
if( rc!=SQLITE_OK ){
assert( pStmt==0 );
sprintf(zBuf, "(%d) ", rc);
Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
if( pStmt ){
if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
Tcl_AppendResult(interp, zBuf, 0);
}
return TCL_OK;
}
/*
** Usage: sqlite3_prepare16 DB sql bytes tailvar
** **
** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global ** database handle <DB>. The parameter <tailval> is the name of a global
@ -2475,6 +2690,64 @@ static int test_prepare16(
return TCL_OK; return TCL_OK;
} }
/*
** Usage: sqlite3_prepare16_v2 DB sql bytes tailvar
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
** variable that is set to the unused portion of <sql> (if any). A
** STMT handle is returned.
*/
static int test_prepare16_v2(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
sqlite3 *db;
const void *zSql;
const void *zTail = 0;
Tcl_Obj *pTail = 0;
sqlite3_stmt *pStmt = 0;
char zBuf[50];
int rc;
int bytes; /* The integer specified as arg 3 */
int objlen; /* The byte-array length of arg 2 */
if( objc!=5 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
rc = sqlite3_prepare16_v2(db, zSql, bytes, &pStmt, &zTail);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
if( rc ){
return TCL_ERROR;
}
if( zTail ){
objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
}else{
objlen = 0;
}
pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
Tcl_IncrRefCount(pTail);
Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
Tcl_DecrRefCount(pTail);
if( pStmt ){
if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
}
Tcl_AppendResult(interp, zBuf, 0);
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
}
/* /*
** Usage: sqlite3_open filename ?options-list? ** Usage: sqlite3_open filename ?options-list?
*/ */
@ -3540,6 +3813,18 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY);
#endif #endif
#ifdef SQLITE_ENABLE_FTS1
Tcl_SetVar2(interp, "sqlite_options", "fts1", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "fts1", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_FTS2
Tcl_SetVar2(interp, "sqlite_options", "fts2", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "fts2", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_GLOBALRECOVER #ifdef SQLITE_OMIT_GLOBALRECOVER
Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY);
#else #else
@ -3698,6 +3983,35 @@ static void set_options(Tcl_Interp *interp){
#endif #endif
} }
/*
** tclcmd: working_64bit_int
**
** Some TCL builds (ex: cygwin) do not support 64-bit integers. This
** leads to a number of test failures. The present command checks the
** TCL build to see whether or not it supports 64-bit integers. It
** returns TRUE if it does and FALSE if not.
**
** This command is used to warn users that their TCL build is defective
** and that the errors they are seeing in the test scripts might be
** a result of their defective TCL rather than problems in SQLite.
*/
static int working_64bit_int(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
Tcl_Obj *pTestObj;
int working = 0;
pTestObj = Tcl_NewWideIntObj(1000000*(i64)1234567890);
working = strcmp(Tcl_GetString(pTestObj), "1234567890000000")==0;
Tcl_DecrRefCount(pTestObj);
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(working));
return TCL_OK;
}
/* /*
** Register commands with the TCL interpreter. ** Register commands with the TCL interpreter.
*/ */
@ -3722,6 +4036,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_mprintf_n_test", (Tcl_CmdProc*)test_mprintf_n }, { "sqlite3_mprintf_n_test", (Tcl_CmdProc*)test_mprintf_n },
{ "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
{ "sqlite3_exec", (Tcl_CmdProc*)test_exec },
{ "sqlite3_exec_nr", (Tcl_CmdProc*)test_exec_nr },
{ "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
{ "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close },
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
@ -3743,6 +4059,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit }, { "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used }, { "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout }, { "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
{ "printf", (Tcl_CmdProc*)test_printf },
}; };
static struct { static struct {
char *zName; char *zName;
@ -3771,6 +4088,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_prepare", test_prepare ,0 }, { "sqlite3_prepare", test_prepare ,0 },
{ "sqlite3_prepare16", test_prepare16 ,0 }, { "sqlite3_prepare16", test_prepare16 ,0 },
{ "sqlite3_prepare_v2", test_prepare_v2 ,0 },
{ "sqlite3_prepare16_v2", test_prepare16_v2 ,0 },
{ "sqlite3_finalize", test_finalize ,0 }, { "sqlite3_finalize", test_finalize ,0 },
{ "sqlite3_reset", test_reset ,0 }, { "sqlite3_reset", test_reset ,0 },
{ "sqlite3_expired", test_expired ,0 }, { "sqlite3_expired", test_expired ,0 },
@ -3786,6 +4105,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_load_extension", test_load_extension, 0}, { "sqlite3_load_extension", test_load_extension, 0},
{ "sqlite3_enable_load_extension", test_enable_load, 0}, { "sqlite3_enable_load_extension", test_enable_load, 0},
{ "sqlite3_extended_result_codes", test_extended_result_codes, 0},
/* sqlite3_column_*() API */ /* sqlite3_column_*() API */
{ "sqlite3_column_count", test_column_count ,0 }, { "sqlite3_column_count", test_column_count ,0 },
@ -3819,6 +4139,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif #endif
#endif #endif
{ "sqlite3_global_recover", test_global_recover, 0 }, { "sqlite3_global_recover", test_global_recover, 0 },
{ "working_64bit_int", working_64bit_int, 0 },
/* Functions from os.h */ /* Functions from os.h */
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
@ -3938,6 +4259,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif #endif
Tcl_LinkVar(interp, "sqlite_static_bind_value", Tcl_LinkVar(interp, "sqlite_static_bind_value",
(char*)&sqlite_static_bind_value, TCL_LINK_STRING); (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
Tcl_LinkVar(interp, "sqlite_static_bind_nbyte",
(char*)&sqlite_static_bind_nbyte, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_temp_directory", Tcl_LinkVar(interp, "sqlite_temp_directory",
(char*)&sqlite3_temp_directory, TCL_LINK_STRING); (char*)&sqlite3_temp_directory, TCL_LINK_STRING);
Tcl_LinkVar(interp, "bitmask_size", Tcl_LinkVar(interp, "bitmask_size",

View file

@ -567,6 +567,7 @@ static int btree_integrity_check(
int nRoot; int nRoot;
int *aRoot; int *aRoot;
int i; int i;
int nErr;
char *zResult; char *zResult;
if( argc<3 ){ if( argc<3 ){
@ -581,7 +582,7 @@ static int btree_integrity_check(
if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
} }
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot); zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
#else #else
zResult = 0; zResult = 0;
#endif #endif
@ -598,7 +599,6 @@ static int btree_integrity_check(
** **
** Print information about all cursors to standard output for debugging. ** Print information about all cursors to standard output for debugging.
*/ */
#ifdef SQLITE_DEBUG
static int btree_cursor_list( static int btree_cursor_list(
void *NotUsed, void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@ -616,7 +616,6 @@ static int btree_cursor_list(
sqlite3BtreeCursorList(pBt); sqlite3BtreeCursorList(pBt);
return SQLITE_OK; return SQLITE_OK;
} }
#endif
/* /*
** Usage: btree_cursor ID TABLENUM WRITEABLE ** Usage: btree_cursor ID TABLENUM WRITEABLE
@ -1053,6 +1052,7 @@ static int btree_data(
rc = sqlite3BtreeData(pCur, 0, n, zBuf); rc = sqlite3BtreeData(pCur, 0, n, zBuf);
if( rc ){ if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0); Tcl_AppendResult(interp, errorName(rc), 0);
free(zBuf);
return TCL_ERROR; return TCL_ERROR;
} }
zBuf[n] = 0; zBuf[n] = 0;
@ -1187,7 +1187,6 @@ static int btree_payload_size(
** aResult[8] = Local payload size ** aResult[8] = Local payload size
** aResult[9] = Parent page number ** aResult[9] = Parent page number
*/ */
#ifdef SQLITE_DEBUG
static int btree_cursor_info( static int btree_cursor_info(
void *NotUsed, void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@ -1225,7 +1224,6 @@ static int btree_cursor_info(
Tcl_AppendResult(interp, &zBuf[1], 0); Tcl_AppendResult(interp, &zBuf[1], 0);
return SQLITE_OK; return SQLITE_OK;
} }
#endif
/* /*
** The command is provided for the purpose of setting breakpoints. ** The command is provided for the purpose of setting breakpoints.
@ -1441,10 +1439,8 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
{ "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement }, { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
{ "btree_from_db", (Tcl_CmdProc*)btree_from_db }, { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
{ "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }, { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size },
#ifdef SQLITE_DEBUG
{ "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info }, { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
{ "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list }, { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
#endif
}; };
int i; int i;

View file

@ -394,16 +394,16 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int tokenType; int tokenType;
int lastTokenParsed = -1; int lastTokenParsed = -1;
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
extern void *sqlite3ParserAlloc(void*(*)(int)); extern void *sqlite3ParserAlloc(void*(*)(size_t));
extern void sqlite3ParserFree(void*, void(*)(void*)); extern void sqlite3ParserFree(void*, void(*)(void*));
extern int sqlite3Parser(void*, int, Token, Parse*); extern void sqlite3Parser(void*, int, Token, Parse*);
if( db->activeVdbeCnt==0 ){ if( db->activeVdbeCnt==0 ){
db->u1.isInterrupted = 0; db->u1.isInterrupted = 0;
} }
pParse->rc = SQLITE_OK; pParse->rc = SQLITE_OK;
i = 0; i = 0;
pEngine = sqlite3ParserAlloc((void*(*)(int))sqlite3MallocX); pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3MallocX);
if( pEngine==0 ){ if( pEngine==0 ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }

View file

@ -49,7 +49,8 @@ void sqlite3BeginTrigger(
SrcList *pTableName,/* The name of the table/view the trigger applies to */ SrcList *pTableName,/* The name of the table/view the trigger applies to */
int foreach, /* One of TK_ROW or TK_STATEMENT */ int foreach, /* One of TK_ROW or TK_STATEMENT */
Expr *pWhen, /* WHEN clause */ Expr *pWhen, /* WHEN clause */
int isTemp /* True if the TEMPORARY keyword is present */ int isTemp, /* True if the TEMPORARY keyword is present */
int noErr /* Suppress errors if the trigger already exists */
){ ){
Trigger *pTrigger = 0; Trigger *pTrigger = 0;
Table *pTab; Table *pTab;
@ -115,7 +116,9 @@ void sqlite3BeginTrigger(
goto trigger_cleanup; goto trigger_cleanup;
} }
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
}
goto trigger_cleanup; goto trigger_cleanup;
} }
@ -439,7 +442,7 @@ void sqlite3DeleteTrigger(Trigger *pTrigger){
** same job as this routine except it takes a pointer to the trigger ** same job as this routine except it takes a pointer to the trigger
** instead of the trigger name. ** instead of the trigger name.
**/ **/
void sqlite3DropTrigger(Parse *pParse, SrcList *pName){ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
Trigger *pTrigger = 0; Trigger *pTrigger = 0;
int i; int i;
const char *zDb; const char *zDb;
@ -463,7 +466,9 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
if( pTrigger ) break; if( pTrigger ) break;
} }
if( !pTrigger ){ if( !pTrigger ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
}
goto drop_trigger_cleanup; goto drop_trigger_cleanup;
} }
sqlite3DropTriggerPtr(pParse, pTrigger); sqlite3DropTriggerPtr(pParse, pTrigger);
@ -664,11 +669,11 @@ static int codeTriggerProgram(
switch( pTriggerStep->op ){ switch( pTriggerStep->op ){
case TK_SELECT: { case TK_SELECT: {
Select *ss = sqlite3SelectDup(pTriggerStep->pSelect); Select *ss = sqlite3SelectDup(pTriggerStep->pSelect);
assert(ss); if( ss ){
assert(ss->pSrc);
sqlite3SelectResolve(pParse, ss, 0); sqlite3SelectResolve(pParse, ss, 0);
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0); sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
sqlite3SelectDelete(ss); sqlite3SelectDelete(ss);
}
break; break;
} }
case TK_UPDATE: { case TK_UPDATE: {

View file

@ -64,7 +64,7 @@
/* /*
** This table maps from the first byte of a UTF-8 character to the number ** This table maps from the first byte of a UTF-8 character to the number
** of trailing bytes expected. A value '255' indicates that the table key ** of trailing bytes expected. A value '4' indicates that the table key
** is not a legal first byte for a UTF-8 character. ** is not a legal first byte for a UTF-8 character.
*/ */
static const u8 xtra_utf8_bytes[256] = { static const u8 xtra_utf8_bytes[256] = {
@ -79,10 +79,10 @@ static const u8 xtra_utf8_bytes[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 10wwwwww */ /* 10wwwwww */
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
/* 110yyyyy */ /* 110yyyyy */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -92,7 +92,7 @@ static const u8 xtra_utf8_bytes[256] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 11110yyy */ /* 11110yyy */
3, 3, 3, 3, 3, 3, 3, 3, 255, 255, 255, 255, 255, 255, 255, 255, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
}; };
/* /*
@ -101,23 +101,39 @@ static const u8 xtra_utf8_bytes[256] = {
** read by a naive implementation of a UTF-8 character reader. The code ** read by a naive implementation of a UTF-8 character reader. The code
** in the READ_UTF8 macro explains things best. ** in the READ_UTF8 macro explains things best.
*/ */
static const int xtra_utf8_bits[4] = { static const int xtra_utf8_bits[] = {
0, 0,
12416, /* (0xC0 << 6) + (0x80) */ 12416, /* (0xC0 << 6) + (0x80) */
925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */ 925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */ 63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
}; };
/*
** If a UTF-8 character contains N bytes extra bytes (N bytes follow
** the initial byte so that the total character length is N+1) then
** masking the character with utf8_mask[N] must produce a non-zero
** result. Otherwise, we have an (illegal) overlong encoding.
*/
static const int utf_mask[] = {
0x00000000,
0xffffff80,
0xfffff800,
0xffff0000,
};
#define READ_UTF8(zIn, c) { \ #define READ_UTF8(zIn, c) { \
int xtra; \ int xtra; \
c = *(zIn)++; \ c = *(zIn)++; \
xtra = xtra_utf8_bytes[c]; \ xtra = xtra_utf8_bytes[c]; \
switch( xtra ){ \ switch( xtra ){ \
case 255: c = (int)0xFFFD; break; \ case 4: c = (int)0xFFFD; break; \
case 3: c = (c<<6) + *(zIn)++; \ case 3: c = (c<<6) + *(zIn)++; \
case 2: c = (c<<6) + *(zIn)++; \ case 2: c = (c<<6) + *(zIn)++; \
case 1: c = (c<<6) + *(zIn)++; \ case 1: c = (c<<6) + *(zIn)++; \
c -= xtra_utf8_bits[xtra]; \ c -= xtra_utf8_bits[xtra]; \
if( (utf_mask[xtra]&c)==0 \
|| (c&0xFFFFF800)==0xD800 \
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
} \ } \
} }
int sqlite3ReadUtf8(const unsigned char *z){ int sqlite3ReadUtf8(const unsigned char *z){
@ -181,6 +197,7 @@ int sqlite3ReadUtf8(const unsigned char *z){
int c2 = (*zIn++); \ int c2 = (*zIn++); \
c2 += ((*zIn++)<<8); \ c2 += ((*zIn++)<<8); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
} \ } \
} }
@ -191,6 +208,7 @@ int sqlite3ReadUtf8(const unsigned char *z){
int c2 = ((*zIn++)<<8); \ int c2 = ((*zIn++)<<8); \
c2 += (*zIn++); \ c2 += (*zIn++); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
} \ } \
} }
@ -245,7 +263,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
unsigned char *zIn; /* Input iterator */ unsigned char *zIn; /* Input iterator */
unsigned char *zTerm; /* End of input */ unsigned char *zTerm; /* End of input */
unsigned char *z; /* Output iterator */ unsigned char *z; /* Output iterator */
int c; unsigned int c;
assert( pMem->flags&MEM_Str ); assert( pMem->flags&MEM_Str );
assert( pMem->enc!=desiredEnc ); assert( pMem->enc!=desiredEnc );
@ -475,7 +493,7 @@ char *sqlite3utf16to8(const void *z, int nByte){
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first). ** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
*/ */
int sqlite3utf16ByteLen(const void *zIn, int nChar){ int sqlite3utf16ByteLen(const void *zIn, int nChar){
int c = 1; unsigned int c = 1;
char const *z = zIn; char const *z = zIn;
int n = 0; int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){ if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
@ -556,11 +574,11 @@ void sqlite3utf16Substr(
** characters in each encoding are inverses of each other. ** characters in each encoding are inverses of each other.
*/ */
void sqlite3utfSelfTest(){ void sqlite3utfSelfTest(){
int i; unsigned int i, t;
unsigned char zBuf[20]; unsigned char zBuf[20];
unsigned char *z; unsigned char *z;
int n; int n;
int c; unsigned int c;
for(i=0; i<0x00110000; i++){ for(i=0; i<0x00110000; i++){
z = zBuf; z = zBuf;
@ -568,7 +586,10 @@ void sqlite3utfSelfTest(){
n = z-zBuf; n = z-zBuf;
z = zBuf; z = zBuf;
READ_UTF8(z, c); READ_UTF8(z, c);
assert( c==i ); t = i;
if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
assert( c==t );
assert( (z-zBuf)==n ); assert( (z-zBuf)==n );
} }
for(i=0; i<0x00110000; i++){ for(i=0; i<0x00110000; i++){

View file

@ -1446,7 +1446,7 @@ int sqlite3ApiExit(sqlite3* db, int rc){
sqlite3Error(db, SQLITE_NOMEM, 0); sqlite3Error(db, SQLITE_NOMEM, 0);
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
} }
return rc; return rc & (db ? db->errMask : 0xff);
} }
/* /*

View file

@ -21,20 +21,6 @@
#include "os.h" #include "os.h"
#ifndef SQLITE_OMIT_VACUUM #ifndef SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.
*/
static void randomName(unsigned char *zBuf){
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"0123456789";
int i;
sqlite3Randomness(20, zBuf);
for(i=0; i<20; i++){
zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
}
}
/* /*
** Execute zSql on database db. Return an error code. ** Execute zSql on database db. Return an error code.
*/ */
@ -69,8 +55,6 @@ static int execExecSql(sqlite3 *db, const char *zSql){
return sqlite3_finalize(pStmt); return sqlite3_finalize(pStmt);
} }
#endif
/* /*
** The non-standard VACUUM command is used to clean up the database, ** The non-standard VACUUM command is used to clean up the database,
** collapse free space, etc. It is modelled after the VACUUM command ** collapse free space, etc. It is modelled after the VACUUM command
@ -94,60 +78,25 @@ void sqlite3Vacuum(Parse *pParse){
*/ */
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
int rc = SQLITE_OK; /* Return code from service routines */ int rc = SQLITE_OK; /* Return code from service routines */
#ifndef SQLITE_OMIT_VACUUM
const char *zFilename; /* full pathname of the database file */
int nFilename; /* number of characters in zFilename[] */
char *zTemp = 0; /* a temporary file in same directory as zFilename */
Btree *pMain; /* The database being vacuumed */ Btree *pMain; /* The database being vacuumed */
Btree *pTemp; Btree *pTemp; /* The temporary database we vacuum into */
char *zSql = 0; char *zSql = 0; /* SQL statements */
int saved_flags; /* Saved value of the db->flags */ int saved_flags; /* Saved value of the db->flags */
Db *pDb = 0; /* Database to detach at end of vacuum */ Db *pDb = 0; /* Database to detach at end of vacuum */
char zTemp[SQLITE_TEMPNAME_SIZE+20]; /* Name of the TEMP file */
/* Save the current value of the write-schema flag before setting it. */ /* Save the current value of the write-schema flag before setting it. */
saved_flags = db->flags; saved_flags = db->flags;
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
sqlite3OsTempFileName(zTemp);
if( !db->autoCommit ){ if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
(char*)0); (char*)0);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
goto end_of_vacuum; goto end_of_vacuum;
} }
/* Get the full pathname of the database file and create a
** temporary filename in the same directory as the original file.
*/
pMain = db->aDb[0].pBt; pMain = db->aDb[0].pBt;
zFilename = sqlite3BtreeGetFilename(pMain);
assert( zFilename );
if( zFilename[0]=='\0' ){
/* The in-memory database. Do nothing. Return directly to avoid causing
** an error trying to DETACH the vacuum_db (which never got attached)
** in the exit-handler.
*/
return SQLITE_OK;
}
nFilename = strlen(zFilename);
zTemp = sqliteMalloc( nFilename+100 );
if( zTemp==0 ){
rc = SQLITE_NOMEM;
goto end_of_vacuum;
}
strcpy(zTemp, zFilename);
/* The randomName() procedure in the following loop uses an excellent
** source of randomness to generate a name from a space of 1.3e+31
** possibilities. So unless the directory already contains on the order
** of 1.3e+31 files, the probability that the following loop will
** run more than once or twice is vanishingly small. We are certain
** enough that this loop will always terminate (and terminate quickly)
** that we don't even bother to set a maximum loop count.
*/
do {
zTemp[nFilename] = '-';
randomName((unsigned char*)&zTemp[nFilename+1]);
} while( sqlite3OsFileExists(zTemp) );
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash ** can be set to 'off' for this file, as it is not recovered if a crash
@ -190,7 +139,9 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
*/ */
rc = execExecSql(db, rc = execExecSql(db,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) " "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"); " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
" AND rootpage>0"
);
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db, rc = execExecSql(db,
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)" "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)"
@ -200,11 +151,6 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) " "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'CREATE VIEW vacuum_db.' || substr(sql,13,100000000) "
" FROM sqlite_master WHERE type='view'"
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Loop through the tables in the main database. For each, do /* Loop through the tables in the main database. For each, do
** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy ** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
@ -214,7 +160,9 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
"SELECT 'INSERT INTO vacuum_db.' || quote(name) " "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM ' || quote(name) || ';'" "|| ' SELECT * FROM ' || quote(name) || ';'"
"FROM sqlite_master " "FROM sqlite_master "
"WHERE type = 'table' AND name!='sqlite_sequence';" "WHERE type = 'table' AND name!='sqlite_sequence' "
" AND rootpage>0"
); );
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
@ -233,17 +181,19 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy the triggers from the main database to the temporary database. /* Copy the triggers, views, and virtual tables from the main database
** This was deferred before in case the triggers interfered with copying ** over to the temporary database. None of these objects has any
** the data. It's possible the indices should be deferred until this ** associated storage, so all we have to do is copy their entries
** point also. ** from the SQLITE_MASTER table.
*/ */
rc = execExecSql(db, rc = execSql(db,
"SELECT 'CREATE TRIGGER vacuum_db.' || substr(sql, 16, 1000000) " "INSERT INTO vacuum_db.sqlite_master "
"FROM sqlite_master WHERE type='trigger'" " SELECT type, name, tbl_name, rootpage, sql"
" FROM sqlite_master"
" WHERE type='view' OR type='trigger'"
" OR (type='table' AND rootpage=0)"
); );
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc ) goto end_of_vacuum;
/* At this point, unless the main db was completely empty, there is now a /* At this point, unless the main db was completely empty, there is now a
** transaction open on the vacuum database, but not on the main database. ** transaction open on the vacuum database, but not on the main database.
@ -309,21 +259,12 @@ end_of_vacuum:
pDb->pSchema = 0; pDb->pSchema = 0;
} }
/* If one of the execSql() calls above returned SQLITE_NOMEM, then the
** mallocFailed flag will be clear (because execSql() calls sqlite3_exec()).
** Fix this so the flag and return code match.
*/
if( rc==SQLITE_NOMEM ){
sqlite3MallocFailed();
}
if( zTemp ){
sqlite3OsDelete(zTemp); sqlite3OsDelete(zTemp);
sqliteFree(zTemp); strcat(zTemp, "-journal");
} sqlite3OsDelete(zTemp);
sqliteFree( zSql ); sqliteFree( zSql );
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, 0);
#endif
return rc; return rc;
} }
#endif /* SQLITE_OMIT_VACUUM */

View file

@ -454,6 +454,21 @@ int sqlite3VdbeExec(
p->resOnStack = 0; p->resOnStack = 0;
db->busyHandler.nBusy = 0; db->busyHandler.nBusy = 0;
CHECK_FOR_INTERRUPT; CHECK_FOR_INTERRUPT;
#ifdef SQLITE_DEBUG
if( (p->db->flags & SQLITE_VdbeListing)!=0
|| sqlite3OsFileExists("vdbe_explain")
){
int i;
printf("VDBE Program Listing:\n");
sqlite3VdbePrintSql(p);
for(i=0; i<p->nOp; i++){
sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
}
}
if( sqlite3OsFileExists("vdbe_trace") ){
p->trace = stdout;
}
#endif
for(pc=p->pc; rc==SQLITE_OK; pc++){ for(pc=p->pc; rc==SQLITE_OK; pc++){
assert( pc>=0 && pc<p->nOp ); assert( pc>=0 && pc<p->nOp );
assert( pTos<=&p->aStack[pc] ); assert( pTos<=&p->aStack[pc] );
@ -1812,32 +1827,31 @@ case OP_IfNot: { /* no-push */
/* Opcode: IsNull P1 P2 * /* Opcode: IsNull P1 P2 *
** **
** If any of the top abs(P1) values on the stack are NULL, then jump ** Check the top of the stack and jump to P2 if the top of the stack
** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack ** is NULL. If P1 is positive, then pop P1 elements from the stack
** unchanged. ** regardless of whether or not the jump is taken. If P1 is negative,
** pop -P1 elements from the stack only if the jump is taken and leave
** the stack unchanged if the jump is not taken.
*/ */
case OP_IsNull: { /* same as TK_ISNULL, no-push */ case OP_IsNull: { /* same as TK_ISNULL, no-push */
int i, cnt; if( pTos->flags & MEM_Null ){
Mem *pTerm;
cnt = pOp->p1;
if( cnt<0 ) cnt = -cnt;
pTerm = &pTos[1-cnt];
assert( pTerm>=p->aStack );
for(i=0; i<cnt; i++, pTerm++){
if( pTerm->flags & MEM_Null ){
pc = pOp->p2-1; pc = pOp->p2-1;
break; if( pOp->p1<0 ){
popStack(&pTos, -pOp->p1);
} }
} }
if( pOp->p1>0 ) popStack(&pTos, cnt); if( pOp->p1>0 ){
popStack(&pTos, pOp->p1);
}
break; break;
} }
/* Opcode: NotNull P1 P2 * /* Opcode: NotNull P1 P2 *
** **
** Jump to P2 if the top P1 values on the stack are all not NULL. Pop the ** Jump to P2 if the top abs(P1) values on the stack are all not NULL.
** stack if P1 times if P1 is greater than zero. If P1 is less than ** Regardless of whether or not the jump is taken, pop the stack
** zero then leave the stack unchanged. ** P1 times if P1 is greater than zero. But if P1 is negative,
** leave the stack unchanged.
*/ */
case OP_NotNull: { /* same as TK_NOTNULL, no-push */ case OP_NotNull: { /* same as TK_NOTNULL, no-push */
int i, cnt; int i, cnt;
@ -2010,7 +2024,9 @@ case OP_Column: {
pC->aRow = 0; pC->aRow = 0;
} }
} }
assert( zRec!=0 || avail>=payloadSize || avail>=9 ); /* The following assert is true in all cases accept when
** the database file has been corrupted externally.
** assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */
szHdrSz = GetVarint((u8*)zData, offset); szHdrSz = GetVarint((u8*)zData, offset);
/* The KeyFetch() or DataFetch() above are fast and will get the entire /* The KeyFetch() or DataFetch() above are fast and will get the entire
@ -2501,6 +2517,8 @@ case OP_VerifyCookie: { /* no-push */
} }
if( rc==SQLITE_OK && iMeta!=pOp->p2 ){ if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0); sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0);
sqlite3ResetInternalSchema(db, pOp->p1);
sqlite3ExpirePreparedStatements(db);
rc = SQLITE_SCHEMA; rc = SQLITE_SCHEMA;
} }
break; break;
@ -2907,7 +2925,7 @@ case OP_MoveGt: { /* no-push */
** **
** The top of the stack holds a blob constructed by MakeRecord. P1 is ** The top of the stack holds a blob constructed by MakeRecord. P1 is
** an index. If no entry exists in P1 that matches the blob then jump ** an index. If no entry exists in P1 that matches the blob then jump
** to P1. If an entry does existing, fall through. The cursor is left ** to P2. If an entry does existing, fall through. The cursor is left
** pointing to the entry that matches. The blob is popped from the stack. ** pointing to the entry that matches. The blob is popped from the stack.
** **
** The difference between this operation and Distinct is that ** The difference between this operation and Distinct is that
@ -2980,7 +2998,7 @@ case OP_IsUnique: { /* no-push */
R = pTos->i; R = pTos->i;
assert( (pTos->flags & MEM_Dyn)==0 ); assert( (pTos->flags & MEM_Dyn)==0 );
pTos--; pTos--;
assert( i>=0 && i<=p->nCursor ); assert( i>=0 && i<p->nCursor );
pCx = p->apCsr[i]; pCx = p->apCsr[i];
assert( pCx!=0 ); assert( pCx!=0 );
pCrsr = pCx->pCursor; pCrsr = pCx->pCursor;
@ -3081,6 +3099,9 @@ case OP_NotExists: { /* no-push */
pC->rowidIsValid = res==0; pC->rowidIsValid = res==0;
pC->nullRow = 0; pC->nullRow = 0;
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
/* res might be uninitialized if rc!=SQLITE_OK. But if rc!=SQLITE_OK
** processing is about to abort so we really do not care whether or not
** the following jump is taken. */
if( res!=0 ){ if( res!=0 ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
pC->rowidIsValid = 0; pC->rowidIsValid = 0;
@ -3852,38 +3873,6 @@ case OP_IdxGE: { /* no-push */
break; break;
} }
/* Opcode: IdxIsNull P1 P2 *
**
** The top of the stack contains an index entry such as might be generated
** by the MakeIdxRec opcode. This routine looks at the first P1 fields of
** that key. If any of the first P1 fields are NULL, then a jump is made
** to address P2. Otherwise we fall straight through.
**
** The index entry is always popped from the stack.
*/
case OP_IdxIsNull: { /* no-push */
int i = pOp->p1;
int k, n;
const char *z;
u32 serial_type;
assert( pTos>=p->aStack );
assert( pTos->flags & MEM_Blob );
z = pTos->z;
n = pTos->n;
k = sqlite3GetVarint32((u8*)z, &serial_type);
for(; k<n && i>0; i--){
k += sqlite3GetVarint32((u8*)&z[k], &serial_type);
if( serial_type==0 ){ /* Serial type 0 is a NULL */
pc = pOp->p2-1;
break;
}
}
Release(pTos);
pTos--;
break;
}
/* Opcode: Destroy P1 P2 * /* Opcode: Destroy P1 P2 *
** **
** Delete an entire database table or index whose root page in the database ** Delete an entire database table or index whose root page in the database
@ -3906,9 +3895,9 @@ case OP_IdxIsNull: { /* no-push */
*/ */
case OP_Destroy: { case OP_Destroy: {
int iMoved; int iMoved;
Vdbe *pVdbe;
int iCnt; int iCnt;
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
Vdbe *pVdbe;
iCnt = 0; iCnt = 0;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){ if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){
@ -4032,10 +4021,14 @@ case OP_CreateTable: {
break; break;
} }
/* Opcode: ParseSchema P1 * P3 /* Opcode: ParseSchema P1 P2 P3
** **
** Read and parse all entries from the SQLITE_MASTER table of database P1 ** Read and parse all entries from the SQLITE_MASTER table of database P1
** that match the WHERE clause P3. ** that match the WHERE clause P3. P2 is the "force" flag. Always do
** the parsing if P2 is true. If P2 is false, then this routine is a
** no-op if the schema is not currently loaded. In other words, if P2
** is false, the SQLITE_MASTER table is only parsed if the rest of the
** schema is already loaded into the symbol table.
** **
** This opcode invokes the parser to create a new virtual machine, ** This opcode invokes the parser to create a new virtual machine,
** then runs the new virtual machine. It is thus a reentrant opcode. ** then runs the new virtual machine. It is thus a reentrant opcode.
@ -4047,13 +4040,16 @@ case OP_ParseSchema: { /* no-push */
InitData initData; InitData initData;
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
if( !DbHasProperty(db, iDb, DB_SchemaLoaded) ) break; if( !pOp->p2 && !DbHasProperty(db, iDb, DB_SchemaLoaded) ){
break;
}
zMaster = SCHEMA_TABLE(iDb); zMaster = SCHEMA_TABLE(iDb);
initData.db = db; initData.db = db;
initData.iDb = pOp->p1;
initData.pzErrMsg = &p->zErrMsg; initData.pzErrMsg = &p->zErrMsg;
zSql = sqlite3MPrintf( zSql = sqlite3MPrintf(
"SELECT name, rootpage, sql, %d FROM '%q'.%s WHERE %s", "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3); db->aDb[iDb].zName, zMaster, pOp->p3);
if( zSql==0 ) goto no_mem; if( zSql==0 ) goto no_mem;
sqlite3SafetyOff(db); sqlite3SafetyOff(db);
assert( db->init.busy==0 ); assert( db->init.busy==0 );
@ -4124,11 +4120,16 @@ case OP_DropTrigger: { /* no-push */
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
/* Opcode: IntegrityCk * P2 * /* Opcode: IntegrityCk P1 P2 *
** **
** Do an analysis of the currently open database. Push onto the ** Do an analysis of the currently open database. Push onto the
** stack the text of an error message describing any problems. ** stack the text of an error message describing any problems.
** If there are no errors, push a "ok" onto the stack. ** If no problems are found, push a NULL onto the stack.
**
** P1 is the address of a memory cell that contains the maximum
** number of allowed errors. At most mem[P1] errors will be reported.
** In other words, the analysis stops as soon as mem[P1] errors are
** seen. Mem[P1] is updated with the number of errors remaining.
** **
** The root page numbers of all tables in the database are integer ** The root page numbers of all tables in the database are integer
** values on the stack. This opcode pulls as many integers as it ** values on the stack. This opcode pulls as many integers as it
@ -4137,13 +4138,15 @@ case OP_DropTrigger: { /* no-push */
** If P2 is not zero, the check is done on the auxiliary database ** If P2 is not zero, the check is done on the auxiliary database
** file, not the main database file. ** file, not the main database file.
** **
** This opcode is used for testing purposes only. ** This opcode is used to implement the integrity_check pragma.
*/ */
case OP_IntegrityCk: { case OP_IntegrityCk: {
int nRoot; int nRoot;
int *aRoot; int *aRoot;
int j; int j;
int nErr;
char *z; char *z;
Mem *pnErr;
for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){ for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){
if( (pTos[-nRoot].flags & MEM_Int)==0 ) break; if( (pTos[-nRoot].flags & MEM_Int)==0 ) break;
@ -4151,6 +4154,10 @@ case OP_IntegrityCk: {
assert( nRoot>0 ); assert( nRoot>0 );
aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) ); aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) );
if( aRoot==0 ) goto no_mem; if( aRoot==0 ) goto no_mem;
j = pOp->p1;
assert( j>=0 && j<p->nMem );
pnErr = &p->aMem[j];
assert( (pnErr->flags & MEM_Int)!=0 );
for(j=0; j<nRoot; j++){ for(j=0; j<nRoot; j++){
Mem *pMem = &pTos[-j]; Mem *pMem = &pTos[-j];
aRoot[j] = pMem->i; aRoot[j] = pMem->i;
@ -4158,12 +4165,12 @@ case OP_IntegrityCk: {
aRoot[j] = 0; aRoot[j] = 0;
popStack(&pTos, nRoot); popStack(&pTos, nRoot);
pTos++; pTos++;
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot); z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot,
if( z==0 || z[0]==0 ){ pnErr->i, &nErr);
if( z ) sqliteFree(z); pnErr->i -= nErr;
pTos->z = "ok"; if( nErr==0 ){
pTos->n = 2; assert( z==0 );
pTos->flags = MEM_Str | MEM_Static | MEM_Term; pTos->flags = MEM_Null;
}else{ }else{
pTos->z = z; pTos->z = z;
pTos->n = strlen(z); pTos->n = strlen(z);
@ -4499,6 +4506,7 @@ case OP_AggFinal: { /* no-push */
} }
#ifndef SQLITE_OMIT_VACUUM
/* Opcode: Vacuum * * * /* Opcode: Vacuum * * *
** **
** Vacuum the entire database. This opcode will cause other virtual ** Vacuum the entire database. This opcode will cause other virtual
@ -4511,6 +4519,7 @@ case OP_Vacuum: { /* no-push */
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
break; break;
} }
#endif
/* Opcode: Expire P1 * * /* Opcode: Expire P1 * *
** **
@ -4672,9 +4681,9 @@ case OP_VFilter: { /* no-push */
assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int ); assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int );
nArg = pTos[-1].i; nArg = pTos[-1].i;
/* Invoke the xFilter method if one is defined. */ /* Invoke the xFilter method */
if( pModule->xFilter ){ {
int res; int res = 0;
int i; int i;
Mem **apArg = p->apArg; Mem **apArg = p->apArg;
for(i = 0; i<nArg; i++){ for(i = 0; i<nArg; i++){
@ -4857,7 +4866,9 @@ case OP_VUpdate: { /* no-push */
apArg[i] = pX; apArg[i] = pX;
} }
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
sqlite3VtabLock(pVtab);
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
sqlite3VtabUnlock(pVtab);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( pOp->p1 && rc==SQLITE_OK ){ if( pOp->p1 && rc==SQLITE_OK ){
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );

View file

@ -129,12 +129,16 @@ int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int); void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*); int sqlite3VdbeCurrentAddr(Vdbe*);
void sqlite3VdbeTrace(Vdbe*,FILE*); void sqlite3VdbeTrace(Vdbe*,FILE*);
void sqlite3VdbeResetStepResult(Vdbe*);
int sqlite3VdbeReset(Vdbe*); int sqlite3VdbeReset(Vdbe*);
int sqliteVdbeSetVariables(Vdbe*,int,const char**); int sqliteVdbeSetVariables(Vdbe*,int,const char**);
void sqlite3VdbeSetNumCols(Vdbe*,int); void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int); int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*); void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*); sqlite3 *sqlite3VdbeDb(Vdbe*);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
const char *sqlite3VdbeGetSql(Vdbe*);
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
#ifndef NDEBUG #ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...); void sqlite3VdbeComment(Vdbe*, const char*, ...);

View file

@ -15,6 +15,8 @@
** 6000 lines long) it was split up into several smaller files and ** 6000 lines long) it was split up into several smaller files and
** this header information was factored out. ** this header information was factored out.
*/ */
#ifndef _VDBEINT_H_
#define _VDBEINT_H_
/* /*
** intToKey() and keyToInt() used to transform the rowid. But with ** intToKey() and keyToInt() used to transform the rowid. But with
@ -328,6 +330,8 @@ struct Vdbe {
u8 inVtabMethod; /* See comments above */ u8 inVtabMethod; /* See comments above */
int nChange; /* Number of db changes made since last reset */ int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */ i64 startTime; /* Time when query started - used for profiling */
int nSql; /* Number of bytes in zSql */
char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */ int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */ int lru; /* Counter used for LRU cache replacement */
@ -401,3 +405,5 @@ void sqlite3VdbeFifoInit(Fifo*);
int sqlite3VdbeFifoPush(Fifo*, i64); int sqlite3VdbeFifoPush(Fifo*, i64);
int sqlite3VdbeFifoPop(Fifo*, i64*); int sqlite3VdbeFifoPop(Fifo*, i64*);
void sqlite3VdbeFifoClear(Fifo*); void sqlite3VdbeFifoClear(Fifo*);
#endif /* !defined(_VDBEINT_H_) */

View file

@ -153,9 +153,13 @@ void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
/* /*
** Execute the statement pStmt, either until a row of data is ready, the ** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs. ** statement is completely executed or an error occurs.
**
** This routine implements the bulk of the logic behind the sqlite_step()
** API. The only thing omitted is the automatic recompile if a
** schema change has occurred. That detail is handled by the
** outer sqlite3_step() wrapper procedure.
*/ */
int sqlite3_step(sqlite3_stmt *pStmt){ static int sqlite3Step(Vdbe *p){
Vdbe *p = (Vdbe*)pStmt;
sqlite3 *db; sqlite3 *db;
int rc; int rc;
@ -172,7 +176,8 @@ int sqlite3_step(sqlite3_stmt *pStmt){
if( p->rc==SQLITE_OK ){ if( p->rc==SQLITE_OK ){
p->rc = SQLITE_SCHEMA; p->rc = SQLITE_SCHEMA;
} }
return SQLITE_ERROR; rc = SQLITE_ERROR;
goto end_of_step;
} }
db = p->db; db = p->db;
if( sqlite3SafetyOn(db) ){ if( sqlite3SafetyOn(db) ){
@ -254,8 +259,42 @@ int sqlite3_step(sqlite3_stmt *pStmt){
sqlite3Error(p->db, rc, 0); sqlite3Error(p->db, rc, 0);
p->rc = sqlite3ApiExit(p->db, p->rc); 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 */
return p->rc;
}else{
/* This is for legacy sqlite3_prepare() builds and when the code
** is SQLITE_ROW or SQLITE_DONE */
return rc; return rc;
} }
}
/*
** This is the top-level implementation of sqlite3_step(). Call
** sqlite3Step() to do most of the work. If a schema error occurs,
** call sqlite3Reprepare() and try again.
*/
#ifdef SQLITE_OMIT_PARSER
int sqlite3_step(sqlite3_stmt *pStmt){
return sqlite3Step((Vdbe*)pStmt);
}
#else
int sqlite3_step(sqlite3_stmt *pStmt){
int cnt = 0;
int rc;
Vdbe *v = (Vdbe*)pStmt;
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < 5
&& sqlite3Reprepare(v) ){
sqlite3_reset(pStmt);
v->expired = 0;
}
return rc;
}
#endif
/* /*
** Extract the user data from a sqlite3_context structure and return a ** Extract the user data from a sqlite3_context structure and return a
@ -266,6 +305,27 @@ void *sqlite3_user_data(sqlite3_context *p){
return p->pFunc->pUserData; return p->pFunc->pUserData;
} }
/*
** The following is the implementation of an SQL function that always
** fails with an error message stating that the function is used in the
** wrong context. The sqlite3_overload_function() API might construct
** SQL function that use this routine so that the functions will exist
** for name resolution but are actually overloaded by the xFindFunction
** method of virtual tables.
*/
void sqlite3InvalidFunction(
sqlite3_context *context, /* The function calling context */
int argc, /* Number of arguments to the function */
sqlite3_value **argv /* Value of each argument */
){
const char *zName = context->pFunc->zName;
char *zErr;
zErr = sqlite3MPrintf(
"unable to use function %s in the requested context", zName);
sqlite3_result_error(context, zErr, -1);
sqliteFree(zErr);
}
/* /*
** Allocate or return the aggregate context for a user function. A new ** Allocate or return the aggregate context for a user function. A new
** context is allocated on the first call. Subsequent calls return the ** context is allocated on the first call. Subsequent calls return the
@ -815,6 +875,7 @@ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]); rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
sqlite3MallocAllow(); sqlite3MallocAllow();
} }
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
return rc; return rc;
} }

View file

@ -48,6 +48,46 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
return p; return p;
} }
/*
** Remember the SQL string for a prepared statement.
*/
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){
if( p==0 ) return;
assert( p->zSql==0 );
p->zSql = sqlite3StrNDup(z, n);
}
/*
** Return the SQL associated with a prepared statement
*/
const char *sqlite3VdbeGetSql(Vdbe *p){
return p->zSql;
}
/*
** Swap all content between two VDBE structures.
*/
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
Vdbe tmp, *pTmp;
char *zTmp;
int nTmp;
tmp = *pA;
*pA = *pB;
*pB = tmp;
pTmp = pA->pNext;
pA->pNext = pB->pNext;
pB->pNext = pTmp;
pTmp = pA->pPrev;
pA->pPrev = pB->pPrev;
pB->pPrev = pTmp;
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
nTmp = pA->nSql;
pA->nSql = pB->nSql;
pB->nSql = nTmp;
}
/* /*
** Turn tracing on or off ** Turn tracing on or off
*/ */
@ -812,21 +852,6 @@ void sqlite3VdbeMakeReady(
p->aMem[n].flags = MEM_Null; p->aMem[n].flags = MEM_Null;
} }
#ifdef SQLITE_DEBUG
if( (p->db->flags & SQLITE_VdbeListing)!=0
|| sqlite3OsFileExists("vdbe_explain")
){
int i;
printf("VDBE Program Listing:\n");
sqlite3VdbePrintSql(p);
for(i=0; i<p->nOp; i++){
sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
}
}
if( sqlite3OsFileExists("vdbe_trace") ){
p->trace = stdout;
}
#endif
p->pTos = &p->aStack[-1]; p->pTos = &p->aStack[-1];
p->pc = -1; p->pc = -1;
p->rc = SQLITE_OK; p->rc = SQLITE_OK;
@ -1145,7 +1170,9 @@ static int vdbeCommit(sqlite3 *db){
** transaction files are deleted. ** transaction files are deleted.
*/ */
rc = sqlite3OsDelete(zMaster); rc = sqlite3OsDelete(zMaster);
assert( rc==SQLITE_OK ); if( rc ){
return rc;
}
sqliteFree(zMaster); sqliteFree(zMaster);
zMaster = 0; zMaster = 0;
rc = sqlite3OsSyncDirectory(zMainFile); rc = sqlite3OsSyncDirectory(zMainFile);
@ -1287,9 +1314,10 @@ int sqlite3VdbeHalt(Vdbe *p){
/* No commit or rollback needed if the program never started */ /* No commit or rollback needed if the program never started */
if( p->pc>=0 ){ if( p->pc>=0 ){
int mrc; /* Primary error code from p->rc */
/* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */ /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0); mrc = p->rc & 0xff;
isSpecialError = ((mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR)?1:0);
if( isSpecialError ){ if( isSpecialError ){
/* This loop does static analysis of the query to see which of the /* This loop does static analysis of the query to see which of the
** following three categories it falls into: ** following three categories it falls into:
@ -1421,6 +1449,14 @@ int sqlite3VdbeHalt(Vdbe *p){
return SQLITE_OK; return SQLITE_OK;
} }
/*
** Each VDBE holds the result of the most recent sqlite3_step() call
** in p->rc. This routine sets that result back to SQLITE_OK.
*/
void sqlite3VdbeResetStepResult(Vdbe *p){
p->rc = SQLITE_OK;
}
/* /*
** Clean up a VDBE after execution but do not delete the VDBE just yet. ** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg. Return the result code. ** Write any error messages into *pzErrMsg. Return the result code.
@ -1433,18 +1469,20 @@ int sqlite3VdbeHalt(Vdbe *p){
** VDBE_MAGIC_INIT. ** VDBE_MAGIC_INIT.
*/ */
int sqlite3VdbeReset(Vdbe *p){ int sqlite3VdbeReset(Vdbe *p){
sqlite3 *db;
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){ if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
sqlite3Error(p->db, SQLITE_MISUSE, 0); sqlite3Error(p->db, SQLITE_MISUSE, 0);
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
db = p->db;
/* If the VM did not run to completion or if it encountered an /* If the VM did not run to completion or if it encountered an
** error, then it might not have been halted properly. So halt ** error, then it might not have been halted properly. So halt
** it now. ** it now.
*/ */
sqlite3SafetyOn(p->db); sqlite3SafetyOn(db);
sqlite3VdbeHalt(p); sqlite3VdbeHalt(p);
sqlite3SafetyOff(p->db); sqlite3SafetyOff(db);
/* If the VDBE has be run even partially, then transfer the error code /* If the VDBE has be run even partially, then transfer the error code
** and error message from the VDBE into the main database structure. But ** and error message from the VDBE into the main database structure. But
@ -1453,21 +1491,20 @@ int sqlite3VdbeReset(Vdbe *p){
*/ */
if( p->pc>=0 ){ if( p->pc>=0 ){
if( p->zErrMsg ){ if( p->zErrMsg ){
sqlite3* db = p->db;
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX); sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX);
db->errCode = p->rc; db->errCode = p->rc;
p->zErrMsg = 0; p->zErrMsg = 0;
}else if( p->rc ){ }else if( p->rc ){
sqlite3Error(p->db, p->rc, 0); sqlite3Error(db, p->rc, 0);
}else{ }else{
sqlite3Error(p->db, SQLITE_OK, 0); sqlite3Error(db, SQLITE_OK, 0);
} }
}else if( p->rc && p->expired ){ }else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call /* The expired flag was set on the VDBE before the first call
** to sqlite3_step(). For consistency (since sqlite3_step() was ** to sqlite3_step(). For consistency (since sqlite3_step() was
** called), set the database error in this case as well. ** called), set the database error in this case as well.
*/ */
sqlite3Error(p->db, p->rc, 0); sqlite3Error(db, p->rc, 0);
} }
/* Reclaim all memory used by the VDBE /* Reclaim all memory used by the VDBE
@ -1502,9 +1539,9 @@ int sqlite3VdbeReset(Vdbe *p){
p->magic = VDBE_MAGIC_INIT; p->magic = VDBE_MAGIC_INIT;
p->aborted = 0; p->aborted = 0;
if( p->rc==SQLITE_SCHEMA ){ if( p->rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(p->db, 0); sqlite3ResetInternalSchema(db, 0);
} }
return p->rc; return p->rc & db->errMask;
} }
/* /*
@ -1515,6 +1552,7 @@ int sqlite3VdbeFinalize(Vdbe *p){
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){ if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
rc = sqlite3VdbeReset(p); rc = sqlite3VdbeReset(p);
assert( (rc & p->db->errMask)==rc );
}else if( p->magic!=VDBE_MAGIC_INIT ){ }else if( p->magic!=VDBE_MAGIC_INIT ){
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
@ -1569,6 +1607,7 @@ void sqlite3VdbeDelete(Vdbe *p){
sqliteFree(p->aStack); sqliteFree(p->aStack);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqliteFree(p->aColName); sqliteFree(p->aColName);
sqliteFree(p->zSql);
p->magic = VDBE_MAGIC_DEAD; p->magic = VDBE_MAGIC_DEAD;
sqliteFree(p); sqliteFree(p);
} }
@ -1887,14 +1926,13 @@ int sqlite3VdbeRecordCompare(
idx2 += GetVarint( aKey2+idx2, serial_type2 ); idx2 += GetVarint( aKey2+idx2, serial_type2 );
if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break; if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break;
/* Assert that there is enough space left in each key for the blob of /* Extract the values to be compared.
** data to go with the serial type just read. This assert may fail if
** the file is corrupted. Then read the value from each key into mem1
** and mem2 respectively.
*/ */
d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2); d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2);
/* Do the comparison
*/
rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0); rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0);
if( mem1.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem1); if( mem1.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem1);
if( mem2.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem2); if( mem2.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem2);

View file

@ -50,14 +50,6 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
assert(rc==SQLITE_OK || rc==SQLITE_NOMEM); assert(rc==SQLITE_OK || rc==SQLITE_NOMEM);
assert(rc==SQLITE_OK || pMem->enc!=desiredEnc); assert(rc==SQLITE_OK || pMem->enc!=desiredEnc);
assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc); assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc);
if( rc==SQLITE_NOMEM ){
/*
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Null;
pMem->z = 0;
*/
}
return rc; return rc;
#endif #endif
} }
@ -127,22 +119,9 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
** Make sure the given Mem is \u0000 terminated. ** Make sure the given Mem is \u0000 terminated.
*/ */
int sqlite3VdbeMemNulTerminate(Mem *pMem){ int sqlite3VdbeMemNulTerminate(Mem *pMem){
/* In SQLite, a string without a nul terminator occurs when a string
** is loaded from disk (in this case the memory management is ephemeral),
** or when it is supplied by the user as a bound variable or function
** return value. Therefore, the memory management of the string must be
** either ephemeral, static or controlled by a user-supplied destructor.
*/
assert(
!(pMem->flags&MEM_Str) || /* it's not a string, or */
(pMem->flags&MEM_Term) || /* it's nul term. already, or */
(pMem->flags&(MEM_Ephem|MEM_Static)) || /* it's static or ephem, or */
(pMem->flags&MEM_Dyn && pMem->xDel) /* external management */
);
if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){ if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
return SQLITE_OK; /* Nothing to do */ return SQLITE_OK; /* Nothing to do */
} }
if( pMem->flags & (MEM_Static|MEM_Ephem) ){ if( pMem->flags & (MEM_Static|MEM_Ephem) ){
return sqlite3VdbeMemMakeWriteable(pMem); return sqlite3VdbeMemMakeWriteable(pMem);
}else{ }else{
@ -151,7 +130,11 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
memcpy(z, pMem->z, pMem->n); memcpy(z, pMem->z, pMem->n);
z[pMem->n] = 0; z[pMem->n] = 0;
z[pMem->n+1] = 0; z[pMem->n+1] = 0;
if( pMem->xDel ){
pMem->xDel(pMem->z); pMem->xDel(pMem->z);
}else{
sqliteFree(pMem->z);
}
pMem->xDel = 0; pMem->xDel = 0;
pMem->z = z; pMem->z = z;
} }
@ -782,7 +765,9 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
return 0; return 0;
} }
} }
}else if( !(pVal->flags&MEM_Blob) ){ sqlite3VdbeMemNulTerminate(pVal);
}else{
assert( (pVal->flags&MEM_Blob)==0 );
sqlite3VdbeMemStringify(pVal, enc); sqlite3VdbeMemStringify(pVal, enc);
assert( 0==(1&(int)pVal->z) ); assert( 0==(1&(int)pVal->z) );
} }

View file

@ -40,6 +40,29 @@ int sqlite3_create_module(
return sqlite3ApiExit(db, SQLITE_OK); return sqlite3ApiExit(db, SQLITE_OK);
} }
/*
** Lock the virtual table so that it cannot be disconnected.
** Locks nest. Every lock should have a corresponding unlock.
** If an unlock is omitted, resources leaks will occur.
**
** If a disconnect is attempted while a virtual table is locked,
** the disconnect is deferred until all locks have been removed.
*/
void sqlite3VtabLock(sqlite3_vtab *pVtab){
pVtab->nRef++;
}
/*
** Unlock a virtual table. When the last lock is removed,
** disconnect the virtual table.
*/
void sqlite3VtabUnlock(sqlite3_vtab *pVtab){
pVtab->nRef--;
if( pVtab->nRef==0 ){
pVtab->pModule->xDisconnect(pVtab);
}
}
/* /*
** Clear any and all virtual-table information from the Table record. ** Clear any and all virtual-table information from the Table record.
** This routine is called, for example, just before deleting the Table ** This routine is called, for example, just before deleting the Table
@ -49,10 +72,7 @@ void sqlite3VtabClear(Table *p){
sqlite3_vtab *pVtab = p->pVtab; sqlite3_vtab *pVtab = p->pVtab;
if( pVtab ){ if( pVtab ){
assert( p->pMod && p->pMod->pModule ); assert( p->pMod && p->pMod->pModule );
pVtab->nRef--; sqlite3VtabUnlock(pVtab);
if( pVtab->nRef==0 ){
pVtab->pModule->xDisconnect(pVtab);
}
p->pVtab = 0; p->pVtab = 0;
} }
if( p->azModuleArg ){ if( p->azModuleArg ){
@ -139,7 +159,7 @@ void sqlite3VtabBeginParse(
*/ */
static void addArgumentToVtab(Parse *pParse){ static void addArgumentToVtab(Parse *pParse){
if( pParse->sArg.z && pParse->pNewTable ){ if( pParse->sArg.z && pParse->pNewTable ){
const char *z = pParse->sArg.z; const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n; int n = pParse->sArg.n;
addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n)); addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n));
} }
@ -210,7 +230,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp(v, OP_Expire, 0, 0); sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
zWhere = sqlite3MPrintf("name='%q'", pTab->zName); zWhere = sqlite3MPrintf("name='%q'", pTab->zName);
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC);
sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1); sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1);
} }
@ -266,14 +286,16 @@ static int vtabCallConstructor(
sqlite3 *db, sqlite3 *db,
Table *pTab, Table *pTab,
Module *pMod, Module *pMod,
int (*xConstruct)(sqlite3*, void *, int, char **, sqlite3_vtab **), int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
char **pzErr char **pzErr
){ ){
int rc; int rc;
int rc2; int rc2;
char **azArg = pTab->azModuleArg; sqlite3_vtab *pVtab;
const char *const*azArg = (const char *const*)pTab->azModuleArg;
int nArg = pTab->nModuleArg; int nArg = pTab->nModuleArg;
char *zErr = sqlite3MPrintf("vtable constructor failed: %s", pTab->zName); char *zErr = 0;
char *zModuleName = sqlite3MPrintf("%s", pTab->zName);
assert( !db->pVTab ); assert( !db->pVTab );
assert( xConstruct ); assert( xConstruct );
@ -281,16 +303,21 @@ static int vtabCallConstructor(
db->pVTab = pTab; db->pVTab = pTab;
rc = sqlite3SafetyOff(db); rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK ); assert( rc==SQLITE_OK );
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab); rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab, &zErr);
rc2 = sqlite3SafetyOn(db); rc2 = sqlite3SafetyOn(db);
if( rc==SQLITE_OK && pTab->pVtab ){ pVtab = pTab->pVtab;
pTab->pVtab->pModule = pMod->pModule; if( rc==SQLITE_OK && pVtab ){
pTab->pVtab->nRef = 1; pVtab->pModule = pMod->pModule;
pVtab->nRef = 1;
} }
if( SQLITE_OK!=rc ){ if( SQLITE_OK!=rc ){
*pzErr = zErr; if( zErr==0 ){
zErr = 0; *pzErr = sqlite3MPrintf("vtable constructor failed: %s", zModuleName);
}else {
*pzErr = sqlite3MPrintf("%s", zErr);
sqlite3_free(zErr);
}
}else if( db->pVTab ){ }else if( db->pVTab ){
const char *zFormat = "vtable constructor did not declare schema: %s"; const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(zFormat, pTab->zName); *pzErr = sqlite3MPrintf(zFormat, pTab->zName);
@ -300,7 +327,7 @@ static int vtabCallConstructor(
rc = rc2; rc = rc2;
} }
db->pVTab = 0; db->pVTab = 0;
sqliteFree(zErr); sqliteFree(zModuleName);
return rc; return rc;
} }
@ -313,7 +340,6 @@ static int vtabCallConstructor(
*/ */
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
Module *pMod; Module *pMod;
const char *zModule;
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( !pTab || !pTab->isVirtual || pTab->pVtab ){ if( !pTab || !pTab->isVirtual || pTab->pVtab ){
@ -321,7 +347,6 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
} }
pMod = pTab->pMod; pMod = pTab->pMod;
zModule = pTab->azModuleArg[0];
if( !pMod ){ if( !pMod ){
const char *zModule = pTab->azModuleArg[0]; const char *zModule = pTab->azModuleArg[0];
sqlite3ErrorMsg(pParse, "no such module: %s", zModule); sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
@ -359,7 +384,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
/* Add pVtab to the end of sqlite3.aVTrans */ /* Add pVtab to the end of sqlite3.aVTrans */
db->aVTrans[db->nVTrans++] = pVtab; db->aVTrans[db->nVTrans++] = pVtab;
pVtab->nRef++; sqlite3VtabLock(pVtab);
return SQLITE_OK; return SQLITE_OK;
} }
@ -444,6 +469,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
sParse.pNewTable = 0; sParse.pNewTable = 0;
db->pVTab = 0; db->pVTab = 0;
assert( (rc&0xff)==rc );
return rc; return rc;
} }
@ -492,10 +518,7 @@ static void callFinaliser(sqlite3 *db, int offset){
int (*x)(sqlite3_vtab *); int (*x)(sqlite3_vtab *);
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset); x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
if( x ) x(pVtab); if( x ) x(pVtab);
pVtab->nRef--; sqlite3VtabUnlock(pVtab);
if( pVtab->nRef==0 ){
pVtab->pModule->xDisconnect(pVtab);
}
} }
sqliteFree(db->aVTrans); sqliteFree(db->aVTrans);
db->nVTrans = 0; db->nVTrans = 0;
@ -623,6 +646,10 @@ FuncDef *sqlite3VtabOverloadFunction(
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
void *pArg; void *pArg;
FuncDef *pNew; FuncDef *pNew;
int rc;
char *zLowerName;
unsigned char *z;
/* Check to see the left operand is a column in a virtual table */ /* Check to see the left operand is a column in a virtual table */
if( pExpr==0 ) return pDef; if( pExpr==0 ) return pDef;
@ -637,8 +664,15 @@ FuncDef *sqlite3VtabOverloadFunction(
if( pMod->xFindFunction==0 ) return pDef; if( pMod->xFindFunction==0 ) return pDef;
/* Call the xFuncFunction method on the virtual table implementation /* Call the xFuncFunction method on the virtual table implementation
** to see if the implementation wants to overload this function */ ** to see if the implementation wants to overload this function
if( pMod->xFindFunction(pVtab, nArg, pDef->zName, &xFunc, &pArg)==0 ){ */
zLowerName = sqlite3StrDup(pDef->zName);
for(z=(unsigned char*)zLowerName; *z; z++){
*z = sqlite3UpperToLower[*z];
}
rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
sqliteFree(zLowerName);
if( rc==0 ){
return pDef; return pDef;
} }

View file

@ -157,22 +157,31 @@ struct ExprMaskSet {
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) #define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) #define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
#define WO_MATCH 64 #define WO_MATCH 64
#define WO_ISNULL 128
/* /*
** Value for flags returned by bestIndex() ** Value for flags returned by bestIndex().
**
** The least significant byte is reserved as a mask for WO_ values above.
** The WhereLevel.flags field is usually set to WO_IN|WO_EQ|WO_ISNULL.
** But if the table is the right table of a left join, WhereLevel.flags
** is set to WO_IN|WO_EQ. The WhereLevel.flags field can then be used as
** the "op" parameter to findTerm when we are resolving equality constraints.
** ISNULL constraints will then not be used on the right table of a left
** join. Tickets #2177 and #2189.
*/ */
#define WHERE_ROWID_EQ 0x0001 /* rowid=EXPR or rowid IN (...) */ #define WHERE_ROWID_EQ 0x000100 /* rowid=EXPR or rowid IN (...) */
#define WHERE_ROWID_RANGE 0x0002 /* rowid<EXPR and/or rowid>EXPR */ #define WHERE_ROWID_RANGE 0x000200 /* rowid<EXPR and/or rowid>EXPR */
#define WHERE_COLUMN_EQ 0x0010 /* x=EXPR or x IN (...) */ #define WHERE_COLUMN_EQ 0x001000 /* x=EXPR or x IN (...) */
#define WHERE_COLUMN_RANGE 0x0020 /* x<EXPR and/or x>EXPR */ #define WHERE_COLUMN_RANGE 0x002000 /* x<EXPR and/or x>EXPR */
#define WHERE_COLUMN_IN 0x0040 /* x IN (...) */ #define WHERE_COLUMN_IN 0x004000 /* x IN (...) */
#define WHERE_TOP_LIMIT 0x0100 /* x<EXPR or x<=EXPR constraint */ #define WHERE_TOP_LIMIT 0x010000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x0200 /* x>EXPR or x>=EXPR constraint */ #define WHERE_BTM_LIMIT 0x020000 /* x>EXPR or x>=EXPR constraint */
#define WHERE_IDX_ONLY 0x0800 /* Use index only - omit table */ #define WHERE_IDX_ONLY 0x080000 /* Use index only - omit table */
#define WHERE_ORDERBY 0x1000 /* Output will appear in correct order */ #define WHERE_ORDERBY 0x100000 /* Output will appear in correct order */
#define WHERE_REVERSE 0x2000 /* Scan in reverse order */ #define WHERE_REVERSE 0x200000 /* Scan in reverse order */
#define WHERE_UNIQUE 0x4000 /* Selects no more than one row */ #define WHERE_UNIQUE 0x400000 /* Selects no more than one row */
#define WHERE_VIRTUALTABLE 0x8000 /* Use virtual-table processing */ #define WHERE_VIRTUALTABLE 0x800000 /* Use virtual-table processing */
/* /*
** Initialize a preallocated WhereClause structure. ** Initialize a preallocated WhereClause structure.
@ -354,7 +363,7 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE ); assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE ); assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 ); assert( TK_GE==TK_EQ+4 );
return op==TK_IN || (op>=TK_EQ && op<=TK_GE); return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;
} }
/* /*
@ -388,9 +397,12 @@ static int operatorMask(int op){
assert( allowedOp(op) ); assert( allowedOp(op) );
if( op==TK_IN ){ if( op==TK_IN ){
c = WO_IN; c = WO_IN;
}else if( op==TK_ISNULL ){
c = WO_ISNULL;
}else{ }else{
c = WO_EQ<<(op-TK_EQ); c = WO_EQ<<(op-TK_EQ);
} }
assert( op!=TK_ISNULL || c==WO_ISNULL );
assert( op!=TK_IN || c==WO_IN ); assert( op!=TK_IN || c==WO_IN );
assert( op!=TK_EQ || c==WO_EQ ); assert( op!=TK_EQ || c==WO_EQ );
assert( op!=TK_LT || c==WO_LT ); assert( op!=TK_LT || c==WO_LT );
@ -422,7 +434,7 @@ static WhereTerm *findTerm(
&& pTerm->leftColumn==iColumn && pTerm->leftColumn==iColumn
&& (pTerm->eOperator & op)!=0 && (pTerm->eOperator & op)!=0
){ ){
if( iCur>=0 && pIdx ){ if( iCur>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
Expr *pX = pTerm->pExpr; Expr *pX = pTerm->pExpr;
CollSeq *pColl; CollSeq *pColl;
char idxaff; char idxaff;
@ -590,13 +602,17 @@ static void exprAnalyze(
Bitmask prereqAll; Bitmask prereqAll;
int nPattern; int nPattern;
int isComplete; int isComplete;
int op;
if( sqlite3MallocFailed() ) return; if( sqlite3MallocFailed() ) return;
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
if( pExpr->op==TK_IN ){ op = pExpr->op;
if( op==TK_IN ){
assert( pExpr->pRight==0 ); assert( pExpr->pRight==0 );
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList) pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
| exprSelectTableUsage(pMaskSet, pExpr->pSelect); | exprSelectTableUsage(pMaskSet, pExpr->pSelect);
}else if( op==TK_ISNULL ){
pTerm->prereqRight = 0;
}else{ }else{
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight); pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
} }
@ -608,13 +624,13 @@ static void exprAnalyze(
pTerm->leftCursor = -1; pTerm->leftCursor = -1;
pTerm->iParent = -1; pTerm->iParent = -1;
pTerm->eOperator = 0; pTerm->eOperator = 0;
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){ if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
Expr *pLeft = pExpr->pLeft; Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight; Expr *pRight = pExpr->pRight;
if( pLeft->op==TK_COLUMN ){ if( pLeft->op==TK_COLUMN ){
pTerm->leftCursor = pLeft->iTable; pTerm->leftCursor = pLeft->iTable;
pTerm->leftColumn = pLeft->iColumn; pTerm->leftColumn = pLeft->iColumn;
pTerm->eOperator = operatorMask(pExpr->op); pTerm->eOperator = operatorMask(op);
} }
if( pRight && pRight->op==TK_COLUMN ){ if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew; WhereTerm *pNew;
@ -622,6 +638,10 @@ static void exprAnalyze(
if( pTerm->leftCursor>=0 ){ if( pTerm->leftCursor>=0 ){
int idxNew; int idxNew;
pDup = sqlite3ExprDup(pExpr); pDup = sqlite3ExprDup(pExpr);
if( sqlite3MallocFailed() ){
sqliteFree(pDup);
return;
}
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
if( idxNew==0 ) return; if( idxNew==0 ) return;
pNew = &pWC->a[idxNew]; pNew = &pWC->a[idxNew];
@ -715,16 +735,15 @@ static void exprAnalyze(
if( ok ){ if( ok ){
ExprList *pList = 0; ExprList *pList = 0;
Expr *pNew, *pDup; Expr *pNew, *pDup;
Expr *pLeft = 0;
for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){ for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
if( (pOrTerm->flags & TERM_OR_OK)==0 ) continue; if( (pOrTerm->flags & TERM_OR_OK)==0 ) continue;
pDup = sqlite3ExprDup(pOrTerm->pExpr->pRight); pDup = sqlite3ExprDup(pOrTerm->pExpr->pRight);
pList = sqlite3ExprListAppend(pList, pDup, 0); pList = sqlite3ExprListAppend(pList, pDup, 0);
pLeft = pOrTerm->pExpr->pLeft;
} }
pDup = sqlite3Expr(TK_COLUMN, 0, 0, 0); assert( pLeft!=0 );
if( pDup ){ pDup = sqlite3ExprDup(pLeft);
pDup->iTable = iCursor;
pDup->iColumn = iColumn;
}
pNew = sqlite3Expr(TK_IN, pDup, 0, 0); pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
if( pNew ){ if( pNew ){
int idxNew; int idxNew;
@ -857,11 +876,19 @@ static int isSortingIndex(
/* Match terms of the ORDER BY clause against columns of /* Match terms of the ORDER BY clause against columns of
** the index. ** the index.
**
** Note that indices have pIdx->nColumn regular columns plus
** one additional column containing the rowid. The rowid column
** of the index is also allowed to match against the ORDER BY
** clause.
*/ */
for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){ for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<=pIdx->nColumn; i++){
Expr *pExpr; /* The expression of the ORDER BY pTerm */ Expr *pExpr; /* The expression of the ORDER BY pTerm */
CollSeq *pColl; /* The collating sequence of pExpr */ CollSeq *pColl; /* The collating sequence of pExpr */
int termSortOrder; /* Sort order for this term */ int termSortOrder; /* Sort order for this term */
int iColumn; /* The i-th column of the index. -1 for rowid */
int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
const char *zColl; /* Name of the collating sequence for i-th index term */
pExpr = pTerm->pExpr; pExpr = pTerm->pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){ if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
@ -870,9 +897,22 @@ static int isSortingIndex(
return 0; return 0;
} }
pColl = sqlite3ExprCollSeq(pParse, pExpr); pColl = sqlite3ExprCollSeq(pParse, pExpr);
if( !pColl ) pColl = db->pDfltColl; if( !pColl ){
if( pExpr->iColumn!=pIdx->aiColumn[i] || pColl = db->pDfltColl;
sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){ }
if( i<pIdx->nColumn ){
iColumn = pIdx->aiColumn[i];
if( iColumn==pIdx->pTable->iPKey ){
iColumn = -1;
}
iSortOrder = pIdx->aSortOrder[i];
zColl = pIdx->azColl[i];
}else{
iColumn = -1;
iSortOrder = 0;
zColl = pColl->zName;
}
if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
/* Term j of the ORDER BY clause does not match column i of the index */ /* Term j of the ORDER BY clause does not match column i of the index */
if( i<nEqCol ){ if( i<nEqCol ){
/* If an index column that is constrained by == fails to match an /* If an index column that is constrained by == fails to match an
@ -888,8 +928,8 @@ static int isSortingIndex(
} }
assert( pIdx->aSortOrder!=0 ); assert( pIdx->aSortOrder!=0 );
assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 ); assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
assert( pIdx->aSortOrder[i]==0 || pIdx->aSortOrder[i]==1 ); assert( iSortOrder==0 || iSortOrder==1 );
termSortOrder = pIdx->aSortOrder[i] ^ pTerm->sortOrder; termSortOrder = iSortOrder ^ pTerm->sortOrder;
if( i>nEqCol ){ if( i>nEqCol ){
if( termSortOrder!=sortOrder ){ if( termSortOrder!=sortOrder ){
/* Indices can only be used if all ORDER BY terms past the /* Indices can only be used if all ORDER BY terms past the
@ -901,13 +941,25 @@ static int isSortingIndex(
} }
j++; j++;
pTerm++; pTerm++;
if( iColumn<0 ){
/* If the indexed column is the primary key and everything matches
** so far, then we are assured that the index can be used to sort
** because the primary key is unique and so none of the other columns
** will make any difference
*/
j = nTerm;
}
} }
/* The index can be used for sorting if all terms of the ORDER BY clause
** are covered.
*/
if( j>=nTerm ){
*pbRev = sortOrder!=0; *pbRev = sortOrder!=0;
if( j>=nTerm ){
/* All terms of the ORDER BY clause are covered by this index so
** this index can be used for sorting. */
return 1;
}
if( j==pIdx->nColumn && pIdx->onError!=OE_None ){
/* All terms of this index match some prefix of the ORDER BY clause
** and this index is UNIQUE, so this index can be used for sorting. */
return 1; return 1;
} }
return 0; return 0;
@ -928,8 +980,7 @@ static int sortableByRowid(
assert( pOrderBy!=0 ); assert( pOrderBy!=0 );
assert( pOrderBy->nExpr>0 ); assert( pOrderBy->nExpr>0 );
p = pOrderBy->a[0].pExpr; p = pOrderBy->a[0].pExpr;
if( pOrderBy->nExpr==1 && p->op==TK_COLUMN && p->iTable==base if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1 ){
&& p->iColumn==-1 ){
*pbRev = pOrderBy->a[0].sortOrder; *pbRev = pOrderBy->a[0].sortOrder;
return 1; return 1;
} }
@ -1232,6 +1283,7 @@ static double bestIndex(
int rev; /* True to scan in reverse order */ int rev; /* True to scan in reverse order */
int flags; /* Flags associated with pProbe */ int flags; /* Flags associated with pProbe */
int nEq; /* Number of == or IN constraints */ int nEq; /* Number of == or IN constraints */
int eqTermMask; /* Mask of valid equality operators */
double cost; /* Cost of using pProbe */ double cost; /* Cost of using pProbe */
TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady)); TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
@ -1323,6 +1375,17 @@ static double bestIndex(
bestFlags = flags; bestFlags = flags;
} }
/* If the pSrc table is the right table of a LEFT JOIN then we may not
** use an index to satisfy IS NULL constraints on that table. This is
** because columns might end up being NULL if the table does not match -
** a circumstance which the index cannot help us discover. Ticket #2177.
*/
if( (pSrc->jointype & JT_LEFT)!=0 ){
eqTermMask = WO_EQ|WO_IN;
}else{
eqTermMask = WO_EQ|WO_IN|WO_ISNULL;
}
/* Look at each index. /* Look at each index.
*/ */
for(; pProbe; pProbe=pProbe->pNext){ for(; pProbe; pProbe=pProbe->pNext){
@ -1337,7 +1400,7 @@ static double bestIndex(
flags = 0; flags = 0;
for(i=0; i<pProbe->nColumn; i++){ for(i=0; i<pProbe->nColumn; i++){
int j = pProbe->aiColumn[i]; int j = pProbe->aiColumn[i];
pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe); pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pProbe);
if( pTerm==0 ) break; if( pTerm==0 ) break;
flags |= WHERE_COLUMN_EQ; flags |= WHERE_COLUMN_EQ;
if( pTerm->eOperator & WO_IN ){ if( pTerm->eOperator & WO_IN ){
@ -1431,7 +1494,7 @@ static double bestIndex(
*ppIndex = bestIdx; *ppIndex = bestIdx;
TRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n", TRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq)); bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq));
*pFlags = bestFlags; *pFlags = bestFlags | eqTermMask;
*pnEq = bestNEq; *pnEq = bestNEq;
return lowestCost; return lowestCost;
} }
@ -1476,30 +1539,18 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
} }
/* /*
** Generate code that builds a probe for an index. Details: ** Generate code that builds a probe for an index.
**
** * Check the top nColumn entries on the stack. If any
** of those entries are NULL, jump immediately to brk,
** which is the loop exit, since no index entry will match
** if any part of the key is NULL. Pop (nColumn+nExtra)
** elements from the stack.
**
** * Construct a probe entry from the top nColumn entries in
** the stack with affinities appropriate for index pIdx.
** Only nColumn elements are popped from the stack in this case
** (by OP_MakeRecord).
** **
** There should be nColumn values on the stack. The index
** to be probed is pIdx. Pop the values from the stack and
** replace them all with a single record that is the index
** problem.
*/ */
static void buildIndexProbe( static void buildIndexProbe(
Vdbe *v, Vdbe *v, /* Generate code into this VM */
int nColumn, int nColumn, /* The number of columns to check for NULL */
int nExtra, Index *pIdx /* Index that we will be searching */
int brk,
Index *pIdx
){ ){
sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
sqlite3IndexAffinityStr(v, pIdx); sqlite3IndexAffinityStr(v, pIdx);
} }
@ -1523,15 +1574,17 @@ static void codeEqualityTerm(
WhereLevel *pLevel /* When level of the FROM clause we are working on */ WhereLevel *pLevel /* When level of the FROM clause we are working on */
){ ){
Expr *pX = pTerm->pExpr; Expr *pX = pTerm->pExpr;
if( pX->op!=TK_IN ){ Vdbe *v = pParse->pVdbe;
assert( pX->op==TK_EQ ); if( pX->op==TK_EQ ){
sqlite3ExprCode(pParse, pX->pRight); sqlite3ExprCode(pParse, pX->pRight);
}else if( pX->op==TK_ISNULL ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
}else{ }else{
int iTab; int iTab;
int *aIn; int *aIn;
Vdbe *v = pParse->pVdbe;
assert( pX->op==TK_IN );
sqlite3CodeSubselect(pParse, pX); sqlite3CodeSubselect(pParse, pX);
iTab = pX->iTable; iTab = pX->iTable;
sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
@ -1603,17 +1656,20 @@ static void codeAllEqualityTerms(
/* Evaluate the equality constraints /* Evaluate the equality constraints
*/ */
for(j=0; j<pIdx->nColumn; j++){ assert( pIdx->nColumn>=nEq );
for(j=0; j<nEq; j++){
int k = pIdx->aiColumn[j]; int k = pIdx->aiColumn[j];
pTerm = findTerm(pWC, iCur, k, notReady, WO_EQ|WO_IN, pIdx); pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
if( pTerm==0 ) break; if( pTerm==0 ) break;
assert( (pTerm->flags & TERM_CODED)==0 ); assert( (pTerm->flags & TERM_CODED)==0 );
codeEqualityTerm(pParse, pTerm, brk, pLevel); codeEqualityTerm(pParse, pTerm, brk, pLevel);
if( (pTerm->eOperator & WO_ISNULL)==0 ){
sqlite3VdbeAddOp(v, OP_IsNull, termsInMem ? -1 : -(j+1), brk);
}
if( termsInMem ){ if( termsInMem ){
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1); sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1);
} }
} }
assert( j==nEq );
/* Make sure all the constraint values are on the top of the stack /* Make sure all the constraint values are on the top of the stack
*/ */
@ -1850,8 +1906,7 @@ WhereInfo *sqlite3WhereBegin(
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){ for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */ int doNotReorder; /* True if this table should not be reordered */
doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0 doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
|| (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0);
if( once && doNotReorder ) break; if( once && doNotReorder ) break;
m = getMask(&maskSet, pTabItem->iCursor); m = getMask(&maskSet, pTabItem->iCursor);
if( (m & notReady)==0 ){ if( (m & notReady)==0 ){
@ -1986,7 +2041,9 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum, sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,
(char*)pKey, P3_KEYINFO_HANDOFF); (char*)pKey, P3_KEYINFO_HANDOFF);
} }
if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){ if( (pLevel->flags & (WHERE_IDX_ONLY|WHERE_COLUMN_RANGE))!=0 ){
/* Only call OP_SetNumColumns on the index if we might later use
** OP_Column on the index. */
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1); sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
} }
sqlite3CodeVerifySchema(pParse, iDb); sqlite3CodeVerifySchema(pParse, iDb);
@ -2025,7 +2082,7 @@ WhereInfo *sqlite3WhereBegin(
** initialize a memory cell that records if this table matches any ** initialize a memory cell that records if this table matches any
** row of the left table of the join. ** row of the left table of the join.
*/ */
if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){ if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){
if( !pParse->nMem ) pParse->nMem++; if( !pParse->nMem ) pParse->nMem++;
pLevel->iLeftJoin = pParse->nMem++; pLevel->iLeftJoin = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin); sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin);
@ -2159,7 +2216,6 @@ WhereInfo *sqlite3WhereBegin(
int btmEq=0; /* True if btm limit uses ==. False if strictly > */ int btmEq=0; /* True if btm limit uses ==. False if strictly > */
int topOp, btmOp; /* Operators for the top and bottom search bounds */ int topOp, btmOp; /* Operators for the top and bottom search bounds */
int testOp; int testOp;
int nNotNull; /* Number of rows of index that must be non-NULL */
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0; int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0; int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
@ -2181,7 +2237,6 @@ WhereInfo *sqlite3WhereBegin(
** operator and the top bound is a < or <= operator. For a descending ** operator and the top bound is a < or <= operator. For a descending
** index the operators are reversed. ** index the operators are reversed.
*/ */
nNotNull = nEq + topLimit;
if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){ if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){
topOp = WO_LT|WO_LE; topOp = WO_LT|WO_LE;
btmOp = WO_GT|WO_GE; btmOp = WO_GT|WO_GE;
@ -2206,6 +2261,7 @@ WhereInfo *sqlite3WhereBegin(
pX = pTerm->pExpr; pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 ); assert( (pTerm->flags & TERM_CODED)==0 );
sqlite3ExprCode(pParse, pX->pRight); sqlite3ExprCode(pParse, pX->pRight);
sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), brk);
topEq = pTerm->eOperator & (WO_LE|WO_GE); topEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm); disableTerm(pLevel, pTerm);
testOp = OP_IdxGE; testOp = OP_IdxGE;
@ -2216,7 +2272,7 @@ WhereInfo *sqlite3WhereBegin(
if( testOp!=OP_Noop ){ if( testOp!=OP_Noop ){
int nCol = nEq + topLimit; int nCol = nEq + topLimit;
pLevel->iMem = pParse->nMem++; pLevel->iMem = pParse->nMem++;
buildIndexProbe(v, nCol, nEq, brk, pIdx); buildIndexProbe(v, nCol, pIdx);
if( bRev ){ if( bRev ){
int op = topEq ? OP_MoveLe : OP_MoveLt; int op = topEq ? OP_MoveLe : OP_MoveLt;
sqlite3VdbeAddOp(v, op, iIdxCur, brk); sqlite3VdbeAddOp(v, op, iIdxCur, brk);
@ -2244,6 +2300,7 @@ WhereInfo *sqlite3WhereBegin(
pX = pTerm->pExpr; pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 ); assert( (pTerm->flags & TERM_CODED)==0 );
sqlite3ExprCode(pParse, pX->pRight); sqlite3ExprCode(pParse, pX->pRight);
sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), brk);
btmEq = pTerm->eOperator & (WO_LE|WO_GE); btmEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm); disableTerm(pLevel, pTerm);
}else{ }else{
@ -2251,7 +2308,7 @@ WhereInfo *sqlite3WhereBegin(
} }
if( nEq>0 || btmLimit ){ if( nEq>0 || btmLimit ){
int nCol = nEq + btmLimit; int nCol = nEq + btmLimit;
buildIndexProbe(v, nCol, 0, brk, pIdx); buildIndexProbe(v, nCol, pIdx);
if( bRev ){ if( bRev ){
pLevel->iMem = pParse->nMem++; pLevel->iMem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
@ -2278,8 +2335,10 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC); sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
} }
} }
sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0); if( topLimit | btmLimit ){
sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont); sqlite3VdbeAddOp(v, OP_Column, iIdxCur, nEq);
sqlite3VdbeAddOp(v, OP_IsNull, 1, cont);
}
if( !omitTable ){ if( !omitTable ){
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0); sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
@ -2305,7 +2364,7 @@ WhereInfo *sqlite3WhereBegin(
/* Generate a single key that will be used to both start and terminate /* Generate a single key that will be used to both start and terminate
** the search ** the search
*/ */
buildIndexProbe(v, nEq, 0, brk, pIdx); buildIndexProbe(v, nEq, pIdx);
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0); sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
/* Generate code (1) to move to the first matching element of the table. /* Generate code (1) to move to the first matching element of the table.
@ -2326,8 +2385,6 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC); sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC);
pLevel->op = OP_Next; pLevel->op = OP_Next;
} }
sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq, cont);
if( !omitTable ){ if( !omitTable ){
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0); sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);