Updated SQLite to 3.3.13 - why? I have no idea

This commit is contained in:
Scott Ehlert 2007-03-21 20:19:37 +00:00
parent eaa4122c5a
commit a004e906dd
55 changed files with 9336 additions and 3963 deletions

View File

@ -20,16 +20,13 @@ CPP_OBJECTS = basic_sql.cpp handles.cpp module.cpp threading.cpp sdk/amxxmodule.
CPP_OBJECTS += thread/BaseWorker.cpp thread/ThreadWorker.cpp thread/PosixThreads.cpp CPP_OBJECTS += thread/BaseWorker.cpp thread/ThreadWorker.cpp thread/PosixThreads.cpp
CPP_OBJECTS += sqlitepp/SqliteQuery.cpp sqlitepp/SqliteResultSet.cpp sqlitepp/SqliteDatabase.cpp sqlitepp/SqliteDriver.cpp CPP_OBJECTS += sqlitepp/SqliteQuery.cpp sqlitepp/SqliteResultSet.cpp sqlitepp/SqliteDatabase.cpp sqlitepp/SqliteDriver.cpp
C_OBJECTS = $(SQL)/attach.c $(SQL)/auth.c $(SQL)/btree.c $(SQL)/build.c \ C_OBJECTS = $(SQL)/alter.c $(SQL)/analyze.c $(SQL)/attach.c $(SQL)/auth.c $(SQL)/btree.c $(SQL)/build.c \
$(SQL)/date.c $(SQL)/delete.c $(SQL)/func.c $(SQL)/hash.c \ $(SQL)/callback.c $(SQL)/complete.c $(SQL)/date.c $(SQL)/delete.c $(SQL)/expr.c $(SQL)/func.c \
$(SQL)/insert.c $(SQL)/legacy.c $(SQL)/main.c $(SQL)/opcodes.c \ $(SQL)/hash.c $(SQL)/insert.c $(SQL)/legacy.c $(SQL)/loadext.c $(SQL)/main.c $(SQL)/opcodes.c \
$(SQL)/os.c $(SQL)/os_unix.c $(SQL)/pager.c $(SQL)/parse.c \ $(SQL)/os.c $(SQL)/os_unix.c $(SQL)/pager.c $(SQL)/parse.c $(SQL)/pragma.c $(SQL)/prepare.c \
$(SQL)/pragma.c $(SQL)/printf.c $(SQL)/random.c $(SQL)/select.c \ $(SQL)/printf.c $(SQL)/random.c $(SQL)/select.c $(SQL)/table.c $(SQL)/tokenize.c $(SQL)/trigger.c \
$(SQL)/table.c $(SQL)/tokenize.c $(SQL)/trigger.c $(SQL)/update.c \ $(SQL)/update.c $(SQL)/utf.c $(SQL)/util.c $(SQL)/vacuum.c $(SQL)/vdbe.c $(SQL)/vdbeapi.c \
$(SQL)/utf.c $(SQL)/util.c $(SQL)/vacuum.c $(SQL)/vdbe.c \ $(SQL)/vdbeaux.c $(SQL)/vdbefifo.c $(SQL)/vdbemem.c $(SQL)/vtab.c $(SQL)/where.c \
$(SQL)/vdbeapi.c $(SQL)/vdbeaux.c $(SQL)/vdbemem.c $(SQL)/where.c \
$(SQL)/prepare.c $(SQL)/expr.c $(SQL)/callback.c $(SQL)/alter.c \
$(SQL)/vdbefifo.c $(SQL)/complete.c $(SQL)/analyze.c
CFLAGS = -Wall -Werror CFLAGS = -Wall -Werror
CPPFLAGS = -Wall -Wno-non-virtual-dtor -Werror CPPFLAGS = -Wall -Wno-non-virtual-dtor -Werror

View File

@ -294,6 +294,9 @@
<File <File
RelativePath="..\sqlite-source\legacy.c"> RelativePath="..\sqlite-source\legacy.c">
</File> </File>
<File
RelativePath="..\sqlite-source\loadext.c">
</File>
<File <File
RelativePath="..\sqlite-source\main.c"> RelativePath="..\sqlite-source\main.c">
</File> </File>
@ -345,6 +348,9 @@
<File <File
RelativePath="..\sqlite-source\sqlite3.h"> RelativePath="..\sqlite-source\sqlite3.h">
</File> </File>
<File
RelativePath="..\sqlite-source\sqlite3ext.h">
</File>
<File <File
RelativePath="..\sqlite-source\sqliteInt.h"> RelativePath="..\sqlite-source\sqliteInt.h">
</File> </File>
@ -390,6 +396,9 @@
<File <File
RelativePath="..\sqlite-source\vdbemem.c"> RelativePath="..\sqlite-source\vdbemem.c">
</File> </File>
<File
RelativePath="..\sqlite-source\vtab.c">
</File>
<File <File
RelativePath="..\sqlite-source\where.c"> RelativePath="..\sqlite-source\where.c">
</File> </File>

View File

@ -407,6 +407,10 @@
RelativePath="..\sqlite-source\legacy.c" RelativePath="..\sqlite-source\legacy.c"
> >
</File> </File>
<File
RelativePath="..\sqlite-source\loadext.c"
>
</File>
<File <File
RelativePath="..\sqlite-source\main.c" RelativePath="..\sqlite-source\main.c"
> >
@ -475,6 +479,10 @@
RelativePath="..\sqlite-source\sqlite3.h" RelativePath="..\sqlite-source\sqlite3.h"
> >
</File> </File>
<File
RelativePath="..\sqlite-source\sqlite3ext.h"
>
</File>
<File <File
RelativePath="..\sqlite-source\sqliteInt.h" RelativePath="..\sqlite-source\sqliteInt.h"
> >
@ -535,6 +543,10 @@
RelativePath="..\sqlite-source\vdbemem.c" RelativePath="..\sqlite-source\vdbemem.c"
> >
</File> </File>
<File
RelativePath="..\sqlite-source\vtab.c"
>
</File>
<File <File
RelativePath="..\sqlite-source\where.c" RelativePath="..\sqlite-source\where.c"
> >

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.
*/ */
@ -272,6 +272,12 @@ void sqlite3AlterRenameTable(
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_rename_table; if( !pTab ) goto exit_rename_table;
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
goto exit_rename_table;
}
#endif
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName; zDb = db->aDb[iDb].zName;
@ -512,6 +518,13 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_begin_add_column; if( !pTab ) goto exit_begin_add_column;
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
goto exit_begin_add_column;
}
#endif
/* Make sure this is not an attempt to ALTER a view. */ /* Make sure this is not an attempt to ALTER a view. */
if( pTab->pSelect ){ if( pTab->pSelect ){
sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); sqlite3ErrorMsg(pParse, "Cannot add a column to a view");

View File

@ -73,6 +73,8 @@ static void attachFunc(
zFile = (const char *)sqlite3_value_text(argv[0]); zFile = (const char *)sqlite3_value_text(argv[0]);
zName = (const char *)sqlite3_value_text(argv[1]); zName = (const char *)sqlite3_value_text(argv[1]);
if( zFile==0 ) zFile = "";
if( zName==0 ) zName = "";
/* Check for the following errors: /* Check for the following errors:
** **
@ -82,7 +84,7 @@ static void attachFunc(
*/ */
if( db->nDb>=MAX_ATTACHED+2 ){ if( db->nDb>=MAX_ATTACHED+2 ){
sqlite3_snprintf( sqlite3_snprintf(
127, zErr, "too many attached databases - max %d", MAX_ATTACHED sizeof(zErr), zErr, "too many attached databases - max %d", MAX_ATTACHED
); );
goto attach_error; goto attach_error;
} }
@ -92,8 +94,8 @@ static void attachFunc(
} }
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zName; char *z = db->aDb[i].zName;
if( z && sqlite3StrICmp(z, zName)==0 ){ if( z && zName && sqlite3StrICmp(z, zName)==0 ){
sqlite3_snprintf(127, zErr, "database %s is already in use", zName); sqlite3_snprintf(sizeof(zErr), zErr, "database %s is already in use", zName);
goto attach_error; goto attach_error;
} }
} }
@ -186,10 +188,10 @@ static void attachFunc(
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, 0);
db->nDb = iDb; db->nDb = iDb;
if( rc==SQLITE_NOMEM ){ if( rc==SQLITE_NOMEM ){
sqlite3MallocFailed(); if( !sqlite3MallocFailed() ) sqlite3FailedMalloc();
sqlite3_snprintf(127, zErr, "out of memory"); sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
}else{ }else{
sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile); sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
} }
goto attach_error; goto attach_error;
} }
@ -226,7 +228,7 @@ static void detachFunc(
Db *pDb = 0; Db *pDb = 0;
char zErr[128]; char zErr[128];
assert(zName); if( zName==0 ) zName = "";
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i]; pDb = &db->aDb[i];
if( pDb->pBt==0 ) continue; if( pDb->pBt==0 ) continue;
@ -234,17 +236,21 @@ static void detachFunc(
} }
if( i>=db->nDb ){ if( i>=db->nDb ){
sqlite3_snprintf(sizeof(zErr), zErr, "no such database: %s", zName); sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName);
goto detach_error; goto detach_error;
} }
if( i<2 ){ if( i<2 ){
sqlite3_snprintf(sizeof(zErr), zErr, "cannot detach database %s", zName); sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
goto detach_error; goto detach_error;
} }
if( !db->autoCommit ){ if( !db->autoCommit ){
strcpy(zErr, "cannot DETACH database within transaction"); strcpy(zErr, "cannot DETACH database within transaction");
goto detach_error; goto detach_error;
} }
if( sqlite3BtreeIsInReadTrans(pDb->pBt) ){
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
goto detach_error;
}
sqlite3BtreeClose(pDb->pBt); sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0; pDb->pBt = 0;

View File

@ -182,8 +182,10 @@ int sqlite3AuthCheck(
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
int rc; int rc;
/* Don't do any authorization checks if the database is initialising. */ /* Don't do any authorization checks if the database is initialising
if( db->init.busy ){ ** or if the parser is being invoked from within sqlite3_declare_vtab.
*/
if( db->init.busy || IN_DECLARE_VTAB ){
return SQLITE_OK; return SQLITE_OK;
} }

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,16 +421,17 @@ 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 */
#else #else
# define TRACE(X) # define TRACE(X)
#endif #endif
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((int)pCur->nKey);
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, (u32)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((int)pCur->nKey);
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, (u32)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;
} }
@ -2367,7 +2278,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
MemPage *pFreeMemPage = 0; /* "" */ MemPage *pFreeMemPage = 0; /* "" */
#ifndef NDEBUG #ifndef NDEBUG
int nRef = *sqlite3pager_stats(pPager); int nRef = sqlite3pager_refcount(pPager);
#endif #endif
assert( pBt->autoVacuum ); assert( pBt->autoVacuum );
@ -2475,7 +2386,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
assert( finSize!=PENDING_BYTE_PAGE(pBt) ); assert( finSize!=PENDING_BYTE_PAGE(pBt) );
autovacuum_out: autovacuum_out:
assert( nRef==*sqlite3pager_stats(pPager) ); assert( nRef==sqlite3pager_refcount(pPager) );
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3pager_rollback(pPager); sqlite3pager_rollback(pPager);
} }
@ -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.
@ -5984,6 +5890,7 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
** aResult[7] = Header size in bytes ** aResult[7] = Header size in bytes
** aResult[8] = Local payload size ** aResult[8] = Local payload size
** aResult[9] = Parent page number ** aResult[9] = Parent page number
** aResult[10]= Page number of the first overflow page
** **
** This routine is used for testing and debugging only. ** This routine is used for testing and debugging only.
*/ */
@ -5997,14 +5904,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;
@ -6034,6 +5939,11 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
}else{ }else{
aResult[9] = pPage->pParent->pgno; aResult[9] = pPage->pParent->pgno;
} }
if( tmpCur.info.iOverflow ){
aResult[10] = get4byte(&tmpCur.info.pCell[tmpCur.info.iOverflow]);
}else{
aResult[10] = 0;
}
releaseTempCursor(&tmpCur); releaseTempCursor(&tmpCur);
return SQLITE_OK; return SQLITE_OK;
} }
@ -6057,7 +5967,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 +5984,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 +6070,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 +6182,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,19 +6297,28 @@ 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;
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
nRef = *sqlite3pager_stats(pBt->pPager); nRef = sqlite3pager_refcount(pBt->pPager);
if( lockBtreeWithRetry(p)!=SQLITE_OK ){ if( lockBtreeWithRetry(p)!=SQLITE_OK ){
return sqliteStrDup("Unable to acquire a read lock on the database"); return sqliteStrDup("Unable to acquire a read lock on the database");
} }
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 +6326,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 +6344,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 +6356,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);
@ -6454,16 +6379,17 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure this analysis did not leave any unref() pages /* Make sure this analysis did not leave any unref() pages
*/ */
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
if( nRef != *sqlite3pager_stats(pBt->pPager) ){ if( nRef != sqlite3pager_refcount(pBt->pPager) ){
checkAppendMsg(&sCheck, 0, checkAppendMsg(&sCheck, 0,
"Outstanding page count goes from %d to %d during this analysis", "Outstanding page count goes from %d to %d during this analysis",
nRef, *sqlite3pager_stats(pBt->pPager) nRef, sqlite3pager_refcount(pBt->pPager)
); );
} }
/* 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 +6448,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++){
@ -6558,6 +6483,13 @@ int sqlite3BtreeIsInStmt(Btree *p){
return (p->pBt && p->pBt->inStmt); return (p->pBt && p->pBt->inStmt);
} }
/*
** Return non-zero if a read (or write) transaction is active.
*/
int sqlite3BtreeIsInReadTrans(Btree *p){
return (p && (p->inTrans!=TRANS_NONE));
}
/* /*
** This call is a no-op if no write-transaction is currently active on pBt. ** This call is a no-op if no write-transaction is currently active on pBt.
** **

View File

@ -75,6 +75,7 @@ int sqlite3BtreeRollbackStmt(Btree*);
int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*); int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*); int sqlite3BtreeIsInStmt(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeSync(Btree*, const char *zMaster); int sqlite3BtreeSync(Btree*, const char *zMaster);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *); int sqlite3BtreeSchemaLocked(Btree *);
@ -130,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

@ -164,6 +164,12 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pParse->pVirtualLock ){
char *vtab = (char *)pParse->pVirtualLock->pVtab;
sqlite3VdbeOp3(v, OP_VBegin, 0, 0, vtab, P3_VTAB);
}
#endif
/* Once all the cookies have been verified and transactions opened, /* Once all the cookies have been verified and transactions opened,
** obtain the required table-locks. This is a no-op unless the ** obtain the required table-locks. This is a no-op unless the
@ -533,6 +539,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
#ifndef SQLITE_OMIT_CHECK #ifndef SQLITE_OMIT_CHECK
sqlite3ExprDelete(pTable->pCheck); sqlite3ExprDelete(pTable->pCheck);
#endif #endif
sqlite3VtabClear(pTable);
sqliteFree(pTable); sqliteFree(pTable);
} }
@ -710,6 +717,7 @@ void sqlite3StartTable(
Token *pName2, /* Second part of the name of the table or view */ Token *pName2, /* Second part of the name of the table or view */
int isTemp, /* True if this is a TEMP table */ int isTemp, /* True if this is a TEMP table */
int isView, /* True if this is a VIEW */ int isView, /* True if this is a VIEW */
int isVirtual, /* True if this is a VIRTUAL table */
int noErr /* Do nothing if table already exists */ int noErr /* Do nothing if table already exists */
){ ){
Table *pTable; Table *pTable;
@ -773,7 +781,7 @@ void sqlite3StartTable(
code = SQLITE_CREATE_TABLE; code = SQLITE_CREATE_TABLE;
} }
} }
if( sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){ if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
goto begin_table_error; goto begin_table_error;
} }
} }
@ -781,8 +789,12 @@ void sqlite3StartTable(
/* Make sure the new table name does not collide with an existing /* Make sure the new table name does not collide with an existing
** index or table name in the same database. Issue an error message if ** index or table name in the same database. Issue an error message if
** it does. ** it does. The exception is if the statement being parsed was passed
** to an sqlite3_declare_vtab() call. In that case only the column names
** and types will be used, so there is no need to test for namespace
** collisions.
*/ */
if( !IN_DECLARE_VTAB ){
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto begin_table_error; goto begin_table_error;
} }
@ -797,6 +809,8 @@ void sqlite3StartTable(
sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
goto begin_table_error; goto begin_table_error;
} }
}
pTable = sqliteMalloc( sizeof(Table) ); pTable = sqliteMalloc( sizeof(Table) );
if( pTable==0 ){ if( pTable==0 ){
pParse->rc = SQLITE_NOMEM; pParse->rc = SQLITE_NOMEM;
@ -804,10 +818,7 @@ void sqlite3StartTable(
goto begin_table_error; goto begin_table_error;
} }
pTable->zName = zName; pTable->zName = zName;
pTable->nCol = 0;
pTable->aCol = 0;
pTable->iPKey = -1; pTable->iPKey = -1;
pTable->pIndex = 0;
pTable->pSchema = db->aDb[iDb].pSchema; pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1; pTable->nRef = 1;
if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable); if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
@ -836,6 +847,12 @@ void sqlite3StartTable(
int fileFormat; int fileFormat;
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( isVirtual ){
sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
}
#endif
/* If the file format and encoding in the database have not been set, /* If the file format and encoding in the database have not been set,
** set them now. ** set them now.
*/ */
@ -843,7 +860,7 @@ void sqlite3StartTable(
lbl = sqlite3VdbeMakeLabel(v); lbl = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_If, 0, lbl); sqlite3VdbeAddOp(v, OP_If, 0, lbl);
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
1 : SQLITE_DEFAULT_FILE_FORMAT; 1 : SQLITE_MAX_FILE_FORMAT;
sqlite3VdbeAddOp(v, OP_Integer, fileFormat, 0); sqlite3VdbeAddOp(v, OP_Integer, fileFormat, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0); sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0);
@ -858,8 +875,8 @@ void sqlite3StartTable(
** The rowid value is needed by the code that sqlite3EndTable will ** The rowid value is needed by the code that sqlite3EndTable will
** generate. ** generate.
*/ */
#ifndef SQLITE_OMIT_VIEW #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
if( isView ){ if( isView || isVirtual ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}else }else
#endif #endif
@ -1060,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);
@ -1095,7 +1116,7 @@ void sqlite3AddPrimaryKey(
Table *pTab = pParse->pNewTable; Table *pTab = pParse->pNewTable;
char *zType = 0; char *zType = 0;
int iCol = -1, i; int iCol = -1, i;
if( pTab==0 ) goto primary_key_exit; if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
if( pTab->hasPrimKey ){ if( pTab->hasPrimKey ){
sqlite3ErrorMsg(pParse, sqlite3ErrorMsg(pParse,
"table \"%s\" has more than one primary key", pTab->zName); "table \"%s\" has more than one primary key", pTab->zName);
@ -1150,7 +1171,7 @@ void sqlite3AddCheckConstraint(
){ ){
#ifndef SQLITE_OMIT_CHECK #ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable; Table *pTab = pParse->pNewTable;
if( pTab ){ if( pTab && !IN_DECLARE_VTAB ){
/* The CHECK expression must be duplicated so that tokens refer /* The CHECK expression must be duplicated so that tokens refer
** to malloced space and not the (ephemeral) text of the CREATE TABLE ** to malloced space and not the (ephemeral) text of the CREATE TABLE
** statement */ ** statement */
@ -1201,6 +1222,10 @@ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
** If no versions of the requested collations sequence are available, or ** If no versions of the requested collations sequence are available, or
** another error occurs, NULL is returned and an error message written into ** another error occurs, NULL is returned and an error message written into
** pParse. ** pParse.
**
** This routine is a wrapper around sqlite3FindCollSeq(). This routine
** invokes the collation factory if the named collation cannot be found
** and generates an error message.
*/ */
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
@ -1372,7 +1397,7 @@ void sqlite3EndTable(
assert( !db->init.busy || !pSelect ); assert( !db->init.busy || !pSelect );
iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); iDb = sqlite3SchemaToIndex(db, p->pSchema);
#ifndef SQLITE_OMIT_CHECK #ifndef SQLITE_OMIT_CHECK
/* Resolve names in all CHECK constraint expressions. /* Resolve names in all CHECK constraint expressions.
@ -1569,7 +1594,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;
@ -1584,7 +1610,7 @@ void sqlite3CreateView(
sqlite3SelectDelete(pSelect); sqlite3SelectDelete(pSelect);
return; return;
} }
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 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);
@ -1633,7 +1659,7 @@ void sqlite3CreateView(
} }
#endif /* SQLITE_OMIT_VIEW */ #endif /* SQLITE_OMIT_VIEW */
#ifndef SQLITE_OMIT_VIEW #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
/* /*
** The Table structure pTable is really a VIEW. Fill in the names of ** The Table structure pTable is really a VIEW. Fill in the names of
** the columns of the view in the pTable structure. Return the number ** the columns of the view in the pTable structure. Return the number
@ -1647,6 +1673,14 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable ); assert( pTable );
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( sqlite3VtabCallConnect(pParse, pTable) ){
return SQLITE_ERROR;
}
if( IsVirtual(pTable) ) return 0;
#endif
#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are /* A positive nCol means the columns names for this view are
** already known. ** already known.
*/ */
@ -1699,9 +1733,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
} else { } else {
nErr++; nErr++;
} }
#endif /* SQLITE_OMIT_VIEW */
return nErr; return nErr;
} }
#endif /* SQLITE_OMIT_VIEW */ #endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifndef SQLITE_OMIT_VIEW #ifndef SQLITE_OMIT_VIEW
/* /*
@ -1873,6 +1908,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
int code; int code;
const char *zTab = SCHEMA_TABLE(iDb); const char *zTab = SCHEMA_TABLE(iDb);
const char *zDb = db->aDb[iDb].zName; const char *zDb = db->aDb[iDb].zName;
const char *zArg2 = 0;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
goto exit_drop_table; goto exit_drop_table;
} }
@ -1882,6 +1918,14 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
}else{ }else{
code = SQLITE_DROP_VIEW; code = SQLITE_DROP_VIEW;
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE
}else if( IsVirtual(pTab) ){
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto exit_drop_table;
}
code = SQLITE_DROP_VTABLE;
zArg2 = pTab->pMod->zName;
#endif
}else{ }else{
if( !OMIT_TEMPDB && iDb==1 ){ if( !OMIT_TEMPDB && iDb==1 ){
code = SQLITE_DROP_TEMP_TABLE; code = SQLITE_DROP_TEMP_TABLE;
@ -1889,7 +1933,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
code = SQLITE_DROP_TABLE; code = SQLITE_DROP_TABLE;
} }
} }
if( sqlite3AuthCheck(pParse, code, pTab->zName, 0, zDb) ){ if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
goto exit_drop_table; goto exit_drop_table;
} }
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
@ -1925,6 +1969,15 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
Db *pDb = &db->aDb[iDb]; Db *pDb = &db->aDb[iDb];
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
}
}
#endif
/* Drop all triggers associated with the table being dropped. Code /* Drop all triggers associated with the table being dropped. Code
** is generated to remove entries from sqlite_master and/or ** is generated to remove entries from sqlite_master and/or
** sqlite_temp_master if required. ** sqlite_temp_master if required.
@ -1961,13 +2014,16 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
sqlite3NestedParse(pParse, sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
if( !isView ){ if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab); destroyTable(pParse, pTab);
} }
/* Remove the table entry from SQLite's internal schema and modify /* Remove the table entry from SQLite's internal schema and modify
** the schema cookie. ** the schema cookie.
*/ */
if( IsVirtual(pTab) ){
sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0);
}
sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
sqlite3ChangeCookie(db, v, iDb); sqlite3ChangeCookie(db, v, iDb);
} }
@ -2011,7 +2067,7 @@ void sqlite3CreateForeignKey(
char *z; char *z;
assert( pTo!=0 ); assert( pTo!=0 );
if( p==0 || pParse->nErr ) goto fk_end; if( p==0 || pParse->nErr || IN_DECLARE_VTAB ) goto fk_end;
if( pFromCol==0 ){ if( pFromCol==0 ){
int iCol = p->nCol-1; int iCol = p->nCol-1;
if( iCol<0 ) goto fk_end; if( iCol<0 ) goto fk_end;
@ -2215,7 +2271,7 @@ void sqlite3CreateIndex(
int nExtra = 0; int nExtra = 0;
char *zExtra; char *zExtra;
if( pParse->nErr || sqlite3MallocFailed() ){ if( pParse->nErr || sqlite3MallocFailed() || IN_DECLARE_VTAB ){
goto exit_create_index; goto exit_create_index;
} }
@ -2272,6 +2328,12 @@ void sqlite3CreateIndex(
goto exit_create_index; goto exit_create_index;
} }
#endif #endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
sqlite3ErrorMsg(pParse, "virtual tables may not be indexed");
goto exit_create_index;
}
#endif
/* /*
** Find the name of the index. Make sure there is not already another ** Find the name of the index. Make sure there is not already another
@ -2399,7 +2461,7 @@ void sqlite3CreateIndex(
const char *zColName = pListItem->zName; const char *zColName = pListItem->zName;
Column *pTabCol; Column *pTabCol;
int requestedSortOrder; int requestedSortOrder;
char *zColl; /* Collation sequence */ char *zColl; /* Collation sequence name */
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){ for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
@ -2409,6 +2471,12 @@ void sqlite3CreateIndex(
pTab->zName, zColName); pTab->zName, zColName);
goto exit_create_index; goto exit_create_index;
} }
/* TODO: Add a test to make sure that the same column is not named
** more than once within the same index. Only the first instance of
** the column will ever be used by the optimizer. Note that using the
** same column more than once cannot be an error because that would
** break backwards compatibility - it needs to be a warning.
*/
pIndex->aiColumn[i] = j; pIndex->aiColumn[i] = j;
if( pListItem->pExpr ){ if( pListItem->pExpr ){
assert( pListItem->pExpr->pColl ); assert( pListItem->pExpr->pColl );
@ -2638,8 +2706,12 @@ void sqlite3DefaultRowEst(Index *pIdx){
int i; int i;
assert( a!=0 ); assert( a!=0 );
a[0] = 1000000; a[0] = 1000000;
for(i=pIdx->nColumn; i>=1; i--){ for(i=pIdx->nColumn; i>=5; i--){
a[i] = 10; a[i] = 5;
}
while( i>=1 ){
a[i] = 11 - i;
i--;
} }
if( pIdx->onError!=OE_None ){ if( pIdx->onError!=OE_None ){
a[pIdx->nColumn] = 1; a[pIdx->nColumn] = 1;
@ -2878,15 +2950,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.
*/ */
@ -2906,6 +2969,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

@ -195,6 +195,11 @@ static CollSeq *findCollSeqEntry(
** **
** If the entry specified is not found and 'create' is true, then create a ** If the entry specified is not found and 'create' is true, then create a
** new entry. Otherwise return NULL. ** new entry. Otherwise return NULL.
**
** A separate function sqlite3LocateCollSeq() is a wrapper around
** this routine. sqlite3LocateCollSeq() invokes the collation factory
** if necessary and generates an error message if the collating sequence
** cannot be found.
*/ */
CollSeq *sqlite3FindCollSeq( CollSeq *sqlite3FindCollSeq(
sqlite3 *db, sqlite3 *db,
@ -362,6 +367,7 @@ Schema *sqlite3SchemaGet(Btree *pBt){
sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1); sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
p->enc = SQLITE_UTF8;
} }
return p; return p;
} }

View File

@ -231,14 +231,14 @@ static void computeJD(DateTime *p){
A = Y/100; A = Y/100;
B = 2 - A + (A/4); B = 2 - A + (A/4);
X1 = (int)(365.25*(Y+4716)); X1 = (int)(365.25*(Y+4716));
X2 = (int)30.6001*(M+1); X2 = (int)(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;
} }
@ -357,10 +357,11 @@ 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 = (int)(p->rJD + 0.5); Z = (int)(p->rJD + 0.5);
s = (int)((p->rJD + 0.5 - Z)*86400000.0 + 0.5); s = (int)((p->rJD + 0.5 - Z)*86400000.0 + 0.5);
p->s = 0.001*s; p->s = 0.001*s;
s = (int)(p->s); s = (int)p->s;
p->s -= s; p->s -= s;
p->h = s/3600; p->h = s/3600;
s -= p->h*3600; s -= p->h*3600;
@ -393,7 +394,6 @@ static void clearYMD_HMS_TZ(DateTime *p){
static double localtimeOffset(DateTime *p){ static double localtimeOffset(DateTime *p){
DateTime x, y; DateTime x, y;
time_t t; time_t t;
struct tm *pTm;
x = *p; x = *p;
computeYMD_HMS(&x); computeYMD_HMS(&x);
if( x.Y<1971 || x.Y>=2038 ){ if( x.Y<1971 || x.Y>=2038 ){
@ -411,6 +411,20 @@ static double localtimeOffset(DateTime *p){
x.validJD = 0; x.validJD = 0;
computeJD(&x); computeJD(&x);
t = (time_t)((x.rJD-2440587.5)*86400.0 + 0.5); t = (time_t)((x.rJD-2440587.5)*86400.0 + 0.5);
#ifdef HAVE_LOCALTIME_R
{
struct tm sLocal;
localtime_r(&t, &sLocal);
y.Y = sLocal.tm_year + 1900;
y.M = sLocal.tm_mon + 1;
y.D = sLocal.tm_mday;
y.h = sLocal.tm_hour;
y.m = sLocal.tm_min;
y.s = sLocal.tm_sec;
}
#else
{
struct tm *pTm;
sqlite3OsEnterMutex(); sqlite3OsEnterMutex();
pTm = localtime(&t); pTm = localtime(&t);
y.Y = pTm->tm_year + 1900; y.Y = pTm->tm_year + 1900;
@ -420,6 +434,8 @@ static double localtimeOffset(DateTime *p){
y.m = pTm->tm_min; y.m = pTm->tm_min;
y.s = pTm->tm_sec; y.s = pTm->tm_sec;
sqlite3OsLeaveMutex(); sqlite3OsLeaveMutex();
}
#endif
y.validYMD = 1; y.validYMD = 1;
y.validHMS = 1; y.validHMS = 1;
y.validJD = 0; y.validJD = 0;
@ -809,9 +825,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 = (int)x.s; double s = x.s;
int ms = (int)((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;
} }
@ -824,7 +840,7 @@ static void strftimeFunc(
y.M = 1; y.M = 1;
y.D = 1; y.D = 1;
computeJD(&y); computeJD(&y);
nDay = (int)(x.rJD - y.rJD); nDay = (int)(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;
@ -844,7 +860,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;
@ -944,9 +960,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

@ -42,8 +42,12 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
** writable return 0; ** writable return 0;
*/ */
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0 if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
&& pParse->nested==0 ){ && pParse->nested==0)
#ifndef SQLITE_OMIT_VIRTUALTABLE
|| (pTab->pMod && pTab->pMod->pModule->xUpdate==0)
#endif
){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1; return 1;
} }
@ -66,7 +70,9 @@ void sqlite3OpenTable(
Table *pTab, /* The table to be opened */ Table *pTab, /* The table to be opened */
int opcode /* OP_OpenRead or OP_OpenWrite */ int opcode /* OP_OpenRead or OP_OpenWrite */
){ ){
Vdbe *v = sqlite3GetVdbe(p); Vdbe *v;
if( IsVirtual(pTab) ) return;
v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName); sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
@ -100,7 +106,8 @@ void sqlite3DeleteFrom(
AuthContext sContext; /* Authorization context */ AuthContext sContext; /* Authorization context */
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
NameContext sNC; /* Name context to resolve expressions in */ NameContext sNC; /* Name context to resolve expressions in */
int iDb; int iDb; /* Database number */
int memCnt = 0; /* Memory cell used for change counting */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */ int isView; /* True if attempting to delete from a view */
@ -149,7 +156,7 @@ void sqlite3DeleteFrom(
/* If pTab is really a view, make sure it has been initialized. /* If pTab is really a view, make sure it has been initialized.
*/ */
if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto delete_from_cleanup; goto delete_from_cleanup;
} }
@ -190,7 +197,7 @@ void sqlite3DeleteFrom(
*/ */
if( isView ){ if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect); Select *pView = sqlite3SelectDup(pTab->pSelect);
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0); sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView); sqlite3SelectDelete(pView);
} }
@ -198,14 +205,15 @@ void sqlite3DeleteFrom(
** we are counting rows. ** we are counting rows.
*/ */
if( db->flags & SQLITE_CountRows ){ if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0); memCnt = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
} }
/* Special case: A DELETE without a WHERE clause deletes everything. /* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to erase the whole table. Note, however, that ** It is easier just to erase the whole table. Note, however, that
** this means that the row change count will be incorrect. ** this means that the row change count will be incorrect.
*/ */
if( pWhere==0 && !triggers_exist ){ if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){
if( db->flags & SQLITE_CountRows ){ if( db->flags & SQLITE_CountRows ){
/* If counting rows deleted, just count the total number of /* If counting rows deleted, just count the total number of
** entries in the table. */ ** entries in the table. */
@ -215,7 +223,7 @@ void sqlite3DeleteFrom(
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
} }
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
addr2 = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); addr2 = sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
sqlite3VdbeAddOp(v, OP_Next, iCur, addr2); sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
sqlite3VdbeResolveLabel(v, endOfLoop); sqlite3VdbeResolveLabel(v, endOfLoop);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0); sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
@ -231,7 +239,6 @@ void sqlite3DeleteFrom(
} }
} }
} }
/* The usual case: There is a WHERE clause so we have to scan through /* The usual case: There is a WHERE clause so we have to scan through
** the table and pick which records to delete. ** the table and pick which records to delete.
*/ */
@ -243,10 +250,10 @@ void sqlite3DeleteFrom(
/* Remember the rowid of every item to be deleted. /* Remember the rowid of every item to be deleted.
*/ */
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){ if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
} }
/* End the database scan loop. /* End the database scan loop.
@ -304,8 +311,16 @@ void sqlite3DeleteFrom(
} }
/* Delete the row */ /* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
pParse->pVirtualLock = pTab;
sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB);
}else
#endif
{
sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
} }
}
/* If there are row triggers, close all cursors then invoke /* If there are row triggers, close all cursors then invoke
** the AFTER triggers ** the AFTER triggers
@ -327,7 +342,7 @@ void sqlite3DeleteFrom(
sqlite3VdbeResolveLabel(v, end); sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */ /* Close the cursors after the loop if there are no row triggers */
if( !triggers_exist ){ if( !triggers_exist && !IsVirtual(pTab) ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
} }
@ -341,6 +356,7 @@ void sqlite3DeleteFrom(
** invoke the callback function. ** invoke the callback function.
*/ */
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){ if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0); sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);

View File

@ -49,6 +49,24 @@ char sqlite3ExprAffinity(Expr *pExpr){
return pExpr->affinity; return pExpr->affinity;
} }
/*
** Set the collating sequence for expression pExpr to be the collating
** sequence named by pToken. Return a pointer to the revised expression.
** The collating sequence is marked as "explicit" using the EP_ExpCollate
** flag. An explicit collating sequence will override implicit
** collating sequences.
*/
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){
CollSeq *pColl;
if( pExpr==0 ) return 0;
pColl = sqlite3LocateCollSeq(pParse, (char*)pName->z, pName->n);
if( pColl ){
pExpr->pColl = pColl;
pExpr->flags |= EP_ExpCollate;
}
return pExpr;
}
/* /*
** Return the default collation sequence for the expression pExpr. If ** Return the default collation sequence for the expression pExpr. If
** there is no default collation type, return 0. ** there is no default collation type, return 0.
@ -158,10 +176,21 @@ static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
** type. ** type.
*/ */
static CollSeq* binaryCompareCollSeq(Parse *pParse, Expr *pLeft, Expr *pRight){ static CollSeq* binaryCompareCollSeq(Parse *pParse, Expr *pLeft, Expr *pRight){
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pLeft); CollSeq *pColl;
assert( pLeft );
assert( pRight );
if( pLeft->flags & EP_ExpCollate ){
assert( pLeft->pColl );
pColl = pLeft->pColl;
}else if( pRight->flags & EP_ExpCollate ){
assert( pRight->pColl );
pColl = pRight->pColl;
}else{
pColl = sqlite3ExprCollSeq(pParse, pLeft);
if( !pColl ){ if( !pColl ){
pColl = sqlite3ExprCollSeq(pParse, pRight); pColl = sqlite3ExprCollSeq(pParse, pRight);
} }
}
return pColl; return pColl;
} }
@ -205,8 +234,31 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
if( pToken ){ if( pToken ){
assert( pToken->dyn==0 ); assert( pToken->dyn==0 );
pNew->span = pNew->token = *pToken; pNew->span = pNew->token = *pToken;
}else if( pLeft && pRight ){ }else if( pLeft ){
if( pRight ){
sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span); sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span);
if( pRight->flags && EP_ExpCollate ){
pNew->flags |= EP_ExpCollate;
pNew->pColl = pRight->pColl;
}
}
if( pLeft->flags && EP_ExpCollate ){
pNew->flags |= EP_ExpCollate;
pNew->pColl = pLeft->pColl;
}
}
return pNew;
}
/*
** Works like sqlite3Expr() but frees its pLeft and pRight arguments
** if it fails due to a malloc problem.
*/
Expr *sqlite3ExprOrFree(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
Expr *pNew = sqlite3Expr(op, pLeft, pRight, pToken);
if( pNew==0 ){
sqlite3ExprDelete(pLeft);
sqlite3ExprDelete(pRight);
} }
return pNew; return pNew;
} }
@ -547,12 +599,12 @@ Select *sqlite3SelectDup(Select *p){
pNew->iOffset = -1; pNew->iOffset = -1;
pNew->isResolved = p->isResolved; pNew->isResolved = p->isResolved;
pNew->isAgg = p->isAgg; pNew->isAgg = p->isAgg;
pNew->usesVirt = 0; pNew->usesEphm = 0;
pNew->disallowOrderBy = 0; pNew->disallowOrderBy = 0;
pNew->pRightmost = 0; pNew->pRightmost = 0;
pNew->addrOpenVirt[0] = -1; pNew->addrOpenEphm[0] = -1;
pNew->addrOpenVirt[1] = -1; pNew->addrOpenEphm[1] = -1;
pNew->addrOpenVirt[2] = -1; pNew->addrOpenEphm[2] = -1;
return pNew; return pNew;
} }
#else #else
@ -877,14 +929,16 @@ static int lookupName(
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
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;
if( (pExpr->flags & EP_ExpCollate)==0 ){
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. */
@ -897,6 +951,7 @@ static int lookupName(
} }
} }
} }
}
break; break;
} }
} }
@ -932,7 +987,9 @@ static int lookupName(
cnt++; cnt++;
pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol; pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol;
pExpr->affinity = pTab->aCol[iCol].affinity; pExpr->affinity = pTab->aCol[iCol].affinity;
if( (pExpr->flags & EP_ExpCollate)==0 ){
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0); pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
}
pExpr->pTab = pTab; pExpr->pTab = pTab;
break; break;
} }
@ -1032,7 +1089,7 @@ static int lookupName(
n = sizeof(Bitmask)*8-1; n = sizeof(Bitmask)*8-1;
} }
assert( pMatch->iCursor==pExpr->iTable ); assert( pMatch->iCursor==pExpr->iTable );
pMatch->colUsed |= 1<<n; pMatch->colUsed |= ((Bitmask)1)<<n;
} }
lookupname_end: lookupname_end:
@ -1148,6 +1205,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 */
@ -1166,6 +1224,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++;
@ -1316,7 +1388,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
case TK_IN: { case TK_IN: {
char affinity; char affinity;
KeyInfo keyInfo; KeyInfo keyInfo;
int addr; /* Address of OP_OpenVirtual instruction */ int addr; /* Address of OP_OpenEphemeral instruction */
affinity = sqlite3ExprAffinity(pExpr->pLeft); affinity = sqlite3ExprAffinity(pExpr->pLeft);
@ -1334,7 +1406,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** is used. ** is used.
*/ */
pExpr->iTable = pParse->nTab++; pExpr->iTable = pParse->nTab++;
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, pExpr->iTable, 0); addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, pExpr->iTable, 0);
memset(&keyInfo, 0, sizeof(keyInfo)); memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1; keyInfo.nField = 1;
sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1); sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
@ -1367,7 +1439,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
struct ExprList_item *pItem; struct ExprList_item *pItem;
if( !affinity ){ if( !affinity ){
affinity = SQLITE_AFF_NUMERIC; affinity = SQLITE_AFF_NONE;
} }
keyInfo.aColl[0] = pExpr->pLeft->pColl; keyInfo.aColl[0] = pExpr->pLeft->pColl;
@ -1489,7 +1561,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
}else if( pExpr->iColumn>=0 ){ }else if( pExpr->iColumn>=0 ){
Table *pTab = pExpr->pTab; Table *pTab = pExpr->pTab;
int iCol = pExpr->iColumn; int iCol = pExpr->iColumn;
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, iCol); int op = (pTab && IsVirtual(pTab)) ? OP_VColumn : OP_Column;
sqlite3VdbeAddOp(v, op, pExpr->iTable, iCol);
sqlite3ColumnDefault(v, pTab, iCol); sqlite3ColumnDefault(v, pTab, iCol);
#ifndef SQLITE_OMIT_FLOATING_POINT #ifndef SQLITE_OMIT_FLOATING_POINT
if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){ if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){
@ -1497,7 +1570,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
} }
#endif #endif
}else{ }else{
sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0); Table *pTab = pExpr->pTab;
int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
sqlite3VdbeAddOp(v, op, pExpr->iTable, 0);
} }
break; break;
} }
@ -1671,6 +1746,25 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0); pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0);
assert( pDef!=0 ); assert( pDef!=0 );
nExpr = sqlite3ExprCodeExprList(pParse, pList); nExpr = sqlite3ExprCodeExprList(pParse, pList);
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Possibly overload the function if the first argument is
** a virtual table column.
**
** For infix functions (LIKE, GLOB, REGEXP, and MATCH) use the
** second argument, not the first, as the argument to test to
** see if it is a column in a virtual table. This is done because
** the left operand of infix functions (the operand we want to
** control overloading) ends up as the second argument to the
** function. The expression "A glob B" is equivalent to
** "glob(B,A). We want to use the A in "A glob B" to test
** for function overloading. But we use the B term in "glob(B,A)".
*/
if( nExpr>=2 && (pExpr->flags & EP_InfixFunc) ){
pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[1].pExpr);
}else if( nExpr>0 ){
pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[0].pExpr);
}
#endif
for(i=0; i<nExpr && i<32; i++){ for(i=0; i<nExpr && i<32; i++){
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){ if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
constMask |= (1<<i); constMask |= (1<<i);
@ -2157,6 +2251,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

@ -204,7 +204,8 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
r = sqlite3_value_double(argv[0]); r = sqlite3_value_double(argv[0]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r); sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r);
sqlite3_result_double(context, atof(zBuf)); sqlite3AtoF(zBuf, &r);
sqlite3_result_double(context, r);
} }
/* /*
@ -271,6 +272,25 @@ static void randomFunc(
sqlite3_result_int64(context, r); sqlite3_result_int64(context, r);
} }
/*
** Implementation of randomblob(N). Return a random blob
** that is N bytes long.
*/
static void randomBlob(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int n;
unsigned char *p;
assert( argc==1 );
n = sqlite3_value_int(argv[0]);
if( n<1 ) n = 1;
p = sqlite3_malloc(n);
sqlite3Randomness(n, p);
sqlite3_result_blob(context, (char*)p, n, sqlite3_free);
}
/* /*
** Implementation of the last_insert_rowid() SQL function. The return ** Implementation of the last_insert_rowid() SQL function. The return
** value is the same as the sqlite3_last_insert_rowid() API function. ** value is the same as the sqlite3_last_insert_rowid() API function.
@ -547,6 +567,12 @@ static void versionFunc(
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC); sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
} }
/* Array for converting from half-bytes (nybbles) into ASCII hex
** digits. */
static const char hexdigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
/* /*
** EXPERIMENTAL - This is not an official function. The interface may ** EXPERIMENTAL - This is not an official function. The interface may
@ -572,10 +598,6 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
break; break;
} }
case SQLITE_BLOB: { case SQLITE_BLOB: {
static const char hexdigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
char *zText = 0; char *zText = 0;
int nBlob = sqlite3_value_bytes(argv[0]); int nBlob = sqlite3_value_bytes(argv[0]);
char const *zBlob = sqlite3_value_blob(argv[0]); char const *zBlob = sqlite3_value_blob(argv[0]);
@ -621,11 +643,41 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
} }
} }
/*
** The hex() function. Interpret the argument as a blob. Return
** a hexadecimal rendering as text.
*/
static void hexFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int i, n;
const unsigned char *pBlob;
char *zHex, *z;
assert( argc==1 );
pBlob = sqlite3_value_blob(argv[0]);
n = sqlite3_value_bytes(argv[0]);
z = zHex = sqlite3_malloc(n*2 + 1);
if( zHex==0 ) return;
for(i=0; i<n; i++, pBlob++){
unsigned char c = *pBlob;
*(z++) = hexdigits[(c>>4)&0xf];
*(z++) = hexdigits[c&0xf];
}
*z = 0;
sqlite3_result_text(context, zHex, n*2, sqlite3_free);
}
#ifdef SQLITE_SOUNDEX #ifdef SQLITE_SOUNDEX
/* /*
** Compute the soundex encoding of a word. ** Compute the soundex encoding of a word.
*/ */
static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ static void soundexFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
char zResult[8]; char zResult[8];
const u8 *zIn; const u8 *zIn;
int i, j; int i, j;
@ -641,14 +693,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 = (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';
@ -661,6 +720,26 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
} }
#endif #endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** A function that loads a shared-library extension then returns NULL.
*/
static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
const char *zFile = (const char *)sqlite3_value_text(argv[0]);
const char *zProc = 0;
sqlite3 *db = sqlite3_user_data(context);
char *zErrMsg = 0;
if( argc==2 ){
zProc = (const char *)sqlite3_value_text(argv[1]);
}
if( sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){
sqlite3_result_error(context, zErrMsg, -1);
sqlite3_free(zErrMsg);
}
}
#endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
/* /*
** This function generates a string of random characters. Used for ** This function generates a string of random characters. Used for
@ -839,16 +918,8 @@ struct SumCtx {
** that it returns NULL if it sums over no inputs. TOTAL returns ** that it returns NULL if it sums over no inputs. TOTAL returns
** 0.0 in that case. In addition, TOTAL always returns a float where ** 0.0 in that case. In addition, TOTAL always returns a float where
** SUM might return an integer if it never encounters a floating point ** SUM might return an integer if it never encounters a floating point
** value. ** value. TOTAL never fails, but SUM might through an exception if
** ** it overflows an integer.
** I am told that SUM() should raise an exception if it encounters
** a integer overflow. But after pondering this, I decided that
** behavior leads to brittle programs. So instead, I have coded
** SUM() to revert to using floating point if it encounters an
** integer overflow. The answer may not be exact, but it will be
** close. If the SUM() function returns an integer, the value is
** exact. If SUM() returns a floating point value, it means the
** value might be approximated.
*/ */
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
SumCtx *p; SumCtx *p;
@ -1002,8 +1073,10 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc }, { "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc },
{ "coalesce", 0, 0, SQLITE_UTF8, 0, 0 }, { "coalesce", 0, 0, SQLITE_UTF8, 0, 0 },
{ "coalesce", 1, 0, SQLITE_UTF8, 0, 0 }, { "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
{ "hex", 1, 0, SQLITE_UTF8, 0, hexFunc },
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc }, { "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc }, { "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
{ "randomblob", 1, 0, SQLITE_UTF8, 0, randomBlob },
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc }, { "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc}, { "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc }, { "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
@ -1013,6 +1086,10 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
#ifdef SQLITE_SOUNDEX #ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif #endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
{ "load_extension", 1, 1, SQLITE_UTF8, 0, loadExt },
{ "load_extension", 2, 1, SQLITE_UTF8, 0, loadExt },
#endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
{ "randstr", 2, 0, SQLITE_UTF8, 0, randStr }, { "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
{ "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor}, { "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
@ -1078,6 +1155,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

@ -272,8 +272,10 @@ void sqlite3Insert(
assert( pTab!=0 ); assert( pTab!=0 );
/* If pTab is really a view, make sure it has been initialized. /* If pTab is really a view, make sure it has been initialized.
** ViewGetColumnNames() is a no-op if pTab is not a view (or virtual
** module table).
*/ */
if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto insert_cleanup; goto insert_cleanup;
} }
@ -371,7 +373,7 @@ void sqlite3Insert(
** back up and execute the SELECT code above. ** back up and execute the SELECT code above.
*/ */
sqlite3VdbeJumpHere(v, iInitCode); sqlite3VdbeJumpHere(v, iInitCode);
sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0); sqlite3VdbeAddOp(v, OP_OpenEphemeral, srcTab, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn); sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop); sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
sqlite3VdbeResolveLabel(v, iCleanup); sqlite3VdbeResolveLabel(v, iCleanup);
@ -385,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;
@ -400,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);
@ -453,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;
} }
@ -567,6 +567,10 @@ void sqlite3Insert(
** case the record number is the same as that column. ** case the record number is the same as that column.
*/ */
if( !isView ){ if( !isView ){
if( IsVirtual(pTab) ){
/* The row that the VUpdate opcode will delete: none */
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
}
if( keyColumn>=0 ){ if( keyColumn>=0 ){
if( useTempTable ){ if( useTempTable ){
sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn); sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn);
@ -582,6 +586,8 @@ void sqlite3Insert(
sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem); sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
}else if( IsVirtual(pTab) ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
}else{ }else{
sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem); sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
} }
@ -610,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);
} }
@ -624,11 +630,20 @@ void sqlite3Insert(
/* Generate code to check constraints and generate index keys and /* Generate code to check constraints and generate index keys and
** do the insertion. ** do the insertion.
*/ */
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
pParse->pVirtualLock = pTab;
sqlite3VdbeOp3(v, OP_VUpdate, 1, pTab->nCol+2,
(const char*)pTab->pVtab, P3_VTAB);
}else
#endif
{
sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0, sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
0, onError, endOfLoop); 0, onError, endOfLoop);
sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0, sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1); (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1);
} }
}
/* Update the count of rows that are inserted /* Update the count of rows that are inserted
*/ */
@ -665,7 +680,7 @@ void sqlite3Insert(
sqlite3VdbeResolveLabel(v, iCleanup); sqlite3VdbeResolveLabel(v, iCleanup);
} }
if( !triggers_exist ){ if( !triggers_exist && !IsVirtual(pTab) ){
/* Close all tables opened */ /* Close all tables opened */
sqlite3VdbeAddOp(v, OP_Close, base, 0); sqlite3VdbeAddOp(v, OP_Close, base, 0);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
@ -1105,9 +1120,13 @@ void sqlite3OpenTableAndIndices(
int op /* OP_OpenRead or OP_OpenWrite */ int op /* OP_OpenRead or OP_OpenWrite */
){ ){
int i; int i;
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); int iDb;
Index *pIdx; Index *pIdx;
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v;
if( IsVirtual(pTab) ) return;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
v = sqlite3GetVdbe(pParse);
assert( v!=0 ); assert( v!=0 );
sqlite3OpenTable(pParse, base, iDb, pTab, op); sqlite3OpenTable(pParse, base, iDb, pTab, op);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){

View File

@ -1,6 +1,6 @@
/* Hash score: 159 */ /* Hash score: 167 */
static int keywordCode(const char *z, int n){ static int keywordCode(const char *z, int n){
static const char zText[537] = static const char zText[544] =
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER" "ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE" "AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
"XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX" "XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
@ -9,11 +9,11 @@ static int keywordCode(const char *z, int n){
"CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH" "CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
"FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL" "FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
"JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION" "JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
"UNIQUEUSINGVACUUMVALUESVIEWHERE"; "UNIQUEUSINGVACUUMVALUESVIEWHEREVIRTUAL";
static const unsigned char aHash[127] = { static const unsigned char aHash[127] = {
92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0, 92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0,
95, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0, 95, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0,
113, 0, 110, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71, 113, 0, 117, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71,
0, 63, 19, 0, 105, 36, 104, 0, 108, 74, 0, 0, 33, 0, 63, 19, 0, 105, 36, 104, 0, 108, 74, 0, 0, 33,
0, 61, 37, 0, 8, 0, 115, 38, 12, 0, 77, 40, 25, 0, 61, 37, 0, 8, 0, 115, 38, 12, 0, 77, 40, 25,
66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0, 66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0,
@ -22,7 +22,7 @@ static int keywordCode(const char *z, int n){
54, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0, 54, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0,
15, 0, 116, 51, 56, 0, 2, 55, 0, 111, 15, 0, 116, 51, 56, 0, 2, 55, 0, 111,
}; };
static const unsigned char aNext[116] = { static const unsigned char aNext[117] = {
0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0,
0, 11, 0, 0, 0, 0, 5, 13, 0, 7, 0, 0, 0, 0, 11, 0, 0, 0, 0, 5, 13, 0, 7, 0, 0, 0,
@ -31,9 +31,9 @@ static int keywordCode(const char *z, int n){
0, 0, 0, 0, 0, 0, 0, 0, 73, 42, 0, 24, 60, 0, 0, 0, 0, 0, 0, 0, 0, 73, 42, 0, 24, 60,
21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0, 21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0,
0, 0, 0, 0, 0, 39, 96, 98, 0, 0, 100, 0, 32, 0, 0, 0, 0, 0, 39, 96, 98, 0, 0, 100, 0, 32,
0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0, 0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0, 110,
}; };
static const unsigned char aLen[116] = { static const unsigned char aLen[117] = {
5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7, 5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7,
11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6, 11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6,
7, 6, 7, 9, 3, 7, 9, 6, 9, 3, 10, 6, 6, 7, 6, 7, 9, 3, 7, 9, 6, 9, 3, 10, 6, 6,
@ -42,9 +42,9 @@ static int keywordCode(const char *z, int n){
6, 6, 8, 10, 9, 6, 5, 12, 12, 17, 4, 4, 6, 6, 6, 8, 10, 9, 6, 5, 12, 12, 17, 4, 4, 6,
8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9, 8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9,
6, 7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7, 6, 7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7,
5, 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5, 5, 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5, 7,
}; };
static const unsigned short int aOffset[116] = { static const unsigned short int aOffset[117] = {
0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36, 0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36,
42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94, 42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94,
99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167, 99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167,
@ -53,9 +53,9 @@ static int keywordCode(const char *z, int n){
269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352, 269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352,
358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405, 358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405,
414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469, 414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469,
476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531, 476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531, 536,
}; };
static const unsigned char aCode[116] = { static const unsigned char aCode[117] = {
TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP, TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP,
TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT,
TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON, TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON,
@ -79,7 +79,7 @@ static int keywordCode(const char *z, int n){
TK_REPLACE, TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY, TK_REPLACE, TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY,
TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION, TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION,
TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW, TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW,
TK_WHERE, TK_WHERE, TK_VIRTUAL,
}; };
int h, i; int h, i;
if( n<2 ) return TK_ID; if( n<2 ) return TK_ID;

View File

@ -123,7 +123,7 @@ exec_out:
rc = sqlite3ApiExit(0, rc); rc = sqlite3ApiExit(0, rc);
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){ if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
*pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db))); *pzErrMsg = sqlite3_malloc(1+strlen(sqlite3_errmsg(db)));
if( *pzErrMsg ){ if( *pzErrMsg ){
strcpy(*pzErrMsg, sqlite3_errmsg(db)); strcpy(*pzErrMsg, sqlite3_errmsg(db));
} }
@ -131,5 +131,6 @@ exec_out:
*pzErrMsg = 0; *pzErrMsg = 0;
} }
assert( (rc&db->errMask)==rc );
return rc; return rc;
} }

View File

@ -0,0 +1,422 @@
/*
** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to dynamically load extensions into
** the SQLite library.
*/
#ifndef SQLITE_OMIT_LOAD_EXTENSION
#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
#include "sqlite3ext.h"
#include "sqliteInt.h"
#include "os.h"
#include <string.h>
#include <ctype.h>
/*
** Some API routines are omitted when various features are
** excluded from a build of SQLite. Substitute a NULL pointer
** for any missing APIs.
*/
#ifndef SQLITE_ENABLE_COLUMN_METADATA
# define sqlite3_column_database_name 0
# define sqlite3_column_database_name16 0
# define sqlite3_column_table_name 0
# define sqlite3_column_table_name16 0
# define sqlite3_column_origin_name 0
# define sqlite3_column_origin_name16 0
# define sqlite3_table_column_metadata 0
#endif
#ifdef SQLITE_OMIT_AUTHORIZATION
# define sqlite3_set_authorizer 0
#endif
#ifdef SQLITE_OMIT_UTF16
# define sqlite3_bind_text16 0
# define sqlite3_collation_needed16 0
# define sqlite3_column_decltype16 0
# define sqlite3_column_name16 0
# define sqlite3_column_text16 0
# define sqlite3_complete16 0
# define sqlite3_create_collation16 0
# define sqlite3_create_function16 0
# define sqlite3_errmsg16 0
# define sqlite3_open16 0
# define sqlite3_prepare16 0
# define sqlite3_result_error16 0
# define sqlite3_result_text16 0
# define sqlite3_result_text16be 0
# define sqlite3_result_text16le 0
# define sqlite3_value_text16 0
# define sqlite3_value_text16be 0
# define sqlite3_value_text16le 0
#endif
#ifdef SQLITE_OMIT_COMPLETE
# define sqlite3_complete 0
# define sqlite3_complete16 0
#endif
#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
# define sqlite3_progress_handler 0
#endif
#ifdef SQLITE_OMIT_VIRTUALTABLE
# define sqlite3_create_module 0
# define sqlite3_declare_vtab 0
#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.
** A pointer to this structure is passed into extensions when they are
** loaded so that the extension can make calls back into the SQLite
** library.
**
** When adding new APIs, add them to the bottom of this structure
** in order to preserve backwards compatibility.
**
** Extensions that use newer APIs should first call the
** sqlite3_libversion_number() to make sure that the API they
** intend to use is supported by the library. Extensions should
** also check to make sure that the pointer to the function is
** not NULL before calling it.
*/
const sqlite3_api_routines sqlite3_apis = {
sqlite3_aggregate_context,
sqlite3_aggregate_count,
sqlite3_bind_blob,
sqlite3_bind_double,
sqlite3_bind_int,
sqlite3_bind_int64,
sqlite3_bind_null,
sqlite3_bind_parameter_count,
sqlite3_bind_parameter_index,
sqlite3_bind_parameter_name,
sqlite3_bind_text,
sqlite3_bind_text16,
sqlite3_bind_value,
sqlite3_busy_handler,
sqlite3_busy_timeout,
sqlite3_changes,
sqlite3_close,
sqlite3_collation_needed,
sqlite3_collation_needed16,
sqlite3_column_blob,
sqlite3_column_bytes,
sqlite3_column_bytes16,
sqlite3_column_count,
sqlite3_column_database_name,
sqlite3_column_database_name16,
sqlite3_column_decltype,
sqlite3_column_decltype16,
sqlite3_column_double,
sqlite3_column_int,
sqlite3_column_int64,
sqlite3_column_name,
sqlite3_column_name16,
sqlite3_column_origin_name,
sqlite3_column_origin_name16,
sqlite3_column_table_name,
sqlite3_column_table_name16,
sqlite3_column_text,
sqlite3_column_text16,
sqlite3_column_type,
sqlite3_column_value,
sqlite3_commit_hook,
sqlite3_complete,
sqlite3_complete16,
sqlite3_create_collation,
sqlite3_create_collation16,
sqlite3_create_function,
sqlite3_create_function16,
sqlite3_create_module,
sqlite3_data_count,
sqlite3_db_handle,
sqlite3_declare_vtab,
sqlite3_enable_shared_cache,
sqlite3_errcode,
sqlite3_errmsg,
sqlite3_errmsg16,
sqlite3_exec,
sqlite3_expired,
sqlite3_finalize,
sqlite3_free,
sqlite3_free_table,
sqlite3_get_autocommit,
sqlite3_get_auxdata,
sqlite3_get_table,
0, /* Was sqlite3_global_recover(), but that function is deprecated */
sqlite3_interrupt,
sqlite3_last_insert_rowid,
sqlite3_libversion,
sqlite3_libversion_number,
sqlite3_malloc,
sqlite3_mprintf,
sqlite3_open,
sqlite3_open16,
sqlite3_prepare,
sqlite3_prepare16,
sqlite3_profile,
sqlite3_progress_handler,
sqlite3_realloc,
sqlite3_reset,
sqlite3_result_blob,
sqlite3_result_double,
sqlite3_result_error,
sqlite3_result_error16,
sqlite3_result_int,
sqlite3_result_int64,
sqlite3_result_null,
sqlite3_result_text,
sqlite3_result_text16,
sqlite3_result_text16be,
sqlite3_result_text16le,
sqlite3_result_value,
sqlite3_rollback_hook,
sqlite3_set_authorizer,
sqlite3_set_auxdata,
sqlite3_snprintf,
sqlite3_step,
sqlite3_table_column_metadata,
sqlite3_thread_cleanup,
sqlite3_total_changes,
sqlite3_trace,
sqlite3_transfer_bindings,
sqlite3_update_hook,
sqlite3_user_data,
sqlite3_value_blob,
sqlite3_value_bytes,
sqlite3_value_bytes16,
sqlite3_value_double,
sqlite3_value_int,
sqlite3_value_int64,
sqlite3_value_numeric_type,
sqlite3_value_text,
sqlite3_value_text16,
sqlite3_value_text16be,
sqlite3_value_text16le,
sqlite3_value_type,
sqlite3_vmprintf,
/*
** The original API set ends here. All extensions can call any
** of the APIs above provided that the pointer is not NULL. But
** before calling APIs that follow, extension should check the
** sqlite3_libversion_number() to make sure they are dealing with
** a library that is new enough to support that API.
*************************************************************************
*/
sqlite3_overload_function,
};
/*
** 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
** default entry point name (sqlite3_extension_init) is used. Use
** of the default name is recommended.
**
** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
**
** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
** error message text. The calling function should free this memory
** by calling sqlite3_free().
*/
int sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
char **pzErrMsg /* Put error message here if not 0 */
){
void *handle;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
char *zErrmsg = 0;
void **aHandle;
/* Ticket #1863. To avoid a creating security problems for older
** applications that relink against newer versions of SQLite, the
** ability to run load_extension is turned off by default. One
** must call sqlite3_enable_load_extension() to turn on extension
** loading. Otherwise you get the following error.
*/
if( (db->flags & SQLITE_LoadExtension)==0 ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("not authorized");
}
return SQLITE_ERROR;
}
if( zProc==0 ){
zProc = "sqlite3_extension_init";
}
handle = sqlite3OsDlopen(zFile);
if( handle==0 ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile);
}
return SQLITE_ERROR;
}
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
sqlite3OsDlsym(handle, zProc);
if( xInit==0 ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("no entry point [%s] in shared library [%s]",
zProc, zFile);
}
sqlite3OsDlclose(handle);
return SQLITE_ERROR;
}else if( xInit(db, &zErrmsg, &sqlite3_apis) ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
}
sqlite3_free(zErrmsg);
sqlite3OsDlclose(handle);
return SQLITE_ERROR;
}
/* Append the new shared library handle to the db->aExtension array. */
db->nExtension++;
aHandle = sqliteMalloc(sizeof(handle)*db->nExtension);
if( aHandle==0 ){
return SQLITE_NOMEM;
}
if( db->nExtension>0 ){
memcpy(aHandle, db->aExtension, sizeof(handle)*(db->nExtension-1));
}
sqliteFree(db->aExtension);
db->aExtension = aHandle;
db->aExtension[db->nExtension-1] = handle;
return SQLITE_OK;
}
/*
** Call this routine when the database connection is closing in order
** to clean up loaded extensions
*/
void sqlite3CloseExtensions(sqlite3 *db){
int i;
for(i=0; i<db->nExtension; i++){
sqlite3OsDlclose(db->aExtension[i]);
}
sqliteFree(db->aExtension);
}
/*
** Enable or disable extension loading. Extension loading is disabled by
** default so as not to open security holes in older applications.
*/
int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
if( onoff ){
db->flags |= SQLITE_LoadExtension;
}else{
db->flags &= ~SQLITE_LoadExtension;
}
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 */

View File

@ -116,6 +116,7 @@ int sqlite3_close(sqlite3 *db){
#endif #endif
/* If there are any outstanding VMs, return SQLITE_BUSY. */ /* If there are any outstanding VMs, return SQLITE_BUSY. */
sqlite3ResetInternalSchema(db, 0);
if( db->pVdbe ){ if( db->pVdbe ){
sqlite3Error(db, SQLITE_BUSY, sqlite3Error(db, SQLITE_BUSY,
"Unable to close due to unfinalised statements"); "Unable to close due to unfinalised statements");
@ -133,6 +134,8 @@ int sqlite3_close(sqlite3 *db){
return SQLITE_ERROR; return SQLITE_ERROR;
} }
sqlite3VtabRollback(db);
for(j=0; j<db->nDb; j++){ for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j]; struct Db *pDb = &db->aDb[j];
if( pDb->pBt ){ if( pDb->pBt ){
@ -159,12 +162,20 @@ int sqlite3_close(sqlite3 *db){
sqliteFree(pColl); sqliteFree(pColl);
} }
sqlite3HashClear(&db->aCollSeq); sqlite3HashClear(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){
Module *pMod = (Module *)sqliteHashData(i);
sqliteFree(pMod);
}
sqlite3HashClear(&db->aModule);
#endif
sqlite3HashClear(&db->aFunc); sqlite3HashClear(&db->aFunc);
sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
if( db->pErr ){ if( db->pErr ){
sqlite3ValueFree(db->pErr); sqlite3ValueFree(db->pErr);
} }
sqlite3CloseExtensions(db);
db->magic = SQLITE_MAGIC_ERROR; db->magic = SQLITE_MAGIC_ERROR;
@ -195,6 +206,7 @@ void sqlite3RollbackAll(sqlite3 *db){
db->aDb[i].inTrans = 0; db->aDb[i].inTrans = 0;
} }
} }
sqlite3VtabRollback(db);
if( db->flags&SQLITE_InternChanges ){ if( db->flags&SQLITE_InternChanges ){
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, 0);
} }
@ -211,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;
@ -355,6 +367,9 @@ void sqlite3_progress_handler(
** specified number of milliseconds before returning 0. ** specified number of milliseconds before returning 0.
*/ */
int sqlite3_busy_timeout(sqlite3 *db, int ms){ int sqlite3_busy_timeout(sqlite3 *db, int ms){
if( sqlite3SafetyCheck(db) ){
return SQLITE_MISUSE;
}
if( ms>0 ){ if( ms>0 ){
db->busyTimeout = ms; db->busyTimeout = ms;
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db); sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
@ -368,20 +383,35 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
** Cause any pending operation to stop at its earliest opportunity. ** Cause any pending operation to stop at its earliest opportunity.
*/ */
void sqlite3_interrupt(sqlite3 *db){ void sqlite3_interrupt(sqlite3 *db){
if( !sqlite3SafetyCheck(db) ){ if( db && (db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_BUSY) ){
db->flags |= SQLITE_Interrupt; db->u1.isInterrupted = 1;
} }
} }
/* /*
** Windows systems should call this routine to free memory that ** Memory allocation routines that use SQLites internal memory
** is returned in the in the errmsg parameter of sqlite3_open() when ** memory allocator. Depending on how SQLite is compiled, the
** SQLite is a DLL. For some reason, it does not work to call free() ** internal memory allocator might be just an alias for the
** directly. ** system default malloc/realloc/free. Or the built-in allocator
** might do extra stuff like put sentinals around buffers to
** check for overruns or look for memory leaks.
** **
** Note that we need to call free() not sqliteFree() here. ** Use sqlite3_free() to free memory returned by sqlite3_mprintf().
*/ */
void sqlite3_free(char *p){ free(p); } void sqlite3_free(void *p){ if( p ) sqlite3OsFree(p); }
void *sqlite3_malloc(int nByte){ return nByte>0 ? sqlite3OsMalloc(nByte) : 0; }
void *sqlite3_realloc(void *pOld, int nByte){
if( pOld ){
if( nByte>0 ){
return sqlite3OsRealloc(pOld, nByte);
}else{
sqlite3OsFree(pOld);
return 0;
}
}else{
return sqlite3_malloc(nByte);
}
}
/* /*
** This function is exactly the same as sqlite3_create_function(), except ** This function is exactly the same as sqlite3_create_function(), except
@ -411,6 +441,7 @@ int sqlite3CreateFunc(
(!xFunc && (!xFinal && xStep)) || (!xFunc && (!xFinal && xStep)) ||
(nArg<-1 || nArg>127) || (nArg<-1 || nArg>127) ||
(255<(nName = strlen(zFunctionName))) ){ (255<(nName = strlen(zFunctionName))) ){
sqlite3Error(db, SQLITE_ERROR, "bad parameters");
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@ -462,6 +493,7 @@ int sqlite3CreateFunc(
p->xStep = xStep; p->xStep = xStep;
p->xFinalize = xFinal; p->xFinalize = xFinal;
p->pUserData = pUserData; p->pUserData = pUserData;
p->nArg = nArg;
} }
return SQLITE_OK; return SQLITE_OK;
} }
@ -509,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
@ -731,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;
} }
/* /*
@ -809,14 +867,22 @@ 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;
db->aDb = db->aDbStatic; db->aDb = db->aDbStatic;
db->autoCommit = 1; db->autoCommit = 1;
db->flags |= SQLITE_ShortColNames; db->flags |= SQLITE_ShortColNames
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
;
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0);
#endif
/* Add the default collation sequence BINARY. BINARY works for both UTF-8 /* Add the default collation sequence BINARY. BINARY works for both UTF-8
** and UTF-16, so add a version for each to avoid any unnecessary ** and UTF-16, so add a version for each to avoid any unnecessary
@ -851,9 +917,6 @@ static int openDatabase(
} }
db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt); db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(0); db->aDb[1].pSchema = sqlite3SchemaGet(0);
if( db->aDb[0].pSchema ){
ENC(db) = SQLITE_UTF8;
}
/* The default safety_level for the main database is 'full'; for the temp /* The default safety_level for the main database is 'full'; for the temp
@ -871,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);
@ -963,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;
} }
@ -1230,3 +1313,30 @@ error_out:
return sqlite3ApiExit(db, rc); return sqlite3ApiExit(db, rc);
} }
#endif #endif
/*
** Set all the parameters in the compiled SQL statement to NULL.
*/
int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int i;
int rc = SQLITE_OK;
for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){
rc = sqlite3_bind_null(pStmt, i);
}
return rc;
}
/*
** Sleep for a little while. Return the amount of time slept.
*/
int sqlite3_sleep(int 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

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

View File

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

View File

@ -27,12 +27,19 @@
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
# define OS_WIN 1 # define OS_WIN 1
# define OS_UNIX 0 # define OS_UNIX 0
# define OS_OS2 0
# elif defined(_EMX_) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__)
# define OS_WIN 0
# define OS_UNIX 0
# define OS_OS2 1
# else # else
# define OS_WIN 0 # define OS_WIN 0
# define OS_UNIX 1 # define OS_UNIX 1
# define OS_OS2 0
# endif # endif
# else # else
# define OS_UNIX 0 # define OS_UNIX 0
# define OS_OS2 0
# endif # endif
#else #else
# ifndef OS_WIN # ifndef OS_WIN
@ -47,6 +54,14 @@
#if OS_WIN #if OS_WIN
# include <windows.h> # include <windows.h>
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) # define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
#elif OS_OS2
# define INCL_DOSDATETIME
# define INCL_DOSFILEMGR
# define INCL_DOSERRORS
# define INCL_DOSMISC
# define INCL_DOSPROCESS
# include <os2.h>
# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
#else #else
# define SQLITE_TEMPNAME_SIZE 200 # define SQLITE_TEMPNAME_SIZE 200
#endif #endif
@ -66,13 +81,25 @@
** 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
/* /*
** Define the interfaces for Unix and for Windows. ** Define the interfaces for Unix, Windows, and OS/2.
*/ */
#if OS_UNIX #if OS_UNIX
#define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite #define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite
@ -95,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
@ -117,7 +147,38 @@
#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
#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite
#define sqlite3OsOpenExclusive sqlite3Os2OpenExclusive
#define sqlite3OsOpenReadOnly sqlite3Os2OpenReadOnly
#define sqlite3OsDelete sqlite3Os2Delete
#define sqlite3OsFileExists sqlite3Os2FileExists
#define sqlite3OsFullPathname sqlite3Os2FullPathname
#define sqlite3OsIsDirWritable sqlite3Os2IsDirWritable
#define sqlite3OsSyncDirectory sqlite3Os2SyncDirectory
#define sqlite3OsTempFileName sqlite3Os2TempFileName
#define sqlite3OsRandomSeed sqlite3Os2RandomSeed
#define sqlite3OsSleep sqlite3Os2Sleep
#define sqlite3OsCurrentTime sqlite3Os2CurrentTime
#define sqlite3OsEnterMutex sqlite3Os2EnterMutex
#define sqlite3OsLeaveMutex sqlite3Os2LeaveMutex
#define sqlite3OsInMutex sqlite3Os2InMutex
#define sqlite3OsThreadSpecificData sqlite3Os2ThreadSpecificData
#define sqlite3OsMalloc sqlite3GenericMalloc
#define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
#define sqlite3OsDlopen sqlite3Os2Dlopen
#define sqlite3OsDlsym sqlite3Os2Dlsym
#define sqlite3OsDlclose sqlite3Os2Dlclose
#endif
/* /*
** If using an alternative OS interface, then we must have an "os_other.h" ** If using an alternative OS interface, then we must have an "os_other.h"
@ -297,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
@ -341,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_
/* /*
@ -376,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.
@ -476,22 +560,60 @@ static BOOL winceLockFileEx(
#endif /* OS_WINCE */ #endif /* OS_WINCE */
/* /*
** Delete the named file ** 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.
**
** Note that windows does not allow a file to be deleted if some other
** process has it open. Sometimes a virus scanner or indexing program
** will open a journal file shortly after it is created in order to do
** whatever it is it does. While this other process is holding the
** file open, we will be unable to delete it. To work around this
** problem, we delay 100 milliseconds and try to delete again. Up
** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
** up and returning an error.
*/
#define MX_DELETION_ATTEMPTS 3
int sqlite3WinDelete(const char *zFilename){ int sqlite3WinDelete(const char *zFilename){
WCHAR *zWide = utf8ToUnicode(zFilename); int cnt = 0;
if( zWide ){ int rc;
DeleteFileW(zWide); void *zConverted = convertUtf8Filename(zFilename);
sqliteFree(zWide); if( zConverted==0 ){
return SQLITE_NOMEM;
}
if( isNT() ){
do{
rc = DeleteFileW(zConverted);
}while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff
&& cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
}else{ }else{
#if OS_WINCE #if OS_WINCE
return SQLITE_NOMEM; return SQLITE_NOMEM;
#else #else
DeleteFileA(zFilename); do{
rc = DeleteFileA(zConverted);
}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 SQLITE_OK; return rc!=0 ? SQLITE_OK : SQLITE_IOERR;
} }
/* /*
@ -499,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;
} }
@ -536,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,
@ -548,16 +677,16 @@ 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_READ | FILE_SHARE_WRITE,
NULL, NULL,
OPEN_ALWAYS, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL NULL
); );
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
sqliteFree(zWide); sqliteFree(zConverted);
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
*pReadonly = 1; *pReadonly = 1;
@ -567,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,
@ -585,15 +713,16 @@ 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_READ | FILE_SHARE_WRITE,
NULL, NULL,
OPEN_ALWAYS, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL NULL
); );
if( h==INVALID_HANDLE_VALUE ){ if( h==INVALID_HANDLE_VALUE ){
sqliteFree(zConverted);
return SQLITE_CANTOPEN; return SQLITE_CANTOPEN;
} }
*pReadonly = 1; *pReadonly = 1;
@ -602,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;
@ -624,12 +756,21 @@ int sqlite3WinOpenReadWrite(
** On success, write the file handle into *id and return SQLITE_OK. ** On success, write the file handle into *id and return SQLITE_OK.
** **
** On failure, return SQLITE_CANTOPEN. ** On failure, return SQLITE_CANTOPEN.
**
** Sometimes if we have just deleted a prior journal file, windows
** will fail to open a new one because there is a "pending delete".
** To work around this bug, we pause for 100 milliseconds and attempt
** a second open after the first one fails. The whole operation only
** fails if both open attempts are unsuccessful.
*/ */
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
@ -637,8 +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() ){
h = CreateFileW(zWide, int cnt = 0;
do{
h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
0, 0,
NULL, NULL,
@ -646,12 +789,14 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
fileflags, fileflags,
NULL NULL
); );
sqliteFree(zWide); }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
}else{ }else{
#if OS_WINCE #if OS_WINCE
return SQLITE_NOMEM; return SQLITE_NOMEM;
#else #else
h = CreateFileA(zFilename, int cnt = 0;
do{
h = CreateFileA((char*)zConverted,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
0, 0,
NULL, NULL,
@ -659,16 +804,21 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
fileflags, fileflags,
NULL NULL
); );
}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);
} }
@ -683,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,
@ -694,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,
@ -709,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;
} }
@ -774,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;
@ -796,12 +961,24 @@ int sqlite3WinTempFileName(char *zBuf){
/* /*
** Close a file. ** Close a file.
**
** It is reported that an attempt to close a handle might sometimes
** fail. This is a very unreasonable result, but windows is notorious
** for being unreasonable so I do not doubt that it might happen. If
** the close fails, we pause for 100 milliseconds and try again. As
** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
** giving up and returning an error.
*/ */
#define MX_CLOSE_ATTEMPT 3
static int winClose(OsFile **pId){ static int winClose(OsFile **pId){
winFile *pFile; winFile *pFile;
int rc = 1;
if( pId && (pFile = (winFile*)*pId)!=0 ){ if( pId && (pFile = (winFile*)*pId)!=0 ){
int rc, cnt = 0;
TRACE2("CLOSE %d\n", pFile->h); TRACE2("CLOSE %d\n", pFile->h);
CloseHandle(pFile->h); do{
rc = CloseHandle(pFile->h);
}while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
#if OS_WINCE #if OS_WINCE
winceDestroyLock(pFile); winceDestroyLock(pFile);
if( pFile->zDeleteOnClose ){ if( pFile->zDeleteOnClose ){
@ -813,7 +990,7 @@ static int winClose(OsFile **pId){
sqliteFree(pFile); sqliteFree(pFile);
*pId = 0; *pId = 0;
} }
return SQLITE_OK; return rc ? SQLITE_OK : SQLITE_IOERR;
} }
/* /*
@ -824,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;
} }
} }
@ -844,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
@ -871,11 +1049,11 @@ static int winWrite(OsFile *id, const void *pBuf, int amt){
*/ */
static int winSeek(OsFile *id, i64 offset){ static int winSeek(OsFile *id, i64 offset){
LONG upperBits = (LONG)(offset>>32); LONG upperBits = (LONG)(offset>>32);
LONG lowerBits = (LONG)(offset) & 0xffffffff; LONG lowerBits = (LONG)(offset & 0xffffffff);
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);
@ -904,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;
} }
@ -915,7 +1093,7 @@ static int winTruncate(OsFile *id, i64 nByte){
LONG upperBits = (LONG)(nByte>>32); LONG upperBits = (LONG)(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, (LONG)nByte, &upperBits, FILE_BEGIN); SetFilePointer(((winFile*)id)->h, (LONG)nByte, &upperBits, FILE_BEGIN);
SetEndOfFile(((winFile*)id)->h); SetEndOfFile(((winFile*)id)->h);
return SQLITE_OK; return SQLITE_OK;
@ -927,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;
@ -982,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;
@ -1184,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 ){
@ -1218,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;
@ -1317,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)
@ -161,7 +162,8 @@ struct PgHdr {
u8 needSync; /* Sync journal before writing this page */ u8 needSync; /* Sync journal before writing this page */
u8 alwaysRollback; /* Disable dont_rollback() for this page */ u8 alwaysRollback; /* Disable dont_rollback() for this page */
short int nRef; /* Number of users of this page */ short int nRef; /* Number of users of this page */
PgHdr *pDirty; /* Dirty pages sorted by PgHdr.pgno */ PgHdr *pDirty, *pPrevDirty; /* Dirty pages */
u32 notUsed; /* Buffer space */
#ifdef SQLITE_CHECK_PAGES #ifdef SQLITE_CHECK_PAGES
u32 pageHash; u32 pageHash;
#endif #endif
@ -207,24 +209,6 @@ struct PgHistory {
#define PGHDR_TO_HIST(P,PGR) \ #define PGHDR_TO_HIST(P,PGR) \
((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra]) ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
/*
** How big to make the hash table used for locating in-memory pages
** by page number. This macro looks a little silly, but is evaluated
** at compile-time, not run-time (at least for gcc this is true).
*/
#define N_PG_HASH (\
(MAX_PAGES>1024)?2048: \
(MAX_PAGES>512)?1024: \
(MAX_PAGES>256)?512: \
(MAX_PAGES>128)?256: \
(MAX_PAGES>64)?128:64 \
)
/*
** Hash a page number
*/
#define pager_hash(PN) ((PN)&(N_PG_HASH-1))
/* /*
** A open page cache is an instance of the following structure. ** A open page cache is an instance of the following structure.
** **
@ -248,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 */
@ -256,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() */
@ -280,6 +264,7 @@ struct Pager {
PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */
PgHdr *pAll; /* List of all pages */ PgHdr *pAll; /* List of all pages */
PgHdr *pStmt; /* List of pages in the statement subjournal */ PgHdr *pStmt; /* List of pages in the statement subjournal */
PgHdr *pDirty; /* List of all dirty pages */
i64 journalOff; /* Current byte offset in the journal file */ i64 journalOff; /* Current byte offset in the journal file */
i64 journalHdr; /* Byte offset to previous journal header */ i64 journalHdr; /* Byte offset to previous journal header */
i64 stmtHdrOff; /* First journal header written this statement */ i64 stmtHdrOff; /* First journal header written this statement */
@ -294,7 +279,8 @@ struct Pager {
void (*xReiniter)(void*,int); /* Call this routine when reloading pages */ void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void *pCodecArg; /* First argument to xCodec() */ void *pCodecArg; /* First argument to xCodec() */
PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */ int nHash; /* Size of the pager hash table */
PgHdr **aHash; /* Hash table to map page number to PgHdr */
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
Pager *pNext; /* Linked list of pagers in this thread */ Pager *pNext; /* Linked list of pagers in this thread */
#endif #endif
@ -365,7 +351,9 @@ static const unsigned char aJournalMagic[] = {
/* /*
** The default size of a disk sector ** The default size of a disk sector
*/ */
#define PAGER_SECTOR_SIZE 512 #ifndef PAGER_SECTOR_SIZE
# 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
@ -385,14 +373,14 @@ static const unsigned char aJournalMagic[] = {
/* /*
** Enable reference count tracking (for debugging) here: ** Enable reference count tracking (for debugging) here:
*/ */
#ifdef SQLITE_DEBUG #ifdef SQLITE_TEST
int pager3_refinfo_enable = 0; int pager3_refinfo_enable = 0;
static void pager_refinfo(PgHdr *p){ static void pager_refinfo(PgHdr *p){
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 */
} }
@ -401,6 +389,38 @@ static const unsigned char aJournalMagic[] = {
# define REFINFO(X) # define REFINFO(X)
#endif #endif
/*
** Change the size of the pager hash table to N. N must be a power
** of two.
*/
static void pager_resize_hash_table(Pager *pPager, int N){
PgHdr **aHash, *pPg;
assert( N>0 && (N&(N-1))==0 );
aHash = sqliteMalloc( sizeof(aHash[0])*N );
if( aHash==0 ){
/* Failure to rehash is not an error. It is only a performance hit. */
return;
}
sqliteFree(pPager->aHash);
pPager->nHash = N;
pPager->aHash = aHash;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
int h;
if( pPg->pgno==0 ){
assert( pPg->pNextHash==0 && pPg->pPrevHash==0 );
continue;
}
h = pPg->pgno & (N-1);
pPg->pNextHash = aHash[h];
if( aHash[h] ){
aHash[h]->pPrevHash = pPg;
}
aHash[h] = pPg;
pPg->pPrevHash = 0;
}
}
/* /*
** Read a 32-bit integer from the given file descriptor. Store the integer ** Read a 32-bit integer from the given file descriptor. Store the integer
** that is read in *pRes. Return SQLITE_OK if everything worked, or an ** that is read in *pRes. Return SQLITE_OK if everything worked, or an
@ -459,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;
} }
@ -820,13 +841,32 @@ static void page_remove_from_stmt_list(PgHdr *pPg){
** a pointer to the page or NULL if not found. ** a pointer to the page or NULL if not found.
*/ */
static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
PgHdr *p = pPager->aHash[pager_hash(pgno)]; PgHdr *p;
if( pPager->aHash==0 ) return 0;
p = pPager->aHash[pgno & (pPager->nHash-1)];
while( p && p->pgno!=pgno ){ while( p && p->pgno!=pgno ){
p = p->pNextHash; p = p->pNextHash;
} }
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
@ -844,16 +884,16 @@ static void pager_reset(Pager *pPager){
pPager->pFirstSynced = 0; pPager->pFirstSynced = 0;
pPager->pLast = 0; pPager->pLast = 0;
pPager->pAll = 0; pPager->pAll = 0;
memset(pPager->aHash, 0, sizeof(pPager->aHash)); pPager->nHash = 0;
sqliteFree(pPager->aHash);
pPager->nPage = 0; pPager->nPage = 0;
pPager->aHash = 0;
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) );
} }
/* /*
@ -892,6 +932,7 @@ static int pager_unwritelock(Pager *pPager){
pPg->pageHash = pager_pagehash(pPg); pPg->pageHash = pager_pagehash(pPg);
#endif #endif
} }
pPager->pDirty = 0;
pPager->dirtyCache = 0; pPager->dirtyCache = 0;
pPager->nRec = 0; pPager->nRec = 0;
}else{ }else{
@ -904,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;
} }
@ -937,6 +979,9 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
return cksum; return cksum;
} }
/* Forward declaration */
static void makeClean(PgHdr*);
/* /*
** Read a single page from the journal file opened on file descriptor ** Read a single page from the journal file opened on file descriptor
** jfd. Playback this one page. ** jfd. Playback this one page.
@ -1014,7 +1059,9 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize); rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize);
} }
if( pPg ) pPg->dirty = 0; if( pPg ){
makeClean(pPg);
}
} }
if( pPg ){ if( pPg ){
/* No page should ever be explicitly rolled back that is in use, except /* No page should ever be explicitly rolled back that is in use, except
@ -1164,6 +1211,7 @@ static int pager_reload_cache(Pager *pPager){
pPg->pageHash = pager_pagehash(pPg); pPg->pageHash = pager_pagehash(pPg);
#endif #endif
} }
pPager->pDirty = 0;
return rc; return rc;
} }
@ -1312,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;
} }
} }
@ -1388,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.
@ -1507,7 +1560,9 @@ void sqlite3pager_set_safety_level(Pager *pPager, int level, int full_fsync){
** attempts to open a temporary file. This information is used for ** attempts to open a temporary file. This information is used for
** testing and analysis only. ** testing and analysis only.
*/ */
#ifdef SQLITE_TEST
int sqlite3_opentemp_count = 0; int sqlite3_opentemp_count = 0;
#endif
/* /*
** Open a temporary file. Write the name of the file into zFile ** Open a temporary file. Write the name of the file into zFile
@ -1521,7 +1576,9 @@ int sqlite3_opentemp_count = 0;
static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){ static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
int cnt = 8; int cnt = 8;
int rc; int rc;
#ifdef SQLITE_TEST
sqlite3_opentemp_count++; /* Used for testing and analysis only */ sqlite3_opentemp_count++; /* Used for testing and analysis only */
#endif
do{ do{
cnt--; cnt--;
sqlite3OsTempFileName(zFile); sqlite3OsTempFileName(zFile);
@ -1552,7 +1609,7 @@ int sqlite3pager_open(
){ ){
Pager *pPager = 0; Pager *pPager = 0;
char *zFullPathname = 0; char *zFullPathname = 0;
int nameLen = 0; /* Compiler is wrong. This is always initialized before use */ int nameLen; /* Compiler is wrong. This is always initialized before use */
OsFile *fd; OsFile *fd;
int rc = SQLITE_OK; int rc = SQLITE_OK;
int i; int i;
@ -1761,14 +1818,19 @@ 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;
} }
/* /*
@ -1782,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 ){
@ -1805,12 +1868,25 @@ int sqlite3pager_pagecount(Pager *pPager){
return (int)n; return (int)n;
} }
#ifndef SQLITE_OMIT_MEMORYDB
/*
** Clear a PgHistory block
*/
static void clearHistory(PgHistory *pHist){
sqliteFree(pHist->pOrig);
sqliteFree(pHist->pStmt);
pHist->pOrig = 0;
pHist->pStmt = 0;
}
#else
#define clearHistory(x)
#endif
/* /*
** Forward declaration ** Forward declaration
*/ */
static int syncJournal(Pager*); static int syncJournal(Pager*);
static void clearHistory(PgHistory*);
/* /*
** Unlink pPg from it's hash chain. Also set the page number to 0 to indicate ** Unlink pPg from it's hash chain. Also set the page number to 0 to indicate
@ -1820,18 +1896,17 @@ static void clearHistory(PgHistory*);
*/ */
static void unlinkHashChain(Pager *pPager, PgHdr *pPg){ static void unlinkHashChain(Pager *pPager, PgHdr *pPg){
if( pPg->pgno==0 ){ if( pPg->pgno==0 ){
/* If the page number is zero, then this page is not in any hash chain. */ assert( pPg->pNextHash==0 && pPg->pPrevHash==0 );
return; return;
} }
if( pPg->pNextHash ){ if( pPg->pNextHash ){
pPg->pNextHash->pPrevHash = pPg->pPrevHash; pPg->pNextHash->pPrevHash = pPg->pPrevHash;
} }
if( pPg->pPrevHash ){ if( pPg->pPrevHash ){
assert( pPager->aHash[pager_hash(pPg->pgno)]!=pPg ); assert( pPager->aHash[pPg->pgno & (pPager->nHash-1)]!=pPg );
pPg->pPrevHash->pNextHash = pPg->pNextHash; pPg->pPrevHash->pNextHash = pPg->pNextHash;
}else{ }else{
int h = pager_hash(pPg->pgno); int h = pPg->pgno & (pPager->nHash-1);
assert( pPager->aHash[h]==pPg );
pPager->aHash[h] = pPg->pNextHash; pPager->aHash[h] = pPg->pNextHash;
} }
if( MEMDB ){ if( MEMDB ){
@ -1895,6 +1970,7 @@ static void memoryTruncate(Pager *pPager){
}else{ }else{
*ppPg = pPg->pNextAll; *ppPg = pPg->pNextAll;
unlinkPage(pPg); unlinkPage(pPg);
makeClean(pPg);
sqliteFree(pPg); sqliteFree(pPg);
pPager->nPage--; pPager->nPage--;
} }
@ -1914,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{
@ -1935,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;
@ -1981,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
@ -1993,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 ){
@ -2061,7 +2107,7 @@ int sqlite3pager_close(Pager *pPager){
pTmp->pNext = pPager->pNext; pTmp->pNext = pPager->pNext;
} }
#endif #endif
sqliteFree(pPager->aHash);
sqliteFree(pPager); sqliteFree(pPager);
return SQLITE_OK; return SQLITE_OK;
} }
@ -2223,6 +2269,68 @@ static int syncJournal(Pager *pPager){
return rc; return rc;
} }
/*
** Merge two lists of pages connected by pDirty and in pgno order.
** Do not both fixing the pPrevDirty pointers.
*/
static PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB){
PgHdr result, *pTail;
pTail = &result;
while( pA && pB ){
if( pA->pgno<pB->pgno ){
pTail->pDirty = pA;
pTail = pA;
pA = pA->pDirty;
}else{
pTail->pDirty = pB;
pTail = pB;
pB = pB->pDirty;
}
}
if( pA ){
pTail->pDirty = pA;
}else if( pB ){
pTail->pDirty = pB;
}else{
pTail->pDirty = 0;
}
return result.pDirty;
}
/*
** Sort the list of pages in accending order by pgno. Pages are
** connected by pDirty pointers. The pPrevDirty pointers are
** corrupted by this sort.
*/
#define N_SORT_BUCKET 25
static PgHdr *sort_pagelist(PgHdr *pIn){
PgHdr *a[N_SORT_BUCKET], *p;
int i;
memset(a, 0, sizeof(a));
while( pIn ){
p = pIn;
pIn = p->pDirty;
p->pDirty = 0;
for(i=0; i<N_SORT_BUCKET-1; i++){
if( a[i]==0 ){
a[i] = p;
break;
}else{
p = merge_pagelist(a[i], p);
a[i] = 0;
}
}
if( i==N_SORT_BUCKET-1 ){
a[i] = merge_pagelist(a[i], p);
}
}
p = a[0];
for(i=1; i<N_SORT_BUCKET; i++){
p = merge_pagelist(p, a[i]);
}
return p;
}
/* /*
** Given a list of pages (connected by the PgHdr.pDirty pointer) write ** Given a list of pages (connected by the PgHdr.pDirty pointer) write
** every one of those pages out to the database file and mark them all ** every one of those pages out to the database file and mark them all
@ -2256,6 +2364,7 @@ static int pager_write_pagelist(PgHdr *pList){
return rc; return rc;
} }
pList = sort_pagelist(pList);
while( pList ){ while( pList ){
assert( pList->dirty ); assert( pList->dirty );
rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
@ -2292,15 +2401,7 @@ static int pager_write_pagelist(PgHdr *pList){
** collected even if they are still in use. ** collected even if they are still in use.
*/ */
static PgHdr *pager_get_all_dirty_pages(Pager *pPager){ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
PgHdr *p, *pList; return pPager->pDirty;
pList = 0;
for(p=pPager->pAll; p; p=p->pNextAll){
if( p->dirty ){
p->pDirty = pList;
pList = p;
}
}
return pList;
} }
/* /*
@ -2375,6 +2476,8 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
if( pPg->dirty ){ if( pPg->dirty ){
int rc; int rc;
assert( pPg->needSync==0 ); assert( pPg->needSync==0 );
makeClean(pPg);
pPg->dirty = 1;
pPg->pDirty = 0; pPg->pDirty = 0;
rc = pager_write_pagelist( pPg ); rc = pager_write_pagelist( pPg );
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -2476,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);
} }
@ -2557,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;
@ -2573,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;
@ -2605,6 +2706,13 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
TEST_INCR(pPager->nMiss); TEST_INCR(pPager->nMiss);
if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ){ if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ){
/* Create a new page */ /* Create a new page */
if( pPager->nPage>=pPager->nHash ){
pager_resize_hash_table(pPager,
pPager->nHash<256 ? 256 : pPager->nHash*2);
if( pPager->nHash==0 ){
return SQLITE_NOMEM;
}
}
pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
+ sizeof(u32) + pPager->nExtra + sizeof(u32) + pPager->nExtra
+ MEMDB*sizeof(PgHistory) ); + MEMDB*sizeof(PgHistory) );
@ -2646,7 +2754,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
}else{ }else{
page_remove_from_stmt_list(pPg); page_remove_from_stmt_list(pPg);
} }
pPg->dirty = 0; makeClean(pPg);
pPg->nRef = 1; pPg->nRef = 1;
REFINFO(pPg); REFINFO(pPg);
@ -2674,26 +2782,18 @@ 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);
} }
} }
/* Link the page into the page hash table */ /* Link the page into the page hash table */
h = pager_hash(pgno); h = pgno & (pPager->nHash-1);
assert( pgno!=0 );
pPg->pNextHash = pPager->aHash[h]; pPg->pNextHash = pPager->aHash[h];
pPager->aHash[h] = pPg; pPager->aHash[h] = pPg;
if( pPg->pNextHash ){ if( pPg->pNextHash ){
@ -2857,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;
} }
@ -2922,6 +3021,42 @@ int sqlite3pager_begin(void *pData, int exFlag){
return rc; return rc;
} }
/*
** Make a page dirty. Set its dirty flag and add it to the dirty
** page list.
*/
static void makeDirty(PgHdr *pPg){
if( pPg->dirty==0 ){
Pager *pPager = pPg->pPager;
pPg->dirty = 1;
pPg->pDirty = pPager->pDirty;
if( pPager->pDirty ){
pPager->pDirty->pPrevDirty = pPg;
}
pPg->pPrevDirty = 0;
pPager->pDirty = pPg;
}
}
/*
** Make a page clean. Clear its dirty bit and remove it from the
** dirty page list.
*/
static void makeClean(PgHdr *pPg){
if( pPg->dirty ){
pPg->dirty = 0;
if( pPg->pDirty ){
pPg->pDirty->pPrevDirty = pPg->pPrevDirty;
}
if( pPg->pPrevDirty ){
pPg->pPrevDirty->pDirty = pPg->pDirty;
}else{
pPg->pPager->pDirty = pPg->pDirty;
}
}
}
/* /*
** Mark a data page as writeable. The page is written into the journal ** Mark a data page as writeable. The page is written into the journal
** if it is not there already. This routine must be called before making ** if it is not there already. This routine must be called before making
@ -2960,7 +3095,7 @@ int sqlite3pager_write(void *pData){
/* Mark the page as dirty. If the page has already been written /* Mark the page as dirty. If the page has already been written
** to the journal then we can return right away. ** to the journal then we can return right away.
*/ */
pPg->dirty = 1; makeDirty(pPg);
if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){ if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
pPager->dirtyCache = 1; pPager->dirtyCache = 1;
}else{ }else{
@ -3081,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 ){
@ -3156,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.
@ -3167,7 +3304,7 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
*/ */
}else{ }else{
TRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager)); TRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager));
pPg->dirty = 0; makeClean(pPg);
#ifdef SQLITE_CHECK_PAGES #ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg); pPg->pageHash = pager_pagehash(pPg);
#endif #endif
@ -3185,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 );
@ -3206,20 +3344,6 @@ void sqlite3pager_dont_rollback(void *pData){
} }
#ifndef SQLITE_OMIT_MEMORYDB
/*
** Clear a PgHistory block
*/
static void clearHistory(PgHistory *pHist){
sqliteFree(pHist->pOrig);
sqliteFree(pHist->pStmt);
pHist->pOrig = 0;
pHist->pStmt = 0;
}
#else
#define clearHistory(x)
#endif
/* /*
** Commit all changes to the database and release the write lock. ** Commit all changes to the database and release the write lock.
** **
@ -3249,6 +3373,7 @@ int sqlite3pager_commit(Pager *pPager){
pPg->pPrevStmt = pPg->pNextStmt = 0; pPg->pPrevStmt = pPg->pNextStmt = 0;
pPg = pPg->pDirty; pPg = pPg->pDirty;
} }
pPager->pDirty = 0;
#ifndef NDEBUG #ifndef NDEBUG
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
@ -3266,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;
} }
@ -3316,12 +3439,11 @@ int sqlite3pager_rollback(Pager *pPager){
p->inJournal = 0; p->inJournal = 0;
p->inStmt = 0; p->inStmt = 0;
p->pPrevStmt = p->pNextStmt = 0; p->pPrevStmt = p->pNextStmt = 0;
if( pPager->xReiniter ){ if( pPager->xReiniter ){
pPager->xReiniter(PGHDR_TO_DATA(p), pPager->pageSize); pPager->xReiniter(PGHDR_TO_DATA(p), pPager->pageSize);
} }
} }
pPager->pDirty = 0;
pPager->pStmt = 0; pPager->pStmt = 0;
pPager->dbSize = pPager->origDbSize; pPager->dbSize = pPager->origDbSize;
memoryTruncate(pPager); memoryTruncate(pPager);
@ -3332,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;
} }
@ -3369,6 +3490,14 @@ int sqlite3pager_isreadonly(Pager *pPager){
return pPager->readOnly; return pPager->readOnly;
} }
/*
** Return the number of references to the pager.
*/
int sqlite3pager_refcount(Pager *pPager){
return pPager->nRef;
}
#ifdef SQLITE_TEST
/* /*
** This routine is used for testing and analysis only. ** This routine is used for testing and analysis only.
*/ */
@ -3380,15 +3509,14 @@ int *sqlite3pager_stats(Pager *pPager){
a[3] = pPager->dbSize; a[3] = pPager->dbSize;
a[4] = pPager->state; a[4] = pPager->state;
a[5] = pPager->errCode; a[5] = pPager->errCode;
#ifdef SQLITE_TEST
a[6] = pPager->nHit; a[6] = pPager->nHit;
a[7] = pPager->nMiss; a[7] = pPager->nMiss;
a[8] = pPager->nOvfl; a[8] = pPager->nOvfl;
a[9] = pPager->nRead; a[9] = pPager->nRead;
a[10] = pPager->nWrite; a[10] = pPager->nWrite;
#endif
return a; return a;
} }
#endif
/* /*
** Set the statement rollback point. ** Set the statement rollback point.
@ -3401,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 ){
@ -3716,7 +3845,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
if( pPgOld ){ if( pPgOld ){
assert( pPgOld->nRef==0 ); assert( pPgOld->nRef==0 );
unlinkHashChain(pPager, pPgOld); unlinkHashChain(pPager, pPgOld);
pPgOld->dirty = 0; makeClean(pPgOld);
if( pPgOld->needSync ){ if( pPgOld->needSync ){
assert( pPgOld->inJournal ); assert( pPgOld->inJournal );
pPg->inJournal = 1; pPg->inJournal = 1;
@ -3726,8 +3855,9 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
} }
/* Change the page number for pPg and insert it into the new hash-chain. */ /* Change the page number for pPg and insert it into the new hash-chain. */
assert( pgno!=0 );
pPg->pgno = pgno; pPg->pgno = pgno;
h = pager_hash(pgno); h = pgno & (pPager->nHash-1);
if( pPager->aHash[h] ){ if( pPager->aHash[h] ){
assert( pPager->aHash[h]->pPrevHash==0 ); assert( pPager->aHash[h]->pPrevHash==0 );
pPager->aHash[h]->pPrevHash = pPg; pPager->aHash[h]->pPrevHash = pPg;
@ -3736,7 +3866,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
pPager->aHash[h] = pPg; pPager->aHash[h] = pPg;
pPg->pPrevHash = 0; pPg->pPrevHash = 0;
pPg->dirty = 1; makeDirty(pPg);
pPager->dirtyCache = 1; pPager->dirtyCache = 1;
if( needSyncPgno ){ if( needSyncPgno ){
@ -3757,7 +3887,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
pPager->needSync = 1; pPager->needSync = 1;
DATA_TO_PGHDR(pNeedSync)->needSync = 1; DATA_TO_PGHDR(pNeedSync)->needSync = 1;
DATA_TO_PGHDR(pNeedSync)->inJournal = 1; DATA_TO_PGHDR(pNeedSync)->inJournal = 1;
DATA_TO_PGHDR(pNeedSync)->dirty = 1; makeDirty(DATA_TO_PGHDR(pNeedSync));
sqlite3pager_unref(pNeedSync); sqlite3pager_unref(pNeedSync);
} }

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);
@ -98,6 +98,7 @@ int sqlite3pager_stmt_commit(Pager*);
int sqlite3pager_stmt_rollback(Pager*); int sqlite3pager_stmt_rollback(Pager*);
void sqlite3pager_dont_rollback(void*); void sqlite3pager_dont_rollback(void*);
void sqlite3pager_dont_write(Pager*, Pgno); void sqlite3pager_dont_write(Pager*, Pgno);
int sqlite3pager_refcount(Pager*);
int *sqlite3pager_stats(Pager*); int *sqlite3pager_stats(Pager*);
void sqlite3pager_set_safety_level(Pager*,int,int); void sqlite3pager_set_safety_level(Pager*,int,int);
const char *sqlite3pager_filename(Pager*); const char *sqlite3pager_filename(Pager*);

File diff suppressed because it is too large Load Diff

View File

@ -53,99 +53,101 @@
#define TK_TRIGGER 53 #define TK_TRIGGER 53
#define TK_VACUUM 54 #define TK_VACUUM 54
#define TK_VIEW 55 #define TK_VIEW 55
#define TK_REINDEX 56 #define TK_VIRTUAL 56
#define TK_RENAME 57 #define TK_REINDEX 57
#define TK_CTIME_KW 58 #define TK_RENAME 58
#define TK_OR 59 #define TK_CTIME_KW 59
#define TK_AND 60 #define TK_ANY 60
#define TK_IS 61 #define TK_OR 61
#define TK_BETWEEN 62 #define TK_AND 62
#define TK_IN 63 #define TK_IS 63
#define TK_ISNULL 64 #define TK_BETWEEN 64
#define TK_NOTNULL 65 #define TK_IN 65
#define TK_NE 66 #define TK_ISNULL 66
#define TK_EQ 67 #define TK_NOTNULL 67
#define TK_GT 68 #define TK_NE 68
#define TK_LE 69 #define TK_EQ 69
#define TK_LT 70 #define TK_GT 70
#define TK_GE 71 #define TK_LE 71
#define TK_ESCAPE 72 #define TK_LT 72
#define TK_BITAND 73 #define TK_GE 73
#define TK_BITOR 74 #define TK_ESCAPE 74
#define TK_LSHIFT 75 #define TK_BITAND 75
#define TK_RSHIFT 76 #define TK_BITOR 76
#define TK_PLUS 77 #define TK_LSHIFT 77
#define TK_MINUS 78 #define TK_RSHIFT 78
#define TK_STAR 79 #define TK_PLUS 79
#define TK_SLASH 80 #define TK_MINUS 80
#define TK_REM 81 #define TK_STAR 81
#define TK_CONCAT 82 #define TK_SLASH 82
#define TK_UMINUS 83 #define TK_REM 83
#define TK_UPLUS 84 #define TK_CONCAT 84
#define TK_BITNOT 85 #define TK_COLLATE 85
#define TK_STRING 86 #define TK_UMINUS 86
#define TK_JOIN_KW 87 #define TK_UPLUS 87
#define TK_CONSTRAINT 88 #define TK_BITNOT 88
#define TK_DEFAULT 89 #define TK_STRING 89
#define TK_NULL 90 #define TK_JOIN_KW 90
#define TK_PRIMARY 91 #define TK_CONSTRAINT 91
#define TK_UNIQUE 92 #define TK_DEFAULT 92
#define TK_CHECK 93 #define TK_NULL 93
#define TK_REFERENCES 94 #define TK_PRIMARY 94
#define TK_COLLATE 95 #define TK_UNIQUE 95
#define TK_AUTOINCR 96 #define TK_CHECK 96
#define TK_ON 97 #define TK_REFERENCES 97
#define TK_DELETE 98 #define TK_AUTOINCR 98
#define TK_UPDATE 99 #define TK_ON 99
#define TK_INSERT 100 #define TK_DELETE 100
#define TK_SET 101 #define TK_UPDATE 101
#define TK_DEFERRABLE 102 #define TK_INSERT 102
#define TK_FOREIGN 103 #define TK_SET 103
#define TK_DROP 104 #define TK_DEFERRABLE 104
#define TK_UNION 105 #define TK_FOREIGN 105
#define TK_ALL 106 #define TK_DROP 106
#define TK_EXCEPT 107 #define TK_UNION 107
#define TK_INTERSECT 108 #define TK_ALL 108
#define TK_SELECT 109 #define TK_EXCEPT 109
#define TK_DISTINCT 110 #define TK_INTERSECT 110
#define TK_DOT 111 #define TK_SELECT 111
#define TK_FROM 112 #define TK_DISTINCT 112
#define TK_JOIN 113 #define TK_DOT 113
#define TK_USING 114 #define TK_FROM 114
#define TK_ORDER 115 #define TK_JOIN 115
#define TK_BY 116 #define TK_USING 116
#define TK_GROUP 117 #define TK_ORDER 117
#define TK_HAVING 118 #define TK_BY 118
#define TK_LIMIT 119 #define TK_GROUP 119
#define TK_WHERE 120 #define TK_HAVING 120
#define TK_INTO 121 #define TK_LIMIT 121
#define TK_VALUES 122 #define TK_WHERE 122
#define TK_INTEGER 123 #define TK_INTO 123
#define TK_FLOAT 124 #define TK_VALUES 124
#define TK_BLOB 125 #define TK_INTEGER 125
#define TK_REGISTER 126 #define TK_FLOAT 126
#define TK_VARIABLE 127 #define TK_BLOB 127
#define TK_CASE 128 #define TK_REGISTER 128
#define TK_WHEN 129 #define TK_VARIABLE 129
#define TK_THEN 130 #define TK_CASE 130
#define TK_ELSE 131 #define TK_WHEN 131
#define TK_INDEX 132 #define TK_THEN 132
#define TK_ALTER 133 #define TK_ELSE 133
#define TK_TO 134 #define TK_INDEX 134
#define TK_ADD 135 #define TK_ALTER 135
#define TK_COLUMNKW 136 #define TK_TO 136
#define TK_TO_TEXT 137 #define TK_ADD 137
#define TK_TO_BLOB 138 #define TK_COLUMNKW 138
#define TK_TO_NUMERIC 139 #define TK_TO_TEXT 139
#define TK_TO_INT 140 #define TK_TO_BLOB 140
#define TK_TO_REAL 141 #define TK_TO_NUMERIC 141
#define TK_END_OF_FILE 142 #define TK_TO_INT 142
#define TK_ILLEGAL 143 #define TK_TO_REAL 143
#define TK_SPACE 144 #define TK_END_OF_FILE 144
#define TK_UNCLOSED_STRING 145 #define TK_ILLEGAL 145
#define TK_COMMENT 146 #define TK_SPACE 146
#define TK_FUNCTION 147 #define TK_UNCLOSED_STRING 147
#define TK_COLUMN 148 #define TK_COMMENT 148
#define TK_AGG_FUNCTION 149 #define TK_FUNCTION 149
#define TK_AGG_COLUMN 150 #define TK_COLUMN 150
#define TK_CONST_FUNC 151 #define TK_AGG_FUNCTION 151
#define TK_AGG_COLUMN 152
#define TK_CONST_FUNC 153

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 */
@ -780,7 +805,7 @@ void sqlite3Pragma(
** useful if invoked immediately after the main database i ** useful if invoked immediately after the main database i
*/ */
if( sqlite3StrICmp(zLeft, "encoding")==0 ){ if( sqlite3StrICmp(zLeft, "encoding")==0 ){
static struct EncName { static const struct EncName {
char *zName; char *zName;
u8 enc; u8 enc;
} encnames[] = { } encnames[] = {
@ -790,12 +815,11 @@ void sqlite3Pragma(
{ "UTF16le", SQLITE_UTF16LE }, { "UTF16le", SQLITE_UTF16LE },
{ "UTF-16be", SQLITE_UTF16BE }, { "UTF-16be", SQLITE_UTF16BE },
{ "UTF16be", SQLITE_UTF16BE }, { "UTF16be", SQLITE_UTF16BE },
{ "UTF-16", 0 /* Filled in at run-time */ }, { "UTF-16", 0 }, /* SQLITE_UTF16NATIVE */
{ "UTF16", 0 /* Filled in at run-time */ }, { "UTF16", 0 }, /* SQLITE_UTF16NATIVE */
{ 0, 0 } { 0, 0 }
}; };
struct EncName *pEnc; const struct EncName *pEnc;
encnames[6].enc = encnames[7].enc = SQLITE_UTF16NATIVE;
if( !zRight ){ /* "PRAGMA encoding" */ if( !zRight ){ /* "PRAGMA encoding" */
if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
@ -820,7 +844,7 @@ void sqlite3Pragma(
){ ){
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
ENC(pParse->db) = pEnc->enc; ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
break; break;
} }
} }
@ -890,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 */
@ -941,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

@ -28,6 +28,7 @@ static void corruptSchema(InitData *pData, const char *zExtra){
sqlite3SetString(pData->pzErrMsg, "malformed database schema", sqlite3SetString(pData->pzErrMsg, "malformed database schema",
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
} }
pData->rc = SQLITE_CORRUPT;
} }
/* /*
@ -38,28 +39,28 @@ static void corruptSchema(InitData *pData, const char *zExtra){
** Each callback contains the following information: ** Each callback contains the following information:
** **
** argv[0] = name of thing being created ** argv[0] = name of thing being created
** argv[1] = root page number for table or index. NULL 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;
DbClearProperty(db, iDb, DB_Empty);
if( sqlite3MallocFailed() ){ if( sqlite3MallocFailed() ){
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.
@ -76,13 +77,14 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
db->init.iDb = 0; db->init.iDb = 0;
assert( rc!=SQLITE_OK || zErr==0 ); assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){ if( SQLITE_OK!=rc ){
pData->rc = rc;
if( rc==SQLITE_NOMEM ){ if( rc==SQLITE_NOMEM ){
sqlite3FailedMalloc(); sqlite3FailedMalloc();
}else{ }else if( rc!=SQLITE_INTERRUPT ){
corruptSchema(pData, zErr); corruptSchema(pData, zErr);
} }
sqlite3_free(zErr); sqlite3_free(zErr);
return rc; return 1;
} }
}else{ }else{
/* If the SQL column is blank it means this is an index that /* If the SQL column is blank it means this is an index that
@ -121,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;
@ -173,15 +174,14 @@ 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!=SQLITE_OK ){ if( rc ){
sqlite3SafetyOn(db); sqlite3SafetyOn(db);
return rc; return initData.rc;
} }
pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
if( pTab ){ if( pTab ){
@ -211,7 +211,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** meta[1] File format of schema layer. ** meta[1] File format of schema layer.
** meta[2] Size of the page cache. ** meta[2] Size of the page cache.
** meta[3] Use freelist if 0. Autovacuum if greater than zero. ** meta[3] Use freelist if 0. Autovacuum if greater than zero.
** meta[4] Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE ** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE
** meta[5] The user cookie. Used by the application. ** meta[5] The user cookie. Used by the application.
** meta[6] ** meta[6]
** meta[7] ** meta[7]
@ -291,10 +291,11 @@ 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;
sqlite3SafetyOn(db); sqlite3SafetyOn(db);
sqliteFree(zSql); sqliteFree(zSql);
#ifndef SQLITE_OMIT_ANALYZE #ifndef SQLITE_OMIT_ANALYZE
@ -444,12 +445,13 @@ 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 */
){ ){
Parse sParse; Parse sParse;
char *zErrMsg = 0; char *zErrMsg = 0;
@ -499,7 +501,12 @@ int sqlite3_prepare(
if( sParse.rc==SQLITE_SCHEMA ){ if( sParse.rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, 0);
} }
if( pzTail ) *pzTail = sParse.zTail; if( sqlite3MallocFailed() ){
sParse.rc = SQLITE_NOMEM;
}
if( pzTail ){
*pzTail = sParse.zTail;
}
rc = sParse.rc; rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN #ifndef SQLITE_OMIT_EXPLAIN
@ -524,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);
@ -538,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 */
){ ){
@ -565,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 ){
@ -580,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

@ -230,7 +230,7 @@ static int vxprintf(
char buf[etBUFSIZE]; /* Conversion buffer */ char buf[etBUFSIZE]; /* Conversion buffer */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
etByte errorflag = 0; /* True if an error is encountered */ etByte errorflag = 0; /* True if an error is encountered */
etByte xtype = 0; /* Conversion paradigm */ etByte xtype; /* Conversion paradigm */
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
static const char spaces[] = static const char spaces[] =
" "; " ";
@ -333,6 +333,8 @@ static int vxprintf(
infop = &fmtinfo[idx]; infop = &fmtinfo[idx];
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){ if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
xtype = infop->type; xtype = infop->type;
}else{
return -1;
} }
break; break;
} }
@ -804,29 +806,28 @@ char *sqlite3MPrintf(const char *zFormat, ...){
} }
/* /*
** Print into memory obtained from malloc(). Do not use the internal ** Print into memory obtained from sqlite3_malloc(). Omit the internal
** %-conversion extensions. This routine is for use by external users. ** %-conversion extensions.
*/
char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char zBase[SQLITE_PRINT_BUF_SIZE];
return base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
}
/*
** Print into memory obtained from sqlite3_malloc()(). Omit the internal
** %-conversion extensions.
*/ */
char *sqlite3_mprintf(const char *zFormat, ...){ char *sqlite3_mprintf(const char *zFormat, ...){
va_list ap; va_list ap;
char *z; char *z;
char zBuf[200]; char zBase[SQLITE_PRINT_BUF_SIZE];
va_start(ap, zFormat);
va_start(ap,zFormat); z = base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
z = base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap); va_end(ap);
return z; return z;
} }
/* This is the varargs version of sqlite3_mprintf.
*/
char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char zBuf[200];
return base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
}
/* /*
** sqlite3_snprintf() works like snprintf() except that it ignores the ** sqlite3_snprintf() works like snprintf() except that it ignores the
** current locale settings. This is important for SQLite because we ** current locale settings. This is important for SQLite because we
@ -856,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

@ -72,9 +72,9 @@ Select *sqlite3SelectNew(
pNew->pOffset = pOffset; pNew->pOffset = pOffset;
pNew->iLimit = -1; pNew->iLimit = -1;
pNew->iOffset = -1; pNew->iOffset = -1;
pNew->addrOpenVirt[0] = -1; pNew->addrOpenEphm[0] = -1;
pNew->addrOpenVirt[1] = -1; pNew->addrOpenEphm[1] = -1;
pNew->addrOpenVirt[2] = -1; pNew->addrOpenEphm[2] = -1;
if( pNew==&standin) { if( pNew==&standin) {
clearSelect(pNew); clearSelect(pNew);
pNew = 0; pNew = 0;
@ -187,7 +187,7 @@ static void setToken(Token *p, const char *z){
/* /*
** Create an expression node for an identifier with the name of zName ** Create an expression node for an identifier with the name of zName
*/ */
static Expr *createIdExpr(const char *zName){ Expr *sqlite3CreateIdExpr(const char *zName){
Token dummy; Token dummy;
setToken(&dummy, zName); setToken(&dummy, zName);
return sqlite3Expr(TK_ID, 0, 0, &dummy); return sqlite3Expr(TK_ID, 0, 0, &dummy);
@ -211,22 +211,27 @@ static void addWhereTerm(
Expr *pE2a, *pE2b, *pE2c; Expr *pE2a, *pE2b, *pE2c;
Expr *pE; Expr *pE;
pE1a = createIdExpr(zCol); pE1a = sqlite3CreateIdExpr(zCol);
pE2a = createIdExpr(zCol); pE2a = sqlite3CreateIdExpr(zCol);
if( zAlias1==0 ){ if( zAlias1==0 ){
zAlias1 = pTab1->zName; zAlias1 = pTab1->zName;
} }
pE1b = createIdExpr(zAlias1); pE1b = sqlite3CreateIdExpr(zAlias1);
if( zAlias2==0 ){ if( zAlias2==0 ){
zAlias2 = pTab2->zName; zAlias2 = pTab2->zName;
} }
pE2b = createIdExpr(zAlias2); pE2b = sqlite3CreateIdExpr(zAlias2);
pE1c = sqlite3Expr(TK_DOT, pE1b, pE1a, 0); pE1c = sqlite3ExprOrFree(TK_DOT, pE1b, pE1a, 0);
pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0); pE2c = sqlite3ExprOrFree(TK_DOT, pE2b, pE2a, 0);
pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0); pE = sqlite3ExprOrFree(TK_EQ, pE1c, pE2c, 0);
if( pE ){
ExprSetProperty(pE, EP_FromJoin); ExprSetProperty(pE, EP_FromJoin);
pE->iRightJoinTable = iRightJoinTable; pE->iRightJoinTable = iRightJoinTable;
*ppExpr = sqlite3ExprAnd(*ppExpr, pE); }
pE = sqlite3ExprAnd(*ppExpr, pE);
if( pE ){
*ppExpr = pE;
}
} }
/* /*
@ -296,8 +301,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;
@ -315,7 +320,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;
@ -324,10 +329,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
@ -337,8 +342,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 ){
@ -522,7 +527,7 @@ static int selectInnerLoop(
/* Store the result as data using a unique key. /* Store the result as data using a unique key.
*/ */
case SRT_Table: case SRT_Table:
case SRT_VirtualTab: { case SRT_EphemTab: {
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
if( pOrderBy ){ if( pOrderBy ){
pushOntoSorter(pParse, pOrderBy, p); pushOntoSorter(pParse, pOrderBy, p);
@ -705,7 +710,7 @@ static void generateSortTail(
sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1);
switch( eDest ){ switch( eDest ){
case SRT_Table: case SRT_Table:
case SRT_VirtualTab: { case SRT_EphemTab: {
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Insert, iParm, 0); sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
@ -805,6 +810,7 @@ static const char *columnType(
assert( pExpr->op!=TK_AS ); assert( pExpr->op!=TK_AS );
switch( pExpr->op ){ switch( pExpr->op ){
case TK_AGG_COLUMN:
case TK_COLUMN: { case TK_COLUMN: {
/* The expression is a column. Locate the table the column is being /* The expression is a column. Locate the table the column is being
** extracted from in NameContext.pSrcList. This table may be real ** extracted from in NameContext.pSrcList. This table may be real
@ -840,7 +846,6 @@ static const char *columnType(
} }
assert( pTab ); assert( pTab );
#ifndef SQLITE_OMIT_SUBQUERY
if( pS ){ if( pS ){
/* The "table" is actually a sub-select or a view in the FROM clause /* The "table" is actually a sub-select or a view in the FROM clause
** of the SELECT statement. Return the declaration type and origin ** of the SELECT statement. Return the declaration type and origin
@ -858,9 +863,7 @@ static const char *columnType(
sNC.pParse = pNC->pParse; sNC.pParse = pNC->pParse;
zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol); zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
} }
}else }else if( pTab->pSchema ){
#endif
if( pTab->pSchema ){
/* A real table */ /* A real table */
assert( !pS ); assert( !pS );
if( iCol<0 ) iCol = pTab->iPKey; if( iCol<0 ) iCol = pTab->iPKey;
@ -1068,7 +1071,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;
@ -1101,17 +1104,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
@ -1200,11 +1201,11 @@ static int prepSelectStmt(Parse *pParse, Select *p){
if( pTab==0 ){ if( pTab==0 ){
return 1; return 1;
} }
/* The isTransient flag indicates that the Table structure has been /* The isEphem flag indicates that the Table structure has been
** dynamically allocated and may be freed at any time. In other words, ** dynamically allocated and may be freed at any time. In other words,
** pTab is not pointing to a persistent table structure that defines ** pTab is not pointing to a persistent table structure that defines
** part of the schema. */ ** part of the schema. */
pTab->isTransient = 1; pTab->isEphem = 1;
#endif #endif
}else{ }else{
/* An ordinary table or view name in the FROM clause */ /* An ordinary table or view name in the FROM clause */
@ -1215,8 +1216,8 @@ static int prepSelectStmt(Parse *pParse, Select *p){
return 1; return 1;
} }
pTab->nRef++; pTab->nRef++;
#ifndef SQLITE_OMIT_VIEW #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
if( pTab->pSelect ){ if( pTab->pSelect || IsVirtual(pTab) ){
/* We reach here if the named table is a really a view */ /* We reach here if the named table is a really a view */
if( sqlite3ViewGetColumnNames(pParse, pTab) ){ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
return 1; return 1;
@ -1308,13 +1309,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;
@ -1537,10 +1538,10 @@ static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){
int addr; int addr;
assert( pOrderBy->iECursor==0 ); assert( pOrderBy->iECursor==0 );
pOrderBy->iECursor = pParse->nTab++; pOrderBy->iECursor = pParse->nTab++;
addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenVirtual, addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenEphemeral,
pOrderBy->iECursor, pOrderBy->nExpr+1); pOrderBy->iECursor, pOrderBy->nExpr+1);
assert( p->addrOpenVirt[2] == -1 ); assert( p->addrOpenEphm[2] == -1 );
p->addrOpenVirt[2] = addr; p->addrOpenEphm[2] = addr;
} }
} }
@ -1646,10 +1647,10 @@ static int multiSelect(
/* Create the destination temporary table if necessary /* Create the destination temporary table if necessary
*/ */
if( eDest==SRT_VirtualTab ){ if( eDest==SRT_EphemTab ){
assert( p->pEList ); assert( p->pEList );
assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) ); assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0); aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 0);
eDest = SRT_Table; eDest = SRT_Table;
} }
@ -1711,14 +1712,14 @@ static int multiSelect(
rc = 1; rc = 1;
goto multi_select_end; goto multi_select_end;
} }
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, unionTab, 0); addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, unionTab, 0);
if( priorOp==SRT_Table ){ if( priorOp==SRT_Table ){
assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) ); assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
aSetP2[nSetP2++] = addr; aSetP2[nSetP2++] = addr;
}else{ }else{
assert( p->addrOpenVirt[0] == -1 ); assert( p->addrOpenEphm[0] == -1 );
p->addrOpenVirt[0] = addr; p->addrOpenEphm[0] = addr;
p->pRightmost->usesVirt = 1; p->pRightmost->usesEphm = 1;
} }
createSortingIndex(pParse, p, pOrderBy); createSortingIndex(pParse, p, pOrderBy);
assert( p->pEList ); assert( p->pEList );
@ -1807,10 +1808,10 @@ static int multiSelect(
} }
createSortingIndex(pParse, p, pOrderBy); createSortingIndex(pParse, p, pOrderBy);
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0); addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab1, 0);
assert( p->addrOpenVirt[0] == -1 ); assert( p->addrOpenEphm[0] == -1 );
p->addrOpenVirt[0] = addr; p->addrOpenEphm[0] = addr;
p->pRightmost->usesVirt = 1; p->pRightmost->usesEphm = 1;
assert( p->pEList ); assert( p->pEList );
/* Code the SELECTs to our left into temporary table "tab1". /* Code the SELECTs to our left into temporary table "tab1".
@ -1822,9 +1823,9 @@ static int multiSelect(
/* Code the current SELECT into temporary table "tab2" /* Code the current SELECT into temporary table "tab2"
*/ */
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0); addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab2, 0);
assert( p->addrOpenVirt[1] == -1 ); assert( p->addrOpenEphm[1] == -1 );
p->addrOpenVirt[1] = addr; p->addrOpenEphm[1] = addr;
p->pPrior = 0; p->pPrior = 0;
pLimit = p->pLimit; pLimit = p->pLimit;
p->pLimit = 0; p->pLimit = 0;
@ -1898,15 +1899,17 @@ static int multiSelect(
** SELECT might also skip this part if it has no ORDER BY clause and ** SELECT might also skip this part if it has no ORDER BY clause and
** no temp tables are required. ** no temp tables are required.
*/ */
if( pOrderBy || p->usesVirt ){ if( pOrderBy || p->usesEphm ){
int i; /* Loop counter */ int i; /* Loop counter */
KeyInfo *pKeyInfo; /* Collating sequence for the result set */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */
Select *pLoop; /* For looping through SELECT statements */ Select *pLoop; /* For looping through SELECT statements */
int nKeyCol; /* Number of entries in pKeyInfo->aCol[] */
CollSeq **apColl; CollSeq **apColl;
CollSeq **aCopy; CollSeq **aCopy;
assert( p->pRightmost==p ); assert( p->pRightmost==p );
pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*2*sizeof(CollSeq*) + nCol); nKeyCol = nCol + (pOrderBy ? pOrderBy->nExpr : 0);
pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nKeyCol*(sizeof(CollSeq*) + 1));
if( !pKeyInfo ){ if( !pKeyInfo ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
goto multi_select_end; goto multi_select_end;
@ -1924,15 +1927,16 @@ static int multiSelect(
for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
for(i=0; i<2; i++){ for(i=0; i<2; i++){
int addr = pLoop->addrOpenVirt[i]; int addr = pLoop->addrOpenEphm[i];
if( addr<0 ){ if( addr<0 ){
/* If [0] is unused then [1] is also unused. So we can /* If [0] is unused then [1] is also unused. So we can
** always safely abort as soon as the first unused slot is found */ ** always safely abort as soon as the first unused slot is found */
assert( pLoop->addrOpenVirt[1]<0 ); assert( pLoop->addrOpenEphm[1]<0 );
break; break;
} }
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;
} }
} }
@ -1942,24 +1946,23 @@ static int multiSelect(
int addr; int addr;
u8 *pSortOrder; u8 *pSortOrder;
aCopy = &pKeyInfo->aColl[nCol]; aCopy = &pKeyInfo->aColl[nOrderByExpr];
pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol]; pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol];
memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*)); memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
apColl = pKeyInfo->aColl; apColl = pKeyInfo->aColl;
for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){ for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){
Expr *pExpr = pOTerm->pExpr; Expr *pExpr = pOTerm->pExpr;
char *zName = pOTerm->zName; if( (pExpr->flags & EP_ExpCollate) ){
assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol ); assert( pExpr->pColl!=0 );
if( zName ){ *apColl = pExpr->pColl;
*apColl = sqlite3LocateCollSeq(pParse, zName, -1);
}else{ }else{
*apColl = aCopy[pExpr->iColumn]; *apColl = aCopy[pExpr->iColumn];
} }
*pSortOrder = pOTerm->sortOrder; *pSortOrder = pOTerm->sortOrder;
} }
assert( p->pRightmost==p ); assert( p->pRightmost==p );
assert( p->addrOpenVirt[2]>=0 ); assert( p->addrOpenEphm[2]>=0 );
addr = p->addrOpenVirt[2]; addr = p->addrOpenEphm[2];
sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2); sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2);
pKeyInfo->nField = nOrderByExpr; pKeyInfo->nField = nOrderByExpr;
sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
@ -2010,6 +2013,7 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
assert( pExpr->pList==0 ); assert( pExpr->pList==0 );
pExpr->pList = sqlite3ExprListDup(pNew->pList); pExpr->pList = sqlite3ExprListDup(pNew->pList);
pExpr->iTable = pNew->iTable; pExpr->iTable = pNew->iTable;
pExpr->pTab = pNew->pTab;
pExpr->iColumn = pNew->iColumn; pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg; pExpr->iAgg = pNew->iAgg;
sqlite3TokenCopy(&pExpr->token, &pNew->token); sqlite3TokenCopy(&pExpr->token, &pNew->token);
@ -2171,7 +2175,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;
} }
@ -2188,8 +2192,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;
} }
@ -2228,7 +2231,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
@ -2374,6 +2377,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
pIdx = 0; pIdx = 0;
}else{ }else{
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr); CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
if( pColl==0 ) return 0;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->nColumn>=1 ); assert( pIdx->nColumn>=1 );
if( pIdx->aiColumn[0]==iCol && if( pIdx->aiColumn[0]==iCol &&
@ -2393,8 +2397,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
/* If the output is destined for a temporary table, open that table. /* If the output is destined for a temporary table, open that table.
*/ */
if( eDest==SRT_VirtualTab ){ if( eDest==SRT_EphemTab ){
sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 1); sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 1);
} }
/* Generating code to find the min or the max. Basically all we have /* Generating code to find the min or the max. Basically all we have
@ -2403,7 +2407,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
** or last entry in the main table. ** or last entry in the main table.
*/ */
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
assert( iDb>=0 || pTab->isTransient ); assert( iDb>=0 || pTab->isEphem );
sqlite3CodeVerifySchema(pParse, iDb); sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
base = pSrc->a[0].iCursor; base = pSrc->a[0].iCursor;
@ -2473,8 +2477,14 @@ static int processOrderGroupBy(
Expr *pE = pOrderBy->a[i].pExpr; Expr *pE = pOrderBy->a[i].pExpr;
if( sqlite3ExprIsInteger(pE, &iCol) ){ if( sqlite3ExprIsInteger(pE, &iCol) ){
if( iCol>0 && iCol<=pEList->nExpr ){ if( iCol>0 && iCol<=pEList->nExpr ){
CollSeq *pColl = pE->pColl;
int flags = pE->flags & EP_ExpCollate;
sqlite3ExprDelete(pE); sqlite3ExprDelete(pE);
pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr); pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
if( pColl && flags ){
pE->pColl = pColl;
pE->flags |= flags;
}
}else{ }else{
sqlite3ErrorMsg(pParse, sqlite3ErrorMsg(pParse,
"%s BY column number %d out of range - should be " "%s BY column number %d out of range - should be "
@ -2485,11 +2495,6 @@ static int processOrderGroupBy(
if( sqlite3ExprResolveNames(pNC, pE) ){ if( sqlite3ExprResolveNames(pNC, pE) ){
return 1; return 1;
} }
if( sqlite3ExprIsConstant(pE) ){
sqlite3ErrorMsg(pParse,
"%s BY terms must not be non-integer constants", zType);
return 1;
}
} }
return 0; return 0;
} }
@ -2605,7 +2610,14 @@ 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;
}
} }
/* /*
@ -2635,7 +2647,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
pFunc->iDistinct = -1; pFunc->iDistinct = -1;
}else{ }else{
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList); KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
sqlite3VdbeOp3(v, OP_OpenVirtual, pFunc->iDistinct, 0, sqlite3VdbeOp3(v, OP_OpenEphemeral, pFunc->iDistinct, 0,
(char*)pKeyInfo, P3_KEYINFO_HANDOFF); (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
} }
} }
@ -2775,8 +2787,8 @@ int sqlite3Select(
WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */ WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */
Vdbe *v; /* The virtual machine under construction */ Vdbe *v; /* The virtual machine under construction */
int isAgg; /* True for select lists like "count(*)" */ int isAgg; /* True for select lists like "count(*)" */
ExprList *pEList=NULL; /* List of columns to extract. */ ExprList *pEList; /* List of columns to extract. */
SrcList *pTabList=NULL; /* List of tables to select from */ SrcList *pTabList; /* List of tables to select from */
Expr *pWhere; /* The WHERE clause. May be NULL */ Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
@ -2784,7 +2796,7 @@ int sqlite3Select(
int isDistinct; /* True if the DISTINCT keyword is present */ int isDistinct; /* True if the DISTINCT keyword is present */
int distinct; /* Table to use for the distinct set */ int distinct; /* Table to use for the distinct set */
int rc = 1; /* Value to return from this function */ int rc = 1; /* Value to return from this function */
int addrSortIndex; /* Address of an OP_OpenVirtual instruction */ int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
AggInfo sAggInfo; /* Information used by aggregate queries */ AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */ int iEnd; /* Address of the end of the query */
@ -2872,7 +2884,7 @@ int sqlite3Select(
}else{ }else{
needRestoreContext = 0; needRestoreContext = 0;
} }
sqlite3Select(pParse, pItem->pSelect, SRT_VirtualTab, sqlite3Select(pParse, pItem->pSelect, SRT_EphemTab,
pItem->iCursor, p, i, &isAgg, 0); pItem->iCursor, p, i, &isAgg, 0);
if( needRestoreContext ){ if( needRestoreContext ){
pParse->zAuthContext = zSavedAuthContext; pParse->zAuthContext = zSavedAuthContext;
@ -2907,53 +2919,44 @@ int sqlite3Select(
} }
#endif #endif
/* If there is an ORDER BY clause, resolve any collation sequences /* If there is an ORDER BY clause, then this sorting
** names that have been explicitly specified and create a sorting index. ** index might end up being unused if the data can be
**
** This sorting index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the ** extracted in pre-sorted order. If that is the case, then the
** OP_OpenVirtual instruction will be changed to an OP_Noop once ** OP_OpenEphemeral instruction will be changed to an OP_Noop once
** we figure out that the sorting index is not needed. The addrSortIndex ** we figure out that the sorting index is not needed. The addrSortIndex
** variable is used to facilitate that change. ** variable is used to facilitate that change.
*/ */
if( pOrderBy ){ if( pOrderBy ){
struct ExprList_item *pTerm;
KeyInfo *pKeyInfo; KeyInfo *pKeyInfo;
for(i=0, pTerm=pOrderBy->a; i<pOrderBy->nExpr; i++, pTerm++){
if( pTerm->zName ){
pTerm->pExpr->pColl = sqlite3LocateCollSeq(pParse, pTerm->zName, -1);
}
}
if( pParse->nErr ){ if( pParse->nErr ){
goto select_end; goto select_end;
} }
pKeyInfo = keyInfoFromExprList(pParse, pOrderBy); pKeyInfo = keyInfoFromExprList(pParse, pOrderBy);
pOrderBy->iECursor = pParse->nTab++; pOrderBy->iECursor = pParse->nTab++;
p->addrOpenVirt[2] = addrSortIndex = p->addrOpenEphm[2] = addrSortIndex =
sqlite3VdbeOp3(v, OP_OpenVirtual, pOrderBy->iECursor, pOrderBy->nExpr+2, sqlite3VdbeOp3(v, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+2, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
(char*)pKeyInfo, P3_KEYINFO_HANDOFF);
}else{ }else{
addrSortIndex = -1; addrSortIndex = -1;
} }
/* If the output is destined for a temporary table, open that table.
*/
if( eDest==SRT_EphemTab ){
sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, pEList->nExpr);
}
/* Set the limiter. /* Set the limiter.
*/ */
iEnd = sqlite3VdbeMakeLabel(v); iEnd = sqlite3VdbeMakeLabel(v);
computeLimitRegisters(pParse, p, iEnd); computeLimitRegisters(pParse, p, iEnd);
/* If the output is destined for a temporary table, open that table.
*/
if( eDest==SRT_VirtualTab ){
sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr);
}
/* Open a virtual index to use for the distinct set. /* Open a virtual index to use for the distinct set.
*/ */
if( isDistinct ){ if( isDistinct ){
KeyInfo *pKeyInfo; KeyInfo *pKeyInfo;
distinct = pParse->nTab++; distinct = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, p->pEList); pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
sqlite3VdbeOp3(v, OP_OpenVirtual, distinct, 0, sqlite3VdbeOp3(v, OP_OpenEphemeral, distinct, 0,
(char*)pKeyInfo, P3_KEYINFO_HANDOFF); (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
}else{ }else{
distinct = -1; distinct = -1;
@ -2967,13 +2970,13 @@ int sqlite3Select(
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy);
if( pWInfo==0 ) goto select_end; if( pWInfo==0 ) goto select_end;
/* If sorting index that was created by a prior OP_OpenVirtual /* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenVirtual ** instruction ended up not being needed, then change the OP_OpenEphemeral
** into an OP_Noop. ** into an OP_Noop.
*/ */
if( addrSortIndex>=0 && pOrderBy==0 ){ if( addrSortIndex>=0 && pOrderBy==0 ){
sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); sqlite3VdbeChangeToNoop(v, addrSortIndex, 1);
p->addrOpenVirt[2] = -1; p->addrOpenEphm[2] = -1;
} }
/* Use the standard inner loop /* Use the standard inner loop
@ -3007,7 +3010,7 @@ int sqlite3Select(
int addrGroupByChange; /* Code that runs when any GROUP BY term changes */ int addrGroupByChange; /* Code that runs when any GROUP BY term changes */
int addrProcessRow; /* Code to process a single input row */ int addrProcessRow; /* Code to process a single input row */
int addrEnd; /* End of all processing */ int addrEnd; /* End of all processing */
int addrSortingIdx; /* The OP_OpenVirtual for the sorting index */ int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */
int addrReset; /* Subroutine for resetting the accumulator */ int addrReset; /* Subroutine for resetting the accumulator */
addrEnd = sqlite3VdbeMakeLabel(v); addrEnd = sqlite3VdbeMakeLabel(v);
@ -3054,13 +3057,13 @@ int sqlite3Select(
/* If there is a GROUP BY clause we might need a sorting index to /* If there is a GROUP BY clause we might need a sorting index to
** implement it. Allocate that sorting index now. If it turns out ** implement it. Allocate that sorting index now. If it turns out
** that we do not need it after all, the OpenVirtual instruction ** that we do not need it after all, the OpenEphemeral instruction
** will be converted into a Noop. ** will be converted into a Noop.
*/ */
sAggInfo.sortingIdx = pParse->nTab++; sAggInfo.sortingIdx = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy); pKeyInfo = keyInfoFromExprList(pParse, pGroupBy);
addrSortingIdx = addrSortingIdx =
sqlite3VdbeOp3(v, OP_OpenVirtual, sAggInfo.sortingIdx, sqlite3VdbeOp3(v, OP_OpenEphemeral, sAggInfo.sortingIdx,
sAggInfo.nSortingColumn, sAggInfo.nSortingColumn,
(char*)pKeyInfo, P3_KEYINFO_HANDOFF); (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
@ -3123,7 +3126,7 @@ int sqlite3Select(
if( pWInfo==0 ) goto select_end; if( pWInfo==0 ) goto select_end;
if( pGroupBy==0 ){ if( pGroupBy==0 ){
/* The optimizer is able to deliver rows in group by order so /* The optimizer is able to deliver rows in group by order so
** we do not have to sort. The OP_OpenVirtual table will be ** we do not have to sort. The OP_OpenEphemeral table will be
** cancelled later because we still need to use the pKeyInfo ** cancelled later because we still need to use the pKeyInfo
*/ */
pGroupBy = p->pGroupBy; pGroupBy = p->pGroupBy;
@ -3294,3 +3297,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

@ -21,7 +21,7 @@
#include "sqlite3.h" #include "sqlite3.h"
#include <ctype.h> #include <ctype.h>
#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) #if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) && !defined(__OS2__)
# include <signal.h> # include <signal.h>
# include <pwd.h> # include <pwd.h>
# include <unistd.h> # include <unistd.h>
@ -37,6 +37,10 @@
# include <Folders.h> # include <Folders.h>
#endif #endif
#ifdef __OS2__
# include <unistd.h>
#endif
#if defined(HAVE_READLINE) && HAVE_READLINE==1 #if defined(HAVE_READLINE) && HAVE_READLINE==1
# include <readline/readline.h> # include <readline/readline.h>
# include <readline/history.h> # include <readline/history.h>
@ -48,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
@ -176,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.
@ -197,7 +214,7 @@ static char *one_input_line(const char *zPrior, FILE *in){
} }
zResult = readline(zPrompt); zResult = readline(zPrompt);
#if defined(HAVE_READLINE) && HAVE_READLINE==1 #if defined(HAVE_READLINE) && HAVE_READLINE==1
if( zResult ) add_history(zResult); if( zResult && *zResult ) add_history(zResult);
#endif #endif
return zResult; return zResult;
} }
@ -208,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
@ -219,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 */
@ -231,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 */
}; };
/* /*
@ -343,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
@ -350,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);
@ -384,7 +440,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
int w = 5; int w = 5;
if( azArg==0 ) break; if( azArg==0 ) break;
for(i=0; i<nArg; i++){ for(i=0; i<nArg; i++){
int len = strlen(azCol[i]); int len = strlen(azCol[i] ? azCol[i] : "");
if( len>w ) w = len; if( len>w ) w = len;
} }
if( p->cnt++>0 ) fprintf(p->out,"\n"); if( p->cnt++>0 ) fprintf(p->out,"\n");
@ -486,7 +542,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
case MODE_Tcl: { case MODE_Tcl: {
if( p->cnt++==0 && p->showHeader ){ if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){ for(i=0; i<nArg; i++){
output_c_string(p->out,azCol[i]); output_c_string(p->out,azCol[i] ? azCol[i] : "");
fprintf(p->out, "%s", p->separator); fprintf(p->out, "%s", p->separator);
} }
fprintf(p->out,"\n"); fprintf(p->out,"\n");
@ -502,7 +558,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
case MODE_Csv: { case MODE_Csv: {
if( p->cnt++==0 && p->showHeader ){ if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){ for(i=0; i<nArg; i++){
output_csv(p, azCol[i], i<nArg-1); output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
} }
fprintf(p->out,"\n"); fprintf(p->out,"\n");
} }
@ -580,7 +636,7 @@ static void set_table_name(struct callback_data *p, const char *zName){
** If the third argument, quote, is not '\0', then it is used as a ** If the third argument, quote, is not '\0', then it is used as a
** quote character for zAppend. ** quote character for zAppend.
*/ */
static char * appendText(char *zIn, char const *zAppend, char quote){ static char *appendText(char *zIn, char const *zAppend, char quote){
int len; int len;
int i; int i;
int nAppend = strlen(zAppend); int nAppend = strlen(zAppend);
@ -621,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;
@ -662,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);
} }
@ -695,7 +767,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zSelect = appendText(zSelect, zText, '"'); zSelect = appendText(zSelect, zText, '"');
rc = sqlite3_step(pTableInfo); rc = sqlite3_step(pTableInfo);
if( rc==SQLITE_ROW ){ if( rc==SQLITE_ROW ){
zSelect = appendText(zSelect, ") || ', ' || ", 0); zSelect = appendText(zSelect, ") || ',' || ", 0);
}else{ }else{
zSelect = appendText(zSelect, ") ", 0); zSelect = appendText(zSelect, ") ", 0);
} }
@ -714,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.
*/ */
@ -750,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"
@ -759,6 +831,9 @@ static char zHelp[] =
".help Show this message\n" ".help Show this message\n"
".import FILE TABLE Import data from FILE into TABLE\n" ".import FILE TABLE Import data from FILE into TABLE\n"
".indices TABLE Show names of all indices on TABLE\n" ".indices TABLE Show names of all indices on TABLE\n"
#ifndef SQLITE_OMIT_LOAD_EXTENSION
".load FILE ?ENTRY? Load an extension library\n"
#endif
".mode MODE ?TABLE? Set output mode where MODE is one of:\n" ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
" csv Comma-separated values\n" " csv Comma-separated values\n"
" column Left-aligned columns. (See .width)\n" " column Left-aligned columns. (See .width)\n"
@ -783,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
@ -800,6 +875,9 @@ static void open_db(struct callback_data *p){
p->zDbFilename, sqlite3_errmsg(db)); p->zDbFilename, sqlite3_errmsg(db));
exit(1); exit(1);
} }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
} }
} }
@ -840,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;
@ -879,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;
@ -901,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;
@ -918,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);
@ -934,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;
@ -995,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 ){
@ -1032,6 +1104,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
FILE *in; /* The input file */ FILE *in; /* The input file */
int lineno = 0; /* Line number of input file */ int lineno = 0; /* Line number of input file */
open_db(p);
nSep = strlen(p->separator); nSep = strlen(p->separator);
if( nSep==0 ){ if( nSep==0 ){
fprintf(stderr, "non-null separator required for import\n"); fprintf(stderr, "non-null separator required for import\n");
@ -1045,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);
} }
@ -1065,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 ){
@ -1111,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;
} }
} }
@ -1144,6 +1219,23 @@ static int do_meta_command(char *zLine, struct callback_data *p){
} }
}else }else
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
const char *zFile, *zProc;
char *zErrMsg = 0;
int rc;
zFile = azArg[1];
zProc = nArg>=3 ? azArg[2] : 0;
open_db(p);
rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}
}else
#endif
if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){ if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
int n2 = strlen(azArg[1]); int n2 = strlen(azArg[1]);
if( strncmp(azArg[1],"line",n2)==0 if( strncmp(azArg[1],"line",n2)==0
@ -1174,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
@ -1211,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 ){
@ -1363,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
@ -1442,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) ){
@ -1471,7 +1581,12 @@ static void process_input(struct callback_data *p, FILE *in){
if( zLine[i]!=0 ){ if( zLine[i]!=0 ){
nSql = strlen(zLine); nSql = strlen(zLine);
zSql = malloc( nSql+1 ); zSql = malloc( nSql+1 );
if( zSql==0 ){
fprintf(stderr, "out of memory\n");
exit(1);
}
strcpy(zSql, zLine); strcpy(zSql, zLine);
startline = lineno;
} }
}else{ }else{
int len = strlen(zLine); int len = strlen(zLine);
@ -1490,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;
@ -1508,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;
} }
/* /*
@ -1519,7 +1641,7 @@ static void process_input(struct callback_data *p, FILE *in){
static char *find_home_dir(void){ static char *find_home_dir(void){
char *home_dir = NULL; char *home_dir = NULL;
#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) #if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) && !defined(__OS2__)
struct passwd *pwent; struct passwd *pwent;
uid_t uid = getuid(); uid_t uid = getuid();
if( (pwent=getpwuid(uid)) != NULL) { if( (pwent=getpwuid(uid)) != NULL) {
@ -1532,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) #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
@ -1584,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);
@ -1601,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");
} }
@ -1638,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);
@ -1645,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.
@ -1658,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 ){
@ -1712,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;
@ -1722,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]);
@ -1734,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 1; 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);
@ -1764,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(
@ -1779,16 +1933,22 @@ 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);
free(zHistory);
} }
free(zHome);
}else{ }else{
process_input(&data, stdin); rc = process_input(&data, stdin);
} }
} }
set_table_name(&data, 0); set_table_name(&data, 0);
if( db ) sqlite3_close(db); if( db ){
return 0; if( sqlite3_close(db)!=SQLITE_OK ){
fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
}
}
return rc;
} }

View File

@ -1,101 +0,0 @@
EXPORTS
sqlite3_aggregate_context
sqlite3_aggregate_count
sqlite3_bind_blob
sqlite3_bind_double
sqlite3_bind_int
sqlite3_bind_int64
sqlite3_bind_null
sqlite3_bind_parameter_count
sqlite3_bind_parameter_index
sqlite3_bind_parameter_name
sqlite3_bind_text
sqlite3_bind_text16
sqlite3_busy_handler
sqlite3_busy_timeout
sqlite3_changes
sqlite3_close
sqlite3_collation_needed
sqlite3_collation_needed16
sqlite3_column_blob
sqlite3_column_bytes
sqlite3_column_bytes16
sqlite3_column_count
sqlite3_column_decltype
sqlite3_column_decltype16
sqlite3_column_double
sqlite3_column_int
sqlite3_column_int64
sqlite3_column_name
sqlite3_column_name16
sqlite3_column_text
sqlite3_column_text16
sqlite3_column_type
sqlite3_commit_hook
sqlite3_complete
sqlite3_complete16
sqlite3_create_collation
sqlite3_create_collation16
sqlite3_create_function
sqlite3_create_function16
sqlite3_data_count
sqlite3_db_handle
sqlite3_enable_shared_cache
sqlite3_errcode
sqlite3_errmsg
sqlite3_errmsg16
sqlite3_exec
sqlite3_expired
sqlite3_finalize
sqlite3_free
sqlite3_free_table
sqlite3_get_autocommit
sqlite3_get_auxdata
sqlite3_get_table
sqlite3_global_recover
sqlite3_interrupt
sqlite3_last_insert_rowid
sqlite3_libversion
sqlite3_libversion_number
sqlite3_mprintf
sqlite3_open
sqlite3_open16
sqlite3_prepare
sqlite3_prepare16
sqlite3_progress_handler
sqlite3_reset
sqlite3_result_blob
sqlite3_result_double
sqlite3_result_error
sqlite3_result_error16
sqlite3_result_int
sqlite3_result_int64
sqlite3_result_null
sqlite3_result_text
sqlite3_result_text16
sqlite3_result_text16be
sqlite3_result_text16le
sqlite3_result_value
sqlite3_rollback_hook
sqlite3_set_authorizer
sqlite3_set_auxdata
sqlite3_snprintf
sqlite3_step
sqlite3_thread_cleanup
sqlite3_total_changes
sqlite3_trace
sqlite3_transfer_bindings
sqlite3_update_hook
sqlite3_user_data
sqlite3_value_blob
sqlite3_value_bytes
sqlite3_value_bytes16
sqlite3_value_double
sqlite3_value_int
sqlite3_value_int64
sqlite3_value_text
sqlite3_value_text16
sqlite3_value_text16be
sqlite3_value_text16le
sqlite3_value_type
sqlite3_vmprintf

View File

@ -31,7 +31,7 @@ extern "C" {
#ifdef SQLITE_VERSION #ifdef SQLITE_VERSION
# undef SQLITE_VERSION # undef SQLITE_VERSION
#endif #endif
#define SQLITE_VERSION "3.3.5" #define SQLITE_VERSION "3.3.13"
/* /*
** The format of the version string is "X.Y.Z<trailing string>", where ** The format of the version string is "X.Y.Z<trailing string>", where
@ -48,7 +48,7 @@ extern "C" {
#ifdef SQLITE_VERSION_NUMBER #ifdef SQLITE_VERSION_NUMBER
# undef SQLITE_VERSION_NUMBER # undef SQLITE_VERSION_NUMBER
#endif #endif
#define SQLITE_VERSION_NUMBER 3003005 #define SQLITE_VERSION_NUMBER 3003013
/* /*
** The version string is also compiled into the library so that a program ** The version string is also compiled into the library so that a program
@ -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.
@ -405,9 +460,19 @@ void sqlite3_free_table(char **result);
*/ */
char *sqlite3_mprintf(const char*,...); char *sqlite3_mprintf(const char*,...);
char *sqlite3_vmprintf(const char*, va_list); char *sqlite3_vmprintf(const char*, va_list);
void sqlite3_free(char *z);
char *sqlite3_snprintf(int,char*,const char*, ...); char *sqlite3_snprintf(int,char*,const char*, ...);
/*
** SQLite uses its own memory allocator. On many installations, this
** memory allocator is identical to the standard malloc()/realloc()/free()
** and can be used interchangable. On others, the implementations are
** different. For maximum portability, it is best not to mix calls
** to the standard malloc/realloc/free with the sqlite versions.
*/
void *sqlite3_malloc(int);
void *sqlite3_realloc(void*, int);
void sqlite3_free(void*);
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
/* /*
** This routine registers a callback with the SQLite library. The ** This routine registers a callback with the SQLite library. The
@ -466,7 +531,9 @@ int sqlite3_set_authorizer(
#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ #define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */
#define SQLITE_REINDEX 27 /* Index Name NULL */ #define SQLITE_REINDEX 27 /* Index Name NULL */
#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_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
@ -642,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.
@ -926,6 +1018,7 @@ const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol); int sqlite3_column_type(sqlite3_stmt*, int iCol);
int sqlite3_column_numeric_type(sqlite3_stmt*, int iCol); int sqlite3_column_numeric_type(sqlite3_stmt*, int iCol);
sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
/* /*
** The sqlite3_finalize() function is called to delete a compiled ** The sqlite3_finalize() function is called to delete a compiled
@ -1092,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
@ -1468,6 +1565,299 @@ int sqlite3_table_column_metadata(
int *pAutoinc /* OUTPUT: True if colums is auto-increment */ int *pAutoinc /* OUTPUT: True if colums is auto-increment */
); );
/*
****** EXPERIMENTAL - subject to change without notice **************
**
** Attempt to load an SQLite extension library contained in the file
** zFile. The entry point is zProc. zProc may be 0 in which case the
** name of the entry point defaults to "sqlite3_extension_init".
**
** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
**
** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
** error message text. The calling function should free this memory
** by calling sqlite3_free().
**
** Extension loading must be enabled using sqlite3_enable_load_extension()
** prior to calling this API or an error will be returned.
**
****** EXPERIMENTAL - subject to change without notice **************
*/
int sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Derived from zFile if 0 */
char **pzErrMsg /* Put error message here if not 0 */
);
/*
** So as not to open security holes in older applications that are
** unprepared to deal with extension load, and as a means of disabling
** extension loading while executing user-entered SQL, the following
** API is provided to turn the extension loading mechanism on and
** off. It is off by default. See ticket #1863.
**
** Call this routine with onoff==1 to turn extension loading on
** and call it with onoff==0 to turn it back off again.
*/
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 **************
**
** The interface to the virtual-table mechanism is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
**
** When the virtual-table mechanism stablizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
*/
/*
** Structures used by the virtual table interface
*/
typedef struct sqlite3_vtab sqlite3_vtab;
typedef struct sqlite3_index_info sqlite3_index_info;
typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
typedef struct sqlite3_module sqlite3_module;
/*
** A module is a class of virtual tables. Each module is defined
** by an instance of the following structure. This structure consists
** mostly of methods for the module.
*/
struct sqlite3_module {
int iVersion;
int (*xCreate)(sqlite3*, void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVTab, char**);
int (*xConnect)(sqlite3*, void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVTab, char**);
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
int (*xDisconnect)(sqlite3_vtab *pVTab);
int (*xDestroy)(sqlite3_vtab *pVTab);
int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
int (*xClose)(sqlite3_vtab_cursor*);
int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
int argc, sqlite3_value **argv);
int (*xNext)(sqlite3_vtab_cursor*);
int (*xEof)(sqlite3_vtab_cursor*);
int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
int (*xRowid)(sqlite3_vtab_cursor*, sqlite_int64 *pRowid);
int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite_int64 *);
int (*xBegin)(sqlite3_vtab *pVTab);
int (*xSync)(sqlite3_vtab *pVTab);
int (*xCommit)(sqlite3_vtab *pVTab);
int (*xRollback)(sqlite3_vtab *pVTab);
int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
};
/*
** The sqlite3_index_info structure and its substructures is used to
** pass information into and receive the reply from the xBestIndex
** method of an sqlite3_module. The fields under **Inputs** are the
** inputs to xBestIndex and are read-only. xBestIndex inserts its
** results into the **Outputs** fields.
**
** The aConstraint[] array records WHERE clause constraints of the
** form:
**
** column OP expr
**
** Where OP is =, <, <=, >, or >=. The particular operator is stored
** in aConstraint[].op. The index of the column is stored in
** aConstraint[].iColumn. aConstraint[].usable is TRUE if the
** expr on the right-hand side can be evaluated (and thus the constraint
** is usable) and false if it cannot.
**
** The optimizer automatically inverts terms of the form "expr OP column"
** and makes other simplificatinos to the WHERE clause in an attempt to
** get as many WHERE clause terms into the form shown above as possible.
** The aConstraint[] array only reports WHERE clause terms in the correct
** form that refer to the particular virtual table being queried.
**
** Information about the ORDER BY clause is stored in aOrderBy[].
** Each term of aOrderBy records a column of the ORDER BY clause.
**
** The xBestIndex method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter. If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv. If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
** virtual table and is not checked again by SQLite.
**
** The idxNum and idxPtr values are recorded and passed into xFilter.
** sqlite3_free() is used to free idxPtr if needToFreeIdxPtr is true.
**
** The orderByConsumed means that output from xFilter will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
** sorting step is required.
**
** The estimatedCost value is an estimate of the cost of doing the
** particular lookup. A full scan of a table with N entries should have
** a cost of N. A binary search of a table of N entries should have a
** cost of approximately log(N).
*/
struct sqlite3_index_info {
/* Inputs */
const int nConstraint; /* Number of entries in aConstraint */
const struct sqlite3_index_constraint {
int iColumn; /* Column on left-hand side of constraint */
unsigned char op; /* Constraint operator */
unsigned char usable; /* True if this constraint is usable */
int iTermOffset; /* Used internally - xBestIndex should ignore */
} *const aConstraint; /* Table of WHERE clause constraints */
const int nOrderBy; /* Number of terms in the ORDER BY clause */
const struct sqlite3_index_orderby {
int iColumn; /* Column number */
unsigned char desc; /* True for DESC. False for ASC. */
} *const aOrderBy; /* The ORDER BY clause */
/* Outputs */
struct sqlite3_index_constraint_usage {
int argvIndex; /* if >0, constraint is part of argv to xFilter */
unsigned char omit; /* Do not code a test for this constraint */
} *const aConstraintUsage;
int idxNum; /* Number used to identify the index */
char *idxStr; /* String, possibly obtained from sqlite3_malloc */
int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
int orderByConsumed; /* True if output is already ordered */
double estimatedCost; /* Estimated cost of using this index */
};
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
#define SQLITE_INDEX_CONSTRAINT_LE 8
#define SQLITE_INDEX_CONSTRAINT_LT 16
#define SQLITE_INDEX_CONSTRAINT_GE 32
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
/*
** This routine is used to register a new module name with an SQLite
** connection. Module names must be registered before creating new
** virtual tables on the module, or before using preexisting virtual
** tables of the module.
*/
int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *, /* Methods for the module */
void * /* Client data for xCreate/xConnect */
);
/*
** Every module implementation uses a subclass of the following structure
** to describe a particular instance of the module. Each subclass will
** be taylored to the specific needs of the module implementation. The
** purpose of this superclass is to define certain fields that are common
** 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 {
const sqlite3_module *pModule; /* The module for this virtual table */
int nRef; /* Used internally */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
/* Every module implementation uses a subclass of the following structure
** to describe cursors that point into the virtual table and are used
** to loop through the virtual table. Cursors are created using the
** xOpen method of the module. Each module implementation will define
** the content of a cursor structure to suit its own needs.
**
** This superclass exists in order to define fields of the cursor that
** are common to all implementations.
*/
struct sqlite3_vtab_cursor {
sqlite3_vtab *pVtab; /* Virtual table of this cursor */
/* Virtual table implementations will typically add additional fields */
};
/*
** The xCreate and xConnect methods of a module use the following API
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
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
** to a comment remarkably similar to this one) is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
**
** When the virtual-table mechanism stablizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
**
****** EXPERIMENTAL - subject to change without notice **************
*/
/* /*
** Undo the hack that converts floating point types to integer for ** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support. ** builds on processors without floating point support.

View File

@ -0,0 +1,282 @@
/*
** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
**
** @(#) $Id$
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** The following structure hold pointers to all of the SQLite API
** routines.
*/
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
int (*bind_null)(sqlite3_stmt*,int);
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
int (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
int (*column_bytes)(sqlite3_stmt*,int iCol);
int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
const char * (*column_decltype)(sqlite3_stmt*,int i);
const void * (*column_decltype16)(sqlite3_stmt*,int);
double (*column_double)(sqlite3_stmt*,int iCol);
int (*column_int)(sqlite3_stmt*,int iCol);
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
const char * (*column_name)(sqlite3_stmt*,int);
const void * (*column_name16)(sqlite3_stmt*,int);
const char * (*column_origin_name)(sqlite3_stmt*,int);
const void * (*column_origin_name16)(sqlite3_stmt*,int);
const char * (*column_table_name)(sqlite3_stmt*,int);
const void * (*column_table_name16)(sqlite3_stmt*,int);
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
const void * (*column_text16)(sqlite3_stmt*,int iCol);
int (*column_type)(sqlite3_stmt*,int iCol);
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
int (*complete)(const char*sql);
int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
int (*data_count)(sqlite3_stmt*pStmt);
sqlite3 * (*db_handle)(sqlite3_stmt*);
int (*declare_vtab)(sqlite3*,const char*);
int (*enable_shared_cache)(int);
int (*errcode)(sqlite3*db);
const char * (*errmsg)(sqlite3*);
const void * (*errmsg16)(sqlite3*);
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
int (*expired)(sqlite3_stmt*);
int (*finalize)(sqlite3_stmt*pStmt);
void (*free)(void*);
void (*free_table)(char**result);
int (*get_autocommit)(sqlite3*);
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
void *(*malloc)(int);
char * (*mprintf)(const char*,...);
int (*open)(const char*,sqlite3**);
int (*open16)(const void*,sqlite3**);
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
void (*result_int)(sqlite3_context*,int);
void (*result_int64)(sqlite3_context*,sqlite_int64);
void (*result_null)(sqlite3_context*);
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_value)(sqlite3_context*,sqlite3_value*);
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
int (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
int (*value_bytes)(sqlite3_value*);
int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
int (*value_numeric_type)(sqlite3_value*);
const unsigned char * (*value_text)(sqlite3_value*);
const void * (*value_text16)(sqlite3_value*);
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
char * (*vmprintf)(const char*,va_list);
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
};
/*
** The following macros redefine the API routines so that they are
** redirected throught the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
** it can get access to the sqlite3_api_routines structure
** definition. But the main library does not want to redefine
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#ifndef SQLITE_CORE
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
#define sqlite3_bind_blob sqlite3_api->bind_blob
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
#define sqlite3_bind_null sqlite3_api->bind_null
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
#define sqlite3_bind_text sqlite3_api->bind_text
#define sqlite3_bind_text16 sqlite3_api->bind_text16
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
#define sqlite3_changes sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
#define sqlite3_column_blob sqlite3_api->column_blob
#define sqlite3_column_bytes sqlite3_api->column_bytes
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
#define sqlite3_column_count sqlite3_api->column_count
#define sqlite3_column_database_name sqlite3_api->column_database_name
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
#define sqlite3_column_decltype sqlite3_api->column_decltype
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
#define sqlite3_column_double sqlite3_api->column_double
#define sqlite3_column_int sqlite3_api->column_int
#define sqlite3_column_int64 sqlite3_api->column_int64
#define sqlite3_column_name sqlite3_api->column_name
#define sqlite3_column_name16 sqlite3_api->column_name16
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
#define sqlite3_column_table_name sqlite3_api->column_table_name
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
#define sqlite3_column_text sqlite3_api->column_text
#define sqlite3_column_text16 sqlite3_api->column_text16
#define sqlite3_column_type sqlite3_api->column_type
#define sqlite3_column_value sqlite3_api->column_value
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
#define sqlite3_create_collation sqlite3_api->create_collation
#define sqlite3_create_collation16 sqlite3_api->create_collation16
#define sqlite3_create_function sqlite3_api->create_function
#define sqlite3_create_function16 sqlite3_api->create_function16
#define sqlite3_create_module sqlite3_api->create_module
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
#define sqlite3_errcode sqlite3_api->errcode
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
#define sqlite3_expired sqlite3_api->expired
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
#define sqlite3_global_recover sqlite3_api->global_recover
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
#define sqlite3_malloc sqlite3_api->malloc
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
#define sqlite3_reset sqlite3_api->reset
#define sqlite3_result_blob sqlite3_api->result_blob
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
#define sqlite3_result_text sqlite3_api->result_text
#define sqlite3_result_text16 sqlite3_api->result_text16
#define sqlite3_result_text16be sqlite3_api->result_text16be
#define sqlite3_result_text16le sqlite3_api->result_text16le
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->snprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
#define sqlite3_total_changes sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
#define sqlite3_value_bytes sqlite3_api->value_bytes
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
#define sqlite3_value_double sqlite3_api->value_double
#define sqlite3_value_int sqlite3_api->value_int
#define sqlite3_value_int64 sqlite3_api->value_int64
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
#define sqlite3_value_text sqlite3_api->value_text
#define sqlite3_value_text16 sqlite3_api->value_text16
#define sqlite3_value_text16be sqlite3_api->value_text16be
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api;
#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
#endif /* _SQLITE3EXT_H_ */

View File

@ -17,7 +17,7 @@
#define _SQLITEINT_H_ #define _SQLITEINT_H_
#if defined _MSC_VER && _MSC_VER >= 1400 #if defined _MSC_VER && _MSC_VER >= 1400
#define _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE
#endif #endif
/* /*
@ -152,7 +152,7 @@
*/ */
#define SQLITE_MAX_FILE_FORMAT 4 #define SQLITE_MAX_FILE_FORMAT 4
#ifndef SQLITE_DEFAULT_FILE_FORMAT #ifndef SQLITE_DEFAULT_FILE_FORMAT
# define SQLITE_DEFAULT_FILE_FORMAT 4 # define SQLITE_DEFAULT_FILE_FORMAT 1
#endif #endif
/* /*
@ -347,6 +347,7 @@ typedef struct IdList IdList;
typedef struct Index Index; typedef struct Index Index;
typedef struct KeyClass KeyClass; typedef struct KeyClass KeyClass;
typedef struct KeyInfo KeyInfo; typedef struct KeyInfo KeyInfo;
typedef struct Module Module;
typedef struct NameContext NameContext; typedef struct NameContext NameContext;
typedef struct Parse Parse; typedef struct Parse Parse;
typedef struct Select Select; typedef struct Select Select;
@ -450,6 +451,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 */
@ -464,6 +466,8 @@ struct sqlite3 {
int newTnum; /* Rootpage of table being initialized */ int newTnum; /* Rootpage of table being initialized */
u8 busy; /* TRUE if currently initializing */ u8 busy; /* TRUE if currently initializing */
} init; } init;
int nExtension; /* Number of loaded extensions */
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 */
@ -482,6 +486,10 @@ struct sqlite3 {
sqlite3_value *pErr; /* Most recent error message */ sqlite3_value *pErr; /* Most recent error message */
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
union {
int isInterrupted; /* True if sqlite3_interrupt has been called */
double notUsed1; /* Spacer */
} u1;
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
/* Access authorization function */ /* Access authorization function */
@ -492,8 +500,11 @@ struct sqlite3 {
void *pProgressArg; /* Argument to the progress callback */ void *pProgressArg; /* Argument to the progress callback */
int nProgressOps; /* Number of opcodes for progress callback */ int nProgressOps; /* Number of opcodes for progress callback */
#endif #endif
#ifndef SQLITE_OMIT_GLOBALRECOVER #ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3 *pNext; /* Linked list of open db handles. */ Hash aModule; /* populated by sqlite3_create_module() */
Table *pVTab; /* vtab with active Connect/Create method */
sqlite3_vtab **aVTrans; /* Virtual tables with open transactions */
int nVTrans; /* Allocated size of aVTrans */
#endif #endif
Hash aFunc; /* All functions that can be in SQL exprs */ Hash aFunc; /* All functions that can be in SQL exprs */
Hash aCollSeq; /* All collating sequences */ Hash aCollSeq; /* All collating sequences */
@ -518,7 +529,6 @@ struct sqlite3 {
** transaction is active on that particular database file. ** transaction is active on that particular database file.
*/ */
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ #define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
#define SQLITE_Interrupt 0x00000004 /* Cancel current operation */
#define SQLITE_InTrans 0x00000008 /* True if in a transaction */ #define SQLITE_InTrans 0x00000008 /* True if in a transaction */
#define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */ #define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */
#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */ #define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
@ -537,6 +547,7 @@ struct sqlite3 {
#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */ #define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */
#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ #define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
#define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */ #define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
/* /*
** Possible values for the sqlite.magic field. ** Possible values for the sqlite.magic field.
@ -567,11 +578,23 @@ struct FuncDef {
char zName[1]; /* SQL name of the function. MUST BE LAST */ char zName[1]; /* SQL name of the function. MUST BE LAST */
}; };
/*
** Each SQLite module (virtual table definition) is defined by an
** instance of the following structure, stored in the sqlite3.aModule
** hash table.
*/
struct Module {
const sqlite3_module *pModule; /* Callback pointers */
const char *zName; /* Name passed to create_module() */
void *pAux; /* pAux passed to create_module() */
};
/* /*
** Possible values for FuncDef.flags ** Possible values for FuncDef.flags
*/ */
#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */
#define SQLITE_FUNC_EPHEM 0x04 /* Ephermeral. Delete with VDBE */
/* /*
** information about each column of an SQL table is held in an instance ** information about each column of an SQL table is held in an instance
@ -674,7 +697,7 @@ struct CollSeq {
** Table.tnum is the page number for the root BTree page of the table in the ** Table.tnum is the page number for the root BTree page of the table in the
** database file. If Table.iDb is the index of the database table backend ** database file. If Table.iDb is the index of the database table backend
** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that ** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that
** holds temporary tables and indices. If Table.isTransient ** holds temporary tables and indices. If Table.isEphem
** is true, then the table is stored in a file that is automatically deleted ** is true, then the table is stored in a file that is automatically deleted
** when the VDBE cursor to the table is closed. In this case Table.tnum ** when the VDBE cursor to the table is closed. In this case Table.tnum
** refers VDBE cursor number that holds the table open, not to the root ** refers VDBE cursor number that holds the table open, not to the root
@ -690,11 +713,6 @@ struct Table {
Index *pIndex; /* List of SQL indexes on this table. */ Index *pIndex; /* List of SQL indexes on this table. */
int tnum; /* Root BTree node for this table (see note above) */ int tnum; /* Root BTree node for this table (see note above) */
Select *pSelect; /* NULL for tables. Points to definition if a view. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */
u8 readOnly; /* True if this table should not be written by the user */
u8 isTransient; /* True if automatically deleted when VDBE finishes */
u8 hasPrimKey; /* True if there exists a primary key */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
u8 autoInc; /* True if the integer primary key is autoincrement */
int nRef; /* Number of pointers to this Table */ int nRef; /* Number of pointers to this Table */
Trigger *pTrigger; /* List of SQL triggers on this table */ Trigger *pTrigger; /* List of SQL triggers on this table */
FKey *pFKey; /* Linked list of all foreign keys in this table */ FKey *pFKey; /* Linked list of all foreign keys in this table */
@ -704,10 +722,34 @@ struct Table {
#endif #endif
#ifndef SQLITE_OMIT_ALTERTABLE #ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE statement to add a new column */ int addColOffset; /* Offset in CREATE TABLE statement to add a new column */
#endif
u8 readOnly; /* True if this table should not be written by the user */
u8 isEphem; /* True if created using OP_OpenEphermeral */
u8 hasPrimKey; /* True if there exists a primary key */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
u8 autoInc; /* True if the integer primary key is autoincrement */
#ifndef SQLITE_OMIT_VIRTUALTABLE
u8 isVirtual; /* True if this is a virtual table */
u8 isCommit; /* True once the CREATE TABLE has been committed */
Module *pMod; /* Pointer to the implementation of the module */
sqlite3_vtab *pVtab; /* Pointer to the module instance */
int nModuleArg; /* Number of arguments to the module */
char **azModuleArg; /* Text of all module args. [0] is module name */
#endif #endif
Schema *pSchema; Schema *pSchema;
}; };
/*
** Test to see whether or not a table is a virtual table. This is
** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
# define IsVirtual(X) ((X)->isVirtual)
#else
# define IsVirtual(X) 0
#endif
/* /*
** Each foreign key constraint is an instance of the following structure. ** Each foreign key constraint is an instance of the following structure.
** **
@ -899,7 +941,7 @@ struct AggInfo {
Expr *pExpr; /* Expression encoding the function */ Expr *pExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */ FuncDef *pFunc; /* The aggregate function implementation */
int iMem; /* Memory location that acts as accumulator */ int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Virtual table used to enforce DISTINCT */ int iDistinct; /* Ephermeral table used to enforce DISTINCT */
} *aFunc; } *aFunc;
int nFunc; /* Number of entries in aFunc[] */ int nFunc; /* Number of entries in aFunc[] */
int nFuncAlloc; /* Number of slots allocated for aFunc[] */ int nFuncAlloc; /* Number of slots allocated for aFunc[] */
@ -954,7 +996,7 @@ struct AggInfo {
struct Expr { struct Expr {
u8 op; /* Operation performed by this node */ u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */ char affinity; /* The affinity of the column or 0 if not a column */
u8 flags; /* Various flags. See below */ u16 flags; /* Various flags. See below */
CollSeq *pColl; /* The collation type of the column or 0 */ CollSeq *pColl; /* The collation type of the column or 0 */
Expr *pLeft, *pRight; /* Left and right subnodes */ Expr *pLeft, *pRight; /* Left and right subnodes */
ExprList *pList; /* A list of expressions used as function arguments ExprList *pList; /* A list of expressions used as function arguments
@ -982,6 +1024,8 @@ struct Expr {
#define EP_Distinct 0x10 /* Aggregate function with DISTINCT keyword */ #define EP_Distinct 0x10 /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */ #define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
#define EP_Dequoted 0x40 /* True if the string has been dequoted */ #define EP_Dequoted 0x40 /* True if the string has been dequoted */
#define EP_InfixFunc 0x80 /* True for an infix function: LIKE, GLOB, etc */
#define EP_ExpCollate 0x100 /* Collating sequence specified explicitly */
/* /*
** These macros can be used to test, set, or clear bits in the ** These macros can be used to test, set, or clear bits in the
@ -1039,8 +1083,12 @@ struct IdList {
/* /*
** The bitmask datatype defined below is used for various optimizations. ** The bitmask datatype defined below is used for various optimizations.
**
** Changing this from a 64-bit to a 32-bit type limits the number of
** tables in a join to 32 instead of 64. But it also reduces the size
** of the library by 738 bytes on ix86.
*/ */
typedef unsigned int Bitmask; typedef u64 Bitmask;
/* /*
** The following structure describes the FROM clause of a SELECT statement. ** The following structure describes the FROM clause of a SELECT statement.
@ -1052,6 +1100,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 */
@ -1063,8 +1116,8 @@ 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 */ int 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 */
Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */ Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */
@ -1087,6 +1140,19 @@ struct SrcList {
** structure contains a single instance of this structure. This structure ** structure contains a single instance of this structure. This structure
** is intended to be private the the where.c module and should not be ** is intended to be private the the where.c module and should not be
** access or modified by other modules. ** access or modified by other modules.
**
** The pIdxInfo and pBestIdx fields are used to help pick the best
** index on a virtual table. The pIdxInfo pointer contains indexing
** information for the i-th table in the FROM clause before reordering.
** All the pIdxInfo pointers are freed by whereInfoFree() in where.c.
** The pBestIdx pointer is a copy of pIdxInfo for the i-th table after
** FROM clause ordering. This is a little confusing so I will repeat
** it in different words. WhereInfo.a[i].pIdxInfo is index information
** for WhereInfo.pTabList.a[i]. WhereInfo.a[i].pBestInfo is the
** index information for the i-th loop of the join. pBestInfo is always
** either NULL or a copy of some pIdxInfo. So for cleanup it is
** sufficient to free all of the pIdxInfo pointers.
**
*/ */
struct WhereLevel { struct WhereLevel {
int iFrom; /* Which entry in the FROM clause */ int iFrom; /* Which entry in the FROM clause */
@ -1103,6 +1169,13 @@ struct WhereLevel {
int nEq; /* Number of == or IN constraints on this loop */ int nEq; /* Number of == or IN constraints on this loop */
int nIn; /* Number of IN operators constraining this loop */ int nIn; /* Number of IN operators constraining this loop */
int *aInLoop; /* Loop terminators for IN operators */ int *aInLoop; /* Loop terminators for IN operators */
sqlite3_index_info *pBestIdx; /* Index information for this level */
/* The following field is really not part of the current level. But
** we need a place to cache index information for each table in the
** FROM clause and the WhereLevel structure is a convenient place.
*/
sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */
}; };
/* /*
@ -1119,6 +1192,7 @@ struct WhereInfo {
int iContinue; /* Jump here to continue with next record */ int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */ int iBreak; /* Jump here to break out of the loop */
int nLevel; /* Number of nested loop */ int nLevel; /* Number of nested loop */
sqlite3_index_info **apInfo; /* Array of pointers to index info structures */
WhereLevel a[1]; /* Information about each nest loop in the WHERE */ WhereLevel a[1]; /* Information about each nest loop in the WHERE */
}; };
@ -1167,14 +1241,14 @@ struct NameContext {
** offset). But later on, nLimit and nOffset become the memory locations ** offset). But later on, nLimit and nOffset become the memory locations
** in the VDBE that record the limit and offset counters. ** in the VDBE that record the limit and offset counters.
** **
** addrOpenVirt[] entries contain the address of OP_OpenVirtual opcodes. ** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes.
** These addresses must be stored so that we can go back and fill in ** These addresses must be stored so that we can go back and fill in
** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor ** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor
** the number of columns in P2 can be computed at the same time ** the number of columns in P2 can be computed at the same time
** as the OP_OpenVirtual instruction is coded because not ** as the OP_OpenEphm instruction is coded because not
** enough information about the compound query is known at that point. ** enough information about the compound query is known at that point.
** The KeyInfo for addrOpenVirt[0] and [1] contains collating sequences ** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences
** for the result set. The KeyInfo for addrOpenVirt[2] contains collating ** for the result set. The KeyInfo for addrOpenTran[2] contains collating
** sequences for the ORDER BY clause. ** sequences for the ORDER BY clause.
*/ */
struct Select { struct Select {
@ -1183,7 +1257,7 @@ struct Select {
u8 isDistinct; /* True if the DISTINCT keyword is present */ u8 isDistinct; /* True if the DISTINCT keyword is present */
u8 isResolved; /* True once sqlite3SelectResolve() has run. */ u8 isResolved; /* True once sqlite3SelectResolve() has run. */
u8 isAgg; /* True if this is an aggregate query */ u8 isAgg; /* True if this is an aggregate query */
u8 usesVirt; /* True if uses an OpenVirtual opcode */ u8 usesEphm; /* True if uses an OpenEphemeral opcode */
u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */ u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */
SrcList *pSrc; /* The FROM clause */ SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */ Expr *pWhere; /* The WHERE clause */
@ -1195,7 +1269,7 @@ struct Select {
Expr *pLimit; /* LIMIT expression. NULL means not used. */ Expr *pLimit; /* LIMIT expression. NULL means not used. */
Expr *pOffset; /* OFFSET expression. NULL means not used. */ Expr *pOffset; /* OFFSET expression. NULL means not used. */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
int addrOpenVirt[3]; /* OP_OpenVirtual opcodes related to this select */ int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
}; };
/* /*
@ -1212,7 +1286,7 @@ struct Select {
#define SRT_Mem 5 /* Store result in a memory cell */ #define SRT_Mem 5 /* Store result in a memory cell */
#define SRT_Set 6 /* Store non-null results as keys in an index */ #define SRT_Set 6 /* Store non-null results as keys in an index */
#define SRT_Table 7 /* Store result as data with an automatic rowid */ #define SRT_Table 7 /* Store result as data with an automatic rowid */
#define SRT_VirtualTab 8 /* Create virtual table and store like SRT_Table */ #define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */
#define SRT_Subroutine 9 /* Call a subroutine to handle results */ #define SRT_Subroutine 9 /* Call a subroutine to handle results */
#define SRT_Exists 10 /* Store 1 if the result is not empty */ #define SRT_Exists 10 /* Store 1 if the result is not empty */
@ -1241,6 +1315,7 @@ struct Parse {
u8 nameClash; /* A permanent table name clashes with temp table name */ u8 nameClash; /* A permanent table name clashes with temp table name */
u8 checkSchema; /* Causes schema cookie check after an error */ u8 checkSchema; /* Causes schema cookie check after an error */
u8 nested; /* Number of nested calls to the parser/code generator */ u8 nested; /* Number of nested calls to the parser/code generator */
u8 parseError; /* True if a parsing error has been seen */
int nErr; /* Number of errors seen */ int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */ int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */ int nMem; /* Number of memory cells used so far */
@ -1272,8 +1347,19 @@ struct Parse {
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
TriggerStack *trigStack; /* Trigger actions being coded */ TriggerStack *trigStack; /* Trigger actions being coded */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
#ifndef SQLITE_OMIT_VIRTUALTABLE
Token sArg; /* Complete text of a module argument */
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
Table *pVirtualLock; /* Require virtual table lock on this table */
#endif
}; };
#ifdef SQLITE_OMIT_VIRTUALTABLE
#define IN_DECLARE_VTAB 0
#else
#define IN_DECLARE_VTAB (pParse->declareVtab)
#endif
/* /*
** An instance of the following structure can be declared on a stack and used ** An instance of the following structure can be declared on a stack and used
** to save the Parse.zAuthContext value so that it can be restored later. ** to save the Parse.zAuthContext value so that it can be restored later.
@ -1441,7 +1527,9 @@ 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 */
} InitData; } InitData;
/* /*
@ -1500,6 +1588,7 @@ int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*, char **); int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*); void sqlite3FinishCoding(Parse*);
Expr *sqlite3Expr(int, Expr*, Expr*, const Token*); Expr *sqlite3Expr(int, Expr*, Expr*, const Token*);
Expr *sqlite3ExprOrFree(int, Expr*, Expr*, const Token*);
Expr *sqlite3RegisterExpr(Parse*,Token*); Expr *sqlite3RegisterExpr(Parse*,Token*);
Expr *sqlite3ExprAnd(Expr*, Expr*); Expr *sqlite3ExprAnd(Expr*, Expr*);
void sqlite3ExprSpan(Expr*,Token*,Token*); void sqlite3ExprSpan(Expr*,Token*,Token*);
@ -1517,7 +1606,7 @@ void sqlite3RollbackInternalChanges(sqlite3*);
void sqlite3CommitInternalChanges(sqlite3*); void sqlite3CommitInternalChanges(sqlite3*);
Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*); Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
void sqlite3OpenMasterTable(Parse *, int); void sqlite3OpenMasterTable(Parse *, int);
void sqlite3StartTable(Parse*,Token*,Token*,int,int,int); void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
void sqlite3AddColumn(Parse*,Token*); void sqlite3AddColumn(Parse*,Token*);
void sqlite3AddNotNull(Parse*, int); void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
@ -1527,8 +1616,9 @@ 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*);
#ifndef SQLITE_OMIT_VIEW void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
int sqlite3ViewGetColumnNames(Parse*,Table*); int sqlite3ViewGetColumnNames(Parse*,Table*);
#else #else
# define sqlite3ViewGetColumnNames(A,B) 0 # define sqlite3ViewGetColumnNames(A,B) 0
@ -1541,7 +1631,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*);
@ -1583,6 +1675,7 @@ int sqlite3ExprResolveNames(NameContext *, Expr *);
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*); Vdbe *sqlite3GetVdbe(Parse*);
Expr *sqlite3CreateIdExpr(const char*);
void sqlite3Randomness(int, void*); void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*); void sqlite3RollbackAll(sqlite3*);
void sqlite3CodeVerifySchema(Parse*, int); void sqlite3CodeVerifySchema(Parse*, int);
@ -1616,9 +1709,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,
@ -1689,6 +1782,7 @@ int sqlite3ReadSchema(Parse *pParse);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char *,int,int); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char *,int,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *, Token *);
int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3CheckCollSeq(Parse *, CollSeq *);
int sqlite3CheckIndexCollSeq(Parse *, Index *); int sqlite3CheckIndexCollSeq(Parse *, Index *);
int sqlite3CheckObjectName(Parse *, const char *); int sqlite3CheckObjectName(Parse *, const char *);
@ -1744,6 +1838,14 @@ void sqlite3FailedMalloc(void);
void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *); void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *);
int sqlite3OpenTempDatabase(Parse *); int sqlite3OpenTempDatabase(Parse *);
#ifndef SQLITE_OMIT_LOAD_EXTENSION
void sqlite3CloseExtensions(sqlite3*);
int sqlite3AutoLoadExtensions(sqlite3*);
#else
# define sqlite3CloseExtensions(X)
# define sqlite3AutoLoadExtensions(X) SQLITE_OK
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE #ifndef SQLITE_OMIT_SHARED_CACHE
void sqlite3TableLock(Parse *, int, int, u8, const char *); void sqlite3TableLock(Parse *, int, int, u8, const char *);
#else #else
@ -1768,6 +1870,31 @@ int sqlite3OpenTempDatabase(Parse *);
#define sqlite3ThreadSafeFree sqlite3FreeX #define sqlite3ThreadSafeFree sqlite3FreeX
#endif #endif
#ifdef SQLITE_OMIT_VIRTUALTABLE
# define sqlite3VtabClear(X)
# define sqlite3VtabSync(X,Y) (Y)
# define sqlite3VtabRollback(X)
# define sqlite3VtabCommit(X)
#else
void sqlite3VtabClear(Table*);
int sqlite3VtabSync(sqlite3 *db, int rc);
int sqlite3VtabRollback(sqlite3 *db);
int sqlite3VtabCommit(sqlite3 *db);
#endif
void sqlite3VtabLock(sqlite3_vtab*);
void sqlite3VtabUnlock(sqlite3_vtab*);
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*);
void sqlite3VtabArgExtend(Parse*, Token*);
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
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"
#endif #endif

View File

@ -59,7 +59,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( p->nData + need >= p->nAlloc ){ if( p->nData + need >= p->nAlloc ){
char **azNew; char **azNew;
p->nAlloc = p->nAlloc*2 + need + 1; p->nAlloc = p->nAlloc*2 + need + 1;
azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc ); azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed; if( azNew==0 ) goto malloc_failed;
p->azResult = azNew; p->azResult = azNew;
} }
@ -71,11 +71,9 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
p->nColumn = nCol; p->nColumn = nCol;
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
if( colv[i]==0 ){ if( colv[i]==0 ){
z = 0; z = sqlite3_mprintf("");
}else{ }else{
z = malloc( strlen(colv[i])+1 ); z = sqlite3_mprintf("%s", colv[i]);
if( z==0 ) goto malloc_failed;
strcpy(z, colv[i]);
} }
p->azResult[p->nData++] = z; p->azResult[p->nData++] = z;
} }
@ -94,7 +92,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( argv[i]==0 ){ if( argv[i]==0 ){
z = 0; z = 0;
}else{ }else{
z = malloc( strlen(argv[i])+1 ); z = sqlite3_malloc( strlen(argv[i])+1 );
if( z==0 ) goto malloc_failed; if( z==0 ) goto malloc_failed;
strcpy(z, argv[i]); strcpy(z, argv[i]);
} }
@ -140,34 +138,34 @@ int sqlite3_get_table(
res.nData = 1; res.nData = 1;
res.nAlloc = 20; res.nAlloc = 20;
res.rc = SQLITE_OK; res.rc = SQLITE_OK;
res.azResult = malloc( sizeof(char*)*res.nAlloc ); res.azResult = sqlite3_malloc( sizeof(char*)*res.nAlloc );
if( res.azResult==0 ) return SQLITE_NOMEM; if( res.azResult==0 ) return SQLITE_NOMEM;
res.azResult[0] = 0; res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg); rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
if( res.azResult ){ if( res.azResult ){
assert( sizeof(res.azResult[0])>= sizeof(res.nData) ); assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
res.azResult[0] = (void *)(long)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 ){
free(*pzErrMsg); sqlite3_free(*pzErrMsg);
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg); *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
} }
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;
azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) ); azNew = sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) );
if( azNew==0 ){ if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]); sqlite3_free_table(&res.azResult[1]);
return SQLITE_NOMEM; return SQLITE_NOMEM;
@ -178,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;
} }
/* /*
@ -191,9 +189,9 @@ void sqlite3_free_table(
int i, n; int i, n;
azResult--; azResult--;
if( azResult==0 ) return; if( azResult==0 ) return;
n = (int)(long)azResult[0]; n = (int)azResult[0];
for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); } for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); }
free(azResult); sqlite3_free(azResult);
} }
} }

View File

@ -23,6 +23,14 @@
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
/*
* Windows needs to know which symbols to export. Unix does not.
* BUILD_sqlite should be undefined for Unix.
*/
#ifdef BUILD_sqlite
#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLEXPORT
#endif /* BUILD_sqlite */
#define NUM_PREPARED_STMTS 10 #define NUM_PREPARED_STMTS 10
#define MAX_PREPARED_STMTS 100 #define MAX_PREPARED_STMTS 100
@ -543,6 +551,9 @@ static int auth_callback(
case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
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_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);
@ -657,24 +668,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"authorizer", "busy", "cache", "authorizer", "busy", "cache",
"changes", "close", "collate", "changes", "close", "collate",
"collation_needed", "commit_hook", "complete", "collation_needed", "commit_hook", "complete",
"copy", "errorcode", "eval", "copy", "enable_load_extension","errorcode",
"exists", "function", "last_insert_rowid", "eval", "exists", "function",
"nullvalue", "onecolumn", "profile", "interrupt", "last_insert_rowid", "nullvalue",
"progress", "rekey", "rollback_hook", "onecolumn", "profile", "progress",
"timeout", "total_changes", "trace", "rekey", "rollback_hook", "timeout",
"transaction", "update_hook", "version", "total_changes", "trace", "transaction",
0 "update_hook", "version", 0
}; };
enum DB_enum { enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CACHE, DB_AUTHORIZER, DB_BUSY, DB_CACHE,
DB_CHANGES, DB_CLOSE, DB_COLLATE, DB_CHANGES, DB_CLOSE, DB_COLLATE,
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
DB_COPY, DB_ERRORCODE, DB_EVAL, DB_COPY, DB_ENABLE_LOAD_EXTENSION,DB_ERRORCODE,
DB_EXISTS, DB_FUNCTION, DB_LAST_INSERT_ROWID, DB_EVAL, DB_EXISTS, DB_FUNCTION,
DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE, DB_INTERRUPT, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
DB_PROGRESS, DB_REKEY, DB_ROLLBACK_HOOK, DB_ONECOLUMN, DB_PROFILE, DB_PROGRESS,
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, DB_REKEY, DB_ROLLBACK_HOOK, DB_TIMEOUT,
DB_TRANSACTION, DB_UPDATE_HOOK, DB_VERSION DB_TOTAL_CHANGES, DB_TRACE, DB_TRANSACTION,
DB_UPDATE_HOOK, DB_VERSION,
}; };
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@ -1024,7 +1036,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
nSep = strlen(zSep); nSep = strlen(zSep);
nNull = strlen(zNull); nNull = strlen(zNull);
if( nSep==0 ){ if( nSep==0 ){
Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0); Tcl_AppendResult(interp,"Error: non-null separator required for copy",0);
return TCL_ERROR; return TCL_ERROR;
} }
if(sqlite3StrICmp(zConflict, "rollback") != 0 && if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
@ -1043,7 +1055,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
return TCL_ERROR; return TCL_ERROR;
} }
nByte = strlen(zSql); nByte = strlen(zSql);
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0); rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql); sqlite3_free(zSql);
if( rc ){ if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
@ -1069,7 +1081,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
} }
zSql[j++] = ')'; zSql[j++] = ')';
zSql[j] = 0; zSql[j] = 0;
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0); rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
free(zSql); free(zSql);
if( rc ){ if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
@ -1108,11 +1120,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( i+1!=nCol ){ if( i+1!=nCol ){
char *zErr; char *zErr;
zErr = malloc(200 + strlen(zFile)); zErr = malloc(200 + strlen(zFile));
if( zErr ){
sprintf(zErr, sprintf(zErr,
"Error: %s line %d: expected %d columns of data but found %d", "Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i+1); zFile, lineno, nCol, i+1);
Tcl_AppendResult(interp, zErr, 0); Tcl_AppendResult(interp, zErr, 0);
free(zErr); free(zErr);
}
zCommit = "ROLLBACK"; zCommit = "ROLLBACK";
break; break;
} }
@ -1152,6 +1166,31 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/*
** $db enable_load_extension BOOLEAN
**
** Turn the extension loading feature on or off. It if off by
** default.
*/
case DB_ENABLE_LOAD_EXTENSION: {
#ifndef SQLITE_OMIT_LOAD_EXTENSION
int onoff;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
return TCL_ERROR;
}
if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){
return TCL_ERROR;
}
sqlite3_enable_load_extension(pDb->db, onoff);
break;
#else
Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
0);
return TCL_ERROR;
#endif
}
/* /*
** $db errorcode ** $db errorcode
** **
@ -1536,6 +1575,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_SetObjResult(interp, pRet); Tcl_SetObjResult(interp, pRet);
} }
Tcl_DecrRefCount(pRet); Tcl_DecrRefCount(pRet);
}else if( rc==TCL_OK ){
Tcl_ResetResult(interp);
} }
break; break;
} }
@ -1576,6 +1617,17 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/*
** $db interrupt
**
** Interrupt the execution of the inner-most SQL interpreter. This
** causes the SQL statement to return an error of SQLITE_INTERRUPT.
*/
case DB_INTERRUPT: {
sqlite3_interrupt(pDb->db);
break;
}
/* /*
** $db nullvalue ?STRING? ** $db nullvalue ?STRING?
** **
@ -1614,14 +1666,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
*/ */
case DB_LAST_INSERT_ROWID: { case DB_LAST_INSERT_ROWID: {
Tcl_Obj *pResult; Tcl_Obj *pResult;
int rowid; Tcl_WideInt rowid;
if( objc!=2 ){ if( objc!=2 ){
Tcl_WrongNumArgs(interp, 2, objv, ""); Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR; return TCL_ERROR;
} }
rowid = sqlite3_last_insert_rowid(pDb->db); rowid = sqlite3_last_insert_rowid(pDb->db);
pResult = Tcl_GetObjResult(interp); pResult = Tcl_GetObjResult(interp);
Tcl_SetIntObj(pResult, rowid); Tcl_SetWideIntObj(pResult, rowid);
break; break;
} }
@ -1956,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 ){
@ -2004,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;
} }
@ -2016,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);
@ -2039,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;
} }
@ -2070,7 +2125,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** used to open a new SQLite database. See the DbMain() routine above ** used to open a new SQLite database. See the DbMain() routine above
** for additional information. ** for additional information.
*/ */
extern int Sqlite3_Init(Tcl_Interp *interp){ EXTERN int Sqlite3_Init(Tcl_Interp *interp){
Tcl_InitStubs(interp, "8.4", 0); Tcl_InitStubs(interp, "8.4", 0);
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION);
@ -2078,15 +2133,15 @@ extern int Sqlite3_Init(Tcl_Interp *interp){
Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION); Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION);
return TCL_OK; return TCL_OK;
} }
extern int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
extern int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
extern int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } EXTERN int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
#ifndef SQLITE_3_SUFFIX_ONLY #ifndef SQLITE_3_SUFFIX_ONLY
extern int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
extern int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
extern int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
extern int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } EXTERN int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
#endif #endif
#ifdef TCLSH #ifdef TCLSH
@ -2149,9 +2204,13 @@ int TCLSH_MAIN(int argc, char **argv){
extern int Sqlitetest5_Init(Tcl_Interp*); extern int Sqlitetest5_Init(Tcl_Interp*);
extern int Sqlitetest6_Init(Tcl_Interp*); extern int Sqlitetest6_Init(Tcl_Interp*);
extern int Sqlitetest7_Init(Tcl_Interp*); extern int Sqlitetest7_Init(Tcl_Interp*);
extern int Sqlitetest8_Init(Tcl_Interp*);
extern int Md5_Init(Tcl_Interp*); extern int Md5_Init(Tcl_Interp*);
extern int Sqlitetestsse_Init(Tcl_Interp*); extern int Sqlitetestsse_Init(Tcl_Interp*);
extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*);
extern int Sqlitetesttclvar_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);
@ -2160,7 +2219,11 @@ int TCLSH_MAIN(int argc, char **argv){
Sqlitetest5_Init(interp); Sqlitetest5_Init(interp);
Sqlitetest6_Init(interp); Sqlitetest6_Init(interp);
Sqlitetest7_Init(interp); Sqlitetest7_Init(interp);
Sqlitetest8_Init(interp);
Sqlitetestasync_Init(interp); Sqlitetestasync_Init(interp);
Sqlitetesttclvar_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);
@ -2169,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

@ -285,6 +285,10 @@ static int getToken(const unsigned char *z, int *tokenType){
*tokenType = TK_FLOAT; *tokenType = TK_FLOAT;
} }
#endif #endif
while( IdChar(z[i]) ){
*tokenType = TK_ILLEGAL;
i++;
}
return i; return i;
} }
case '[': { case '[': {
@ -390,14 +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*);
db->flags &= ~SQLITE_Interrupt; if( db->activeVdbeCnt==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;
} }
@ -418,7 +424,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
switch( tokenType ){ switch( tokenType ){
case TK_SPACE: case TK_SPACE:
case TK_COMMENT: { case TK_COMMENT: {
if( (db->flags & SQLITE_Interrupt)!=0 ){ if( db->u1.isInterrupted ){
pParse->rc = SQLITE_INTERRUPT; pParse->rc = SQLITE_INTERRUPT;
sqlite3SetString(pzErrMsg, "interrupt", (char*)0); sqlite3SetString(pzErrMsg, "interrupt", (char*)0);
goto abort_parse; goto abort_parse;
@ -483,7 +489,15 @@ abort_parse:
pParse->nTableLock = 0; pParse->nTableLock = 0;
} }
#endif #endif
if( !IN_DECLARE_VTAB ){
/* If the pParse->declareVtab flag is set, do not delete any table
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
** will take responsibility for freeing the Table structure.
*/
sqlite3DeleteTable(pParse->db, pParse->pNewTable); sqlite3DeleteTable(pParse->db, pParse->pNewTable);
}
sqlite3DeleteTrigger(pParse->pNewTrigger); sqlite3DeleteTrigger(pParse->pNewTrigger);
sqliteFree(pParse->apVarExpr); sqliteFree(pParse->apVarExpr);
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){ if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){

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;
@ -103,6 +104,10 @@ void sqlite3BeginTrigger(
/* The table does not exist. */ /* The table does not exist. */
goto trigger_cleanup; goto trigger_cleanup;
} }
if( IsVirtual(pTab) ){
sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
goto trigger_cleanup;
}
/* Check that the trigger name is not reserved and that no trigger of the /* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */ ** specified name exists */
@ -111,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;
} }
@ -435,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;
@ -459,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);
@ -594,9 +603,10 @@ int sqlite3TriggersExist(
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
ExprList *pChanges /* Columns that change in an UPDATE statement */ ExprList *pChanges /* Columns that change in an UPDATE statement */
){ ){
Trigger *pTrigger = pTab->pTrigger; Trigger *pTrigger;
int mask = 0; int mask = 0;
pTrigger = IsVirtual(pTab) ? 0 : pTab->pTrigger;
while( pTrigger ){ while( pTrigger ){
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){ if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
mask |= pTrigger->tr_tm; mask |= pTrigger->tr_tm;
@ -658,12 +668,12 @@ static int codeTriggerProgram(
pParse->trigStack->orconf = orconf; pParse->trigStack->orconf = orconf;
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

@ -16,6 +16,19 @@
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Forward declaration */
static void updateVirtualTable(
Parse *pParse, /* The parsing context */
SrcList *pSrc, /* The virtual table to be modified */
Table *pTab, /* The virtual table */
ExprList *pChanges, /* The columns to change in the UPDATE statement */
Expr *pRowidExpr, /* Expression used to recompute the rowid */
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
Expr *pWhere /* WHERE clause of the UPDATE statement */
);
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/* /*
** The most recently coded instruction was an OP_Column to retrieve the ** The most recently coded instruction was an OP_Column to retrieve the
** i-th column of table pTab. This routine sets the P3 parameter of the ** i-th column of table pTab. This routine sets the P3 parameter of the
@ -90,6 +103,7 @@ void sqlite3Update(
AuthContext sContext; /* The authorization context */ AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */ NameContext sNC; /* The name-context to resolve expressions in */
int iDb; /* Database containing the table being updated */ int iDb; /* Database containing the table being updated */
int memCnt = 0; /* Memory cell used for counting rows changed */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */ int isView; /* Trying to update a view */
@ -130,11 +144,9 @@ void sqlite3Update(
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){ if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto update_cleanup; goto update_cleanup;
} }
if( isView ){
if( sqlite3ViewGetColumnNames(pParse, pTab) ){ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup; goto update_cleanup;
} }
}
aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol ); aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
if( aXRef==0 ) goto update_cleanup; if( aXRef==0 ) goto update_cleanup;
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1; for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
@ -242,6 +254,24 @@ void sqlite3Update(
} }
} }
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto update_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Virtual tables must be handled separately */
if( IsVirtual(pTab) ){
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
pWhere);
pWhere = 0;
pTabList = 0;
goto update_cleanup;
}
#endif
/* Resolve the column names in all the expressions in the /* Resolve the column names in all the expressions in the
** WHERE clause. ** WHERE clause.
*/ */
@ -255,20 +285,13 @@ void sqlite3Update(
sqlite3AuthContextPush(pParse, &sContext, pTab->zName); sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
} }
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto update_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, iDb);
/* If we are trying to update a view, realize that view into /* If we are trying to update a view, realize that view into
** a ephemeral table. ** a ephemeral table.
*/ */
if( isView ){ if( isView ){
Select *pView; Select *pView;
pView = sqlite3SelectDup(pTab->pSelect); pView = sqlite3SelectDup(pTab->pSelect);
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0); sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView); sqlite3SelectDelete(pView);
} }
@ -277,9 +300,9 @@ void sqlite3Update(
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
if( pWInfo==0 ) goto update_cleanup; if( pWInfo==0 ) goto update_cleanup;
/* Remember the index of every item to be updated. /* Remember the rowid of every item to be updated.
*/ */
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
/* End the database scan loop. /* End the database scan loop.
@ -289,7 +312,8 @@ void sqlite3Update(
/* Initialize the count of updated rows /* Initialize the count of updated rows
*/ */
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){ if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0); memCnt = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
} }
if( triggers_exist ){ if( triggers_exist ){
@ -358,7 +382,7 @@ void sqlite3Update(
} }
} }
if( !isView ){ if( !isView && !IsVirtual(pTab) ){
/* /*
** Open every index that needs updating. Note that if any ** Open every index that needs updating. Note that if any
** index could potentially invoke a REPLACE conflict resolution ** index could potentially invoke a REPLACE conflict resolution
@ -390,7 +414,7 @@ void sqlite3Update(
/* Loop over every record that needs updating. We have to load /* Loop over every record that needs updating. We have to load
** the old data for each record to be updated because some columns ** the old data for each record to be updated because some columns
** might not change and we will need to copy the old value. ** might not change and we will need to copy the old value.
** Also, the old data is needed to delete the old index entires. ** Also, the old data is needed to delete the old index entries.
** So make the cursor point at the old record. ** So make the cursor point at the old record.
*/ */
if( !triggers_exist ){ if( !triggers_exist ){
@ -447,7 +471,7 @@ void sqlite3Update(
/* Increment the row counter /* Increment the row counter
*/ */
if( db->flags & SQLITE_CountRows && !pParse->trigStack){ if( db->flags & SQLITE_CountRows && !pParse->trigStack){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
} }
/* If there are triggers, close all the cursors after each iteration /* If there are triggers, close all the cursors after each iteration
@ -492,6 +516,7 @@ void sqlite3Update(
** invoke the callback function. ** invoke the callback function.
*/ */
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){ if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0); sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
@ -506,3 +531,95 @@ update_cleanup:
sqlite3ExprDelete(pWhere); sqlite3ExprDelete(pWhere);
return; return;
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Generate code for an UPDATE of a virtual table.
**
** The strategy is that we create an ephemerial table that contains
** for each row to be changed:
**
** (A) The original rowid of that row.
** (B) The revised rowid for the row. (note1)
** (C) The content of every column in the row.
**
** Then we loop over this ephemeral table and for each row in
** the ephermeral table call VUpdate.
**
** When finished, drop the ephemeral table.
**
** (note1) Actually, if we know in advance that (A) is always the same
** as (B) we only store (A), then duplicate (A) when pulling
** it out of the ephemeral table before calling VUpdate.
*/
static void updateVirtualTable(
Parse *pParse, /* The parsing context */
SrcList *pSrc, /* The virtual table to be modified */
Table *pTab, /* The virtual table */
ExprList *pChanges, /* The columns to change in the UPDATE statement */
Expr *pRowid, /* Expression used to recompute the rowid */
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
Expr *pWhere /* WHERE clause of the UPDATE statement */
){
Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */
ExprList *pEList = 0; /* The result set of the SELECT statement */
Select *pSelect = 0; /* The SELECT statement */
Expr *pExpr; /* Temporary expression */
int ephemTab; /* Table holding the result of the SELECT */
int i; /* Loop counter */
int addr; /* Address of top of loop */
/* Construct the SELECT statement that will find the new values for
** all updated rows.
*/
pEList = sqlite3ExprListAppend(0, sqlite3CreateIdExpr("_rowid_"), 0);
if( pRowid ){
pEList = sqlite3ExprListAppend(pEList, sqlite3ExprDup(pRowid), 0);
}
assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
pExpr = sqlite3ExprDup(pChanges->a[aXRef[i]].pExpr);
}else{
pExpr = sqlite3CreateIdExpr(pTab->aCol[i].zName);
}
pEList = sqlite3ExprListAppend(pEList, pExpr, 0);
}
pSelect = sqlite3SelectNew(pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
/* Create the ephemeral table into which the update results will
** be stored.
*/
assert( v );
ephemTab = pParse->nTab++;
sqlite3VdbeAddOp(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
/* fill the ephemeral table
*/
sqlite3Select(pParse, pSelect, SRT_Table, ephemTab, 0, 0, 0, 0);
/*
** Generate code to scan the ephemeral table and call VDelete and
** VInsert
*/
sqlite3VdbeAddOp(v, OP_Rewind, ephemTab, 0);
addr = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp(v, OP_Column, ephemTab, 0);
if( pRowid ){
sqlite3VdbeAddOp(v, OP_Column, ephemTab, 1);
}else{
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
}
for(i=0; i<pTab->nCol; i++){
sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0));
}
pParse->pVirtualLock = pTab;
sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2,
(const char*)pTab->pVtab, P3_VTAB);
sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr);
sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0);
/* Cleanup */
sqlite3SelectDelete(pSelect);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

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,11 +101,24 @@ 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) { \
@ -113,11 +126,14 @@ static const int xtra_utf8_bits[4] = {
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 );
@ -287,11 +305,11 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
/* Set len to the maximum number of bytes required in the output buffer. */ /* Set len to the maximum number of bytes required in the output buffer. */
if( desiredEnc==SQLITE_UTF8 ){ if( desiredEnc==SQLITE_UTF8 ){
/* When converting from UTF-16, the maximum growth results from /* When converting from UTF-16, the maximum growth results from
** translating a 2-byte character to a 3-byte UTF-8 character (i.e. ** translating a 2-byte character to a 4-byte UTF-8 character.
** code-point 0xFFFC). A single byte is required for the output string ** A single byte is required for the output string
** nul-terminator. ** nul-terminator.
*/ */
len = (pMem->n/2) * 3 + 1; len = pMem->n * 2 + 1;
}else{ }else{
/* When converting from UTF-8 to UTF-16 the maximum growth is caused /* When converting from UTF-8 to UTF-16 the maximum growth is caused
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
@ -462,8 +480,8 @@ char *sqlite3utf16to8(const void *z, int nByte){
memset(&m, 0, sizeof(m)); memset(&m, 0, sizeof(m));
sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC); sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8); sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
assert( m.flags & MEM_Term ); assert( (m.flags & MEM_Term)!=0 || sqlite3MallocFailed() );
assert( m.flags & MEM_Str ); assert( (m.flags & MEM_Str)!=0 || sqlite3MallocFailed() );
return (m.flags & MEM_Dyn)!=0 ? m.z : sqliteStrDup(m.z); return (m.flags & MEM_Dyn)!=0 ? m.z : sqliteStrDup(m.z);
} }
@ -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

@ -476,8 +476,9 @@ static int OSSIZEOF(void *p){
** pointer to the space allocated for the application to use. ** pointer to the space allocated for the application to use.
*/ */
static void OSFREE(void *pFree){ static void OSFREE(void *pFree){
u32 *p; /* Pointer to the OS-layer allocation */
sqlite3OsEnterMutex(); sqlite3OsEnterMutex();
u32 *p = (u32 *)getOsPointer(pFree); /* p points to Os level allocation */ p = (u32 *)getOsPointer(pFree);
checkGuards(p); checkGuards(p);
unlinkAlloc(p); unlinkAlloc(p);
memset(pFree, 0x55, OSSIZEOF(pFree)); memset(pFree, 0x55, OSSIZEOF(pFree));
@ -683,11 +684,11 @@ void sqlite3ReallocOrFree(void **pp, int n){
*/ */
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
void *sqlite3ThreadSafeMalloc(int n){ void *sqlite3ThreadSafeMalloc(int n){
ENTER_MALLOC; (void)ENTER_MALLOC;
return sqlite3Malloc(n, 0); return sqlite3Malloc(n, 0);
} }
void sqlite3ThreadSafeFree(void *p){ void sqlite3ThreadSafeFree(void *p){
ENTER_MALLOC; (void)ENTER_MALLOC;
if( p ){ if( p ){
OSFREE(p); OSFREE(p);
} }
@ -1150,7 +1151,7 @@ int sqlite3SafetyOn(sqlite3 *db){
return 0; return 0;
}else if( db->magic==SQLITE_MAGIC_BUSY ){ }else if( db->magic==SQLITE_MAGIC_BUSY ){
db->magic = SQLITE_MAGIC_ERROR; db->magic = SQLITE_MAGIC_ERROR;
db->flags |= SQLITE_Interrupt; db->u1.isInterrupted = 1;
} }
return 1; return 1;
} }
@ -1166,7 +1167,7 @@ int sqlite3SafetyOff(sqlite3 *db){
return 0; return 0;
}else if( db->magic==SQLITE_MAGIC_OPEN ){ }else if( db->magic==SQLITE_MAGIC_OPEN ){
db->magic = SQLITE_MAGIC_ERROR; db->magic = SQLITE_MAGIC_ERROR;
db->flags |= SQLITE_Interrupt; db->u1.isInterrupted = 1;
} }
return 1; return 1;
} }
@ -1356,9 +1357,11 @@ void *sqlite3HexToBlob(const char *z){
if( n%2 ) return 0; if( n%2 ) return 0;
zBlob = (char *)sqliteMalloc(n/2); zBlob = (char *)sqliteMalloc(n/2);
if( zBlob ){
for(i=0; i<n; i+=2){ for(i=0; i<n; i+=2){
zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]); zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
} }
}
return zBlob; return zBlob;
} }
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ #endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
@ -1443,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

@ -57,17 +57,21 @@
** working correctly. This variable has no function other than to ** working correctly. This variable has no function other than to
** help verify the correct operation of the library. ** help verify the correct operation of the library.
*/ */
#ifdef SQLITE_TEST
int sqlite3_search_count = 0; int sqlite3_search_count = 0;
#endif
/* /*
** When this global variable is positive, it gets decremented once before ** When this global variable is positive, it gets decremented once before
** each instruction in the VDBE. When reaches zero, the SQLITE_Interrupt ** each instruction in the VDBE. When reaches zero, the u1.isInterrupted
** of the db.flags field is set in order to simulate and interrupt. ** field of the sqlite3 structure is set in order to simulate and interrupt.
** **
** This facility is used for testing purposes only. It does not function ** This facility is used for testing purposes only. It does not function
** in an ordinary build. ** in an ordinary build.
*/ */
#ifdef SQLITE_TEST
int sqlite3_interrupt_count = 0; int sqlite3_interrupt_count = 0;
#endif
/* /*
** The next global variable is incremented each type the OP_Sort opcode ** The next global variable is incremented each type the OP_Sort opcode
@ -76,7 +80,9 @@ int sqlite3_interrupt_count = 0;
** has no function other than to help verify the correct operation of the ** has no function other than to help verify the correct operation of the
** library. ** library.
*/ */
#ifdef SQLITE_TEST
int sqlite3_sort_count = 0; int sqlite3_sort_count = 0;
#endif
/* /*
** Release the memory associated with the given stack level. This ** Release the memory associated with the given stack level. This
@ -180,7 +186,7 @@ static Cursor *allocateCursor(Vdbe *p, int iCur, int iDb){
Cursor *pCx; Cursor *pCx;
assert( iCur<p->nCursor ); assert( iCur<p->nCursor );
if( p->apCsr[iCur] ){ if( p->apCsr[iCur] ){
sqlite3VdbeFreeCursor(p->apCsr[iCur]); sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
} }
p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) ); p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) );
if( pCx ){ if( pCx ){
@ -376,7 +382,7 @@ __inline__ unsigned long long int hwtime(void){
** flag on jump instructions, we get a (small) speed improvement. ** flag on jump instructions, we get a (small) speed improvement.
*/ */
#define CHECK_FOR_INTERRUPT \ #define CHECK_FOR_INTERRUPT \
if( db->flags & SQLITE_Interrupt ) goto abort_due_to_interrupt; if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
/* /*
@ -448,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] );
@ -495,11 +516,14 @@ int sqlite3VdbeExec(
*/ */
if( db->xProgress ){ if( db->xProgress ){
if( db->nProgressOps==nProgressOps ){ if( db->nProgressOps==nProgressOps ){
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
if( db->xProgress(db->pProgressArg)!=0 ){ if( db->xProgress(db->pProgressArg)!=0 ){
sqlite3SafetyOn(db);
rc = SQLITE_ABORT; rc = SQLITE_ABORT;
continue; /* skip to the next iteration of the for loop */ continue; /* skip to the next iteration of the for loop */
} }
nProgressOps = 0; nProgressOps = 0;
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
} }
nProgressOps++; nProgressOps++;
} }
@ -1803,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;
@ -2001,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
@ -2492,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;
@ -2637,9 +2664,9 @@ case OP_OpenWrite: { /* no-push */
break; break;
} }
/* Opcode: OpenVirtual P1 P2 P3 /* Opcode: OpenEphemeral P1 P2 P3
** **
** Open a new cursor P1 to a transient or virtual table. ** Open a new cursor P1 to a transient table.
** The cursor is always opened read/write even if ** The cursor is always opened read/write even if
** the main database is read-only. The transient or virtual ** the main database is read-only. The transient or virtual
** table is deleted automatically when the cursor is closed. ** table is deleted automatically when the cursor is closed.
@ -2648,8 +2675,14 @@ case OP_OpenWrite: { /* no-push */
** The cursor points to a BTree table if P3==0 and to a BTree index ** The cursor points to a BTree table if P3==0 and to a BTree index
** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure ** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index. ** that defines the format of keys in the index.
**
** This opcode was once called OpenTemp. But that created
** confusion because the term "temp table", might refer either
** to a TEMP table at the SQL level, or to a table opened by
** this opcode. Then this opcode was call OpenVirtual. But
** that created confusion with the whole virtual-table idea.
*/ */
case OP_OpenVirtual: { /* no-push */ case OP_OpenEphemeral: { /* no-push */
int i = pOp->p1; int i = pOp->p1;
Cursor *pCx; Cursor *pCx;
assert( i>=0 ); assert( i>=0 );
@ -2724,7 +2757,7 @@ case OP_OpenPseudo: { /* no-push */
case OP_Close: { /* no-push */ case OP_Close: { /* no-push */
int i = pOp->p1; int i = pOp->p1;
if( i>=0 && i<p->nCursor ){ if( i>=0 && i<p->nCursor ){
sqlite3VdbeFreeCursor(p->apCsr[i]); sqlite3VdbeFreeCursor(p, p->apCsr[i]);
p->apCsr[i] = 0; p->apCsr[i] = 0;
} }
break; break;
@ -2815,7 +2848,9 @@ case OP_MoveGt: { /* no-push */
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
*pC->pIncrKey = 0; *pC->pIncrKey = 0;
#ifdef SQLITE_TEST
sqlite3_search_count++; sqlite3_search_count++;
#endif
if( oc==OP_MoveGe || oc==OP_MoveGt ){ if( oc==OP_MoveGe || oc==OP_MoveGt ){
if( res<0 ){ if( res<0 ){
rc = sqlite3BtreeNext(pC->pCursor, &res); rc = sqlite3BtreeNext(pC->pCursor, &res);
@ -2890,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
@ -2963,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;
@ -3064,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;
@ -3260,6 +3298,10 @@ case OP_NewRowid: {
** then rowid is stored for subsequent return by the ** then rowid is stored for subsequent return by the
** sqlite3_last_insert_rowid() function (otherwise it's unmodified). ** sqlite3_last_insert_rowid() function (otherwise it's unmodified).
** **
** Parameter P3 may point to a string containing the table-name, or
** may be NULL. If it is not NULL, then the update-hook
** (sqlite3.xUpdateCallback) is invoked following a successful insert.
**
** This instruction only works on tables. The equivalent instruction ** This instruction only works on tables. The equivalent instruction
** for indices is OP_IdxInsert. ** for indices is OP_IdxInsert.
*/ */
@ -3569,8 +3611,10 @@ case OP_Last: { /* no-push */
** correctly optimizing out sorts. ** correctly optimizing out sorts.
*/ */
case OP_Sort: { /* no-push */ case OP_Sort: { /* no-push */
#ifdef SQLITE_TEST
sqlite3_sort_count++; sqlite3_sort_count++;
sqlite3_search_count--; sqlite3_search_count--;
#endif
/* Fall through into OP_Rewind */ /* Fall through into OP_Rewind */
} }
/* Opcode: Rewind P1 P2 * /* Opcode: Rewind P1 P2 *
@ -3643,7 +3687,9 @@ case OP_Next: { /* no-push */
} }
if( res==0 ){ if( res==0 ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
#ifdef SQLITE_TEST
sqlite3_search_count++; sqlite3_search_count++;
#endif
} }
}else{ }else{
pC->nullRow = 1; pC->nullRow = 1;
@ -3827,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
@ -3881,19 +3895,31 @@ case OP_IdxIsNull: { /* no-push */
*/ */
case OP_Destroy: { case OP_Destroy: {
int iMoved; int iMoved;
if( db->activeVdbeCnt>1 ){ int iCnt;
#ifndef SQLITE_OMIT_VIRTUALTABLE
Vdbe *pVdbe;
iCnt = 0;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){
iCnt++;
}
}
#else
iCnt = db->activeVdbeCnt;
#endif
if( iCnt>1 ){
rc = SQLITE_LOCKED; rc = SQLITE_LOCKED;
}else{ }else{
assert( db->activeVdbeCnt==1 ); assert( iCnt==1 );
rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved); rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
pTos++; pTos++;
pTos->flags = MEM_Int; pTos->flags = MEM_Int;
pTos->i = iMoved; pTos->i = iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
if( rc==SQLITE_OK && iMoved!=0 ){ if( rc==SQLITE_OK && iMoved!=0 ){
sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1); sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1);
} }
#endif #endif
} }
break; break;
} }
@ -3995,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.
@ -4010,19 +4040,23 @@ 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 );
db->init.busy = 1; db->init.busy = 1;
assert( !sqlite3MallocFailed() ); assert( !sqlite3MallocFailed() );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_ABORT ) rc = initData.rc;
sqliteFree(zSql); sqliteFree(zSql);
db->init.busy = 0; db->init.busy = 0;
sqlite3SafetyOn(db); sqlite3SafetyOn(db);
@ -4086,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
@ -4099,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;
@ -4113,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] = (int)pMem->i; aRoot[j] = (int)pMem->i;
@ -4120,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 ){ (int)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);
@ -4461,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
@ -4473,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 * *
** **
@ -4522,7 +4569,316 @@ case OP_TableLock: { /* no-push */
} }
break; break;
} }
#endif /* SHARED_OMIT_SHARED_CACHE */ #endif /* SQLITE_OMIT_SHARED_CACHE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VBegin * * P3
**
** P3 a pointer to an sqlite3_vtab structure. Call the xBegin method
** for that table.
*/
case OP_VBegin: { /* no-push */
rc = sqlite3VtabBegin(db, (sqlite3_vtab *)pOp->p3);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VCreate P1 * P3
**
** P3 is the name of a virtual table in database P1. Call the xCreate method
** for that table.
*/
case OP_VCreate: { /* no-push */
rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p3, &p->zErrMsg);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VDestroy P1 * P3
**
** P3 is the name of a virtual table in database P1. Call the xDestroy method
** of that table.
*/
case OP_VDestroy: { /* no-push */
p->inVtabMethod = 2;
rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p3);
p->inVtabMethod = 0;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VOpen P1 * P3
**
** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
** P1 is a cursor number. This opcode opens a cursor to the virtual
** table and stores that cursor in P1.
*/
case OP_VOpen: { /* no-push */
Cursor *pCur = 0;
sqlite3_vtab_cursor *pVtabCursor = 0;
sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3);
sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;
assert(pVtab && pModule);
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = pModule->xOpen(pVtab, &pVtabCursor);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( SQLITE_OK==rc ){
/* Initialise sqlite3_vtab_cursor base class */
pVtabCursor->pVtab = pVtab;
/* Initialise vdbe cursor object */
pCur = allocateCursor(p, pOp->p1, -1);
if( pCur ){
pCur->pVtabCursor = pVtabCursor;
pCur->pModule = pVtabCursor->pVtab->pModule;
}else{
pModule->xClose(pVtabCursor);
}
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VFilter P1 P2 P3
**
** P1 is a cursor opened using VOpen. P2 is an address to jump to if
** the filtered result set is empty.
**
** P3 is either NULL or a string that was generated by the xBestIndex
** method of the module. The interpretation of the P3 string is left
** to the module implementation.
**
** This opcode invokes the xFilter method on the virtual table specified
** by P1. The integer query plan parameter to xFilter is the top of the
** stack. Next down on the stack is the argc parameter. Beneath the
** next of stack are argc additional parameters which are passed to
** xFilter as argv. The topmost parameter (i.e. 3rd element popped from
** the stack) becomes argv[argc-1] when passed to xFilter.
**
** The integer query plan parameter, argc, and all argv stack values
** are popped from the stack before this instruction completes.
**
** A jump is made to P2 if the result set after filtering would be
** empty.
*/
case OP_VFilter: { /* no-push */
int nArg;
const sqlite3_module *pModule;
Cursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
pModule = pCur->pVtabCursor->pVtab->pModule;
/* Grab the index number and argc parameters off the top of the stack. */
assert( (&pTos[-1])>=p->aStack );
assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int );
nArg = (int)pTos[-1].i;
/* Invoke the xFilter method */
{
int res = 0;
int i;
Mem **apArg = p->apArg;
for(i = 0; i<nArg; i++){
apArg[i] = &pTos[i+1-2-nArg];
storeTypeInfo(apArg[i], 0);
}
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
p->inVtabMethod = 1;
rc = pModule->xFilter(pCur->pVtabCursor, (int)pTos->i, pOp->p3, nArg, apArg);
p->inVtabMethod = 0;
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
}
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( res ){
pc = pOp->p2 - 1;
}
}
/* Pop the index number, argc value and parameters off the stack */
popStack(&pTos, 2+nArg);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VRowid P1 * *
**
** Push an integer onto the stack which is the rowid of
** the virtual-table that the P1 cursor is pointing to.
*/
case OP_VRowid: {
const sqlite3_module *pModule;
Cursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
pModule = pCur->pVtabCursor->pVtab->pModule;
if( pModule->xRowid==0 ){
sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xRowid", 0);
rc = SQLITE_ERROR;
} else {
sqlite_int64 iRow;
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = pModule->xRowid(pCur->pVtabCursor, &iRow);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
pTos++;
pTos->flags = MEM_Int;
pTos->i = iRow;
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VColumn P1 P2 *
**
** Push onto the stack the value of the P2-th column of
** the row of the virtual-table that the P1 cursor is pointing to.
*/
case OP_VColumn: {
const sqlite3_module *pModule;
Cursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
pModule = pCur->pVtabCursor->pVtab->pModule;
if( pModule->xColumn==0 ){
sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xColumn", 0);
rc = SQLITE_ERROR;
} else {
sqlite3_context sContext;
memset(&sContext, 0, sizeof(sContext));
sContext.s.flags = MEM_Null;
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
/* Copy the result of the function to the top of the stack. We
** do this regardless of whether or not an error occured to ensure any
** dynamic allocation in sContext.s (a Mem struct) is released.
*/
sqlite3VdbeChangeEncoding(&sContext.s, encoding);
pTos++;
pTos->flags = 0;
sqlite3VdbeMemMove(pTos, &sContext.s);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VNext P1 P2 *
**
** Advance virtual table P1 to the next row in its result set and
** jump to instruction P2. Or, if the virtual table has reached
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: { /* no-push */
const sqlite3_module *pModule;
int res = 0;
Cursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
pModule = pCur->pVtabCursor->pVtab->pModule;
if( pModule->xNext==0 ){
sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xNext", 0);
rc = SQLITE_ERROR;
} else {
/* Invoke the xNext() method of the module. There is no way for the
** underlying implementation to return an error if one occurs during
** xNext(). Instead, if an error occurs, true is returned (indicating that
** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor.
*/
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
p->inVtabMethod = 1;
rc = pModule->xNext(pCur->pVtabCursor);
p->inVtabMethod = 0;
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
}
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( !res ){
/* If there is data, jump to P2 */
pc = pOp->p2 - 1;
}
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VUpdate P1 P2 P3
**
** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
** This opcode invokes the corresponding xUpdate method. P2 values
** are taken from the stack to pass to the xUpdate invocation. The
** value on the top of the stack corresponds to the p2th element
** of the argv array passed to xUpdate.
**
** The xUpdate method will do a DELETE or an INSERT or both.
** The argv[0] element (which corresponds to the P2-th element down
** on the stack) is the rowid of a row to delete. If argv[0] is
** NULL then no deletion occurs. The argv[1] element is the rowid
** of the new row. This can be NULL to have the virtual table
** select the new rowid for itself. The higher elements in the
** stack are the values of columns in the new row.
**
** If P2==1 then no insert is performed. argv[0] is the rowid of
** a row to delete.
**
** P1 is a boolean flag. If it is set to true and the xUpdate call
** is successful, then the value returned by sqlite3_last_insert_rowid()
** is set to the value of the rowid for the row just inserted.
*/
case OP_VUpdate: { /* no-push */
sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3);
sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;
int nArg = pOp->p2;
assert( pOp->p3type==P3_VTAB );
if( pModule->xUpdate==0 ){
sqlite3SetString(&p->zErrMsg, "read-only table", 0);
rc = SQLITE_ERROR;
}else{
int i;
sqlite_int64 rowid;
Mem **apArg = p->apArg;
Mem *pX = &pTos[1-nArg];
for(i = 0; i<nArg; i++, pX++){
storeTypeInfo(pX, 0);
apArg[i] = pX;
}
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
sqlite3VtabLock(pVtab);
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
sqlite3VtabUnlock(pVtab);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( pOp->p1 && rc==SQLITE_OK ){
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
db->lastRowid = rowid;
}
}
popStack(&pTos, nArg);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/* An other opcode is illegal... /* An other opcode is illegal...
*/ */
@ -4560,8 +4916,12 @@ default: {
** the evaluator loop. So we can leave it out when NDEBUG is defined. ** the evaluator loop. So we can leave it out when NDEBUG is defined.
*/ */
#ifndef NDEBUG #ifndef NDEBUG
/* Sanity checking on the top element of the stack */ /* Sanity checking on the top element of the stack. If the previous
if( pTos>=p->aStack ){ ** instruction was VNoChange, then the flags field of the top
** of the stack is set to 0. This is technically invalid for a memory
** cell, so avoid calling MemSanity() in this case.
*/
if( pTos>=p->aStack && pTos->flags ){
sqlite3VdbeMemSanity(pTos); sqlite3VdbeMemSanity(pTos);
} }
assert( pc>=-1 && pc<p->nOp ); assert( pc>=-1 && pc<p->nOp );
@ -4634,8 +4994,7 @@ abort_due_to_error:
** flag. ** flag.
*/ */
abort_due_to_interrupt: abort_due_to_interrupt:
assert( db->flags & SQLITE_Interrupt ); assert( db->u1.isInterrupted );
db->flags &= ~SQLITE_Interrupt;
if( db->magic!=SQLITE_MAGIC_BUSY ){ if( db->magic!=SQLITE_MAGIC_BUSY ){
rc = SQLITE_MISUSE; rc = SQLITE_MISUSE;
}else{ }else{

View File

@ -70,6 +70,8 @@ typedef struct VdbeOpList VdbeOpList;
#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */ #define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */
#define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */ #define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */
#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */ #define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */
#define P3_VTAB (-10) /* P3 is a pointer to an sqlite3_vtab structure */
#define P3_MPRINTF (-11) /* P3 is a string obtained from sqlite3_mprintf() */
/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure /* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
** is made. That copy is freed when the Vdbe is finalized. But if the ** is made. That copy is freed when the Vdbe is finalized. But if the
@ -127,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
@ -83,6 +85,8 @@ struct Cursor {
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
int nField; /* Number of fields in the header */ int nField; /* Number of fields in the header */
i64 seqCount; /* Sequence counter */ i64 seqCount; /* Sequence counter */
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
/* Cached information about the header for the data record that the /* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheValid is true. ** cursor is currently pointing to. Only valid if cacheValid is true.
@ -268,6 +272,14 @@ struct Context {
** **
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile() ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
** is really a pointer to an instance of this structure. ** is really a pointer to an instance of this structure.
**
** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
** any virtual table method invocations made by the vdbe program. It is
** set to 2 for xDestroy method calls and 1 for all other methods. This
** variable is used for two purposes: to allow xDestroy methods to execute
** "DROP TABLE" statements and to prevent some nasty side effects of
** malloc failure when SQLite is invoked recursively by a virtual table
** method function.
*/ */
struct Vdbe { struct Vdbe {
sqlite3 *db; /* The whole database */ sqlite3 *db; /* The whole database */
@ -315,8 +327,11 @@ struct Vdbe {
u8 aborted; /* True if ROLLBACK in another VM causes an abort */ u8 aborted; /* True if ROLLBACK in another VM causes an abort */
u8 expired; /* True if the VM needs to be recompiled */ u8 expired; /* True if the VM needs to be recompiled */
u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 minWriteFileFormat; /* Minimum file format for writable database files */
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 */
@ -334,7 +349,7 @@ struct Vdbe {
/* /*
** Function prototypes ** Function prototypes
*/ */
void sqlite3VdbeFreeCursor(Cursor*); void sqlite3VdbeFreeCursor(Vdbe *, Cursor*);
void sqliteVdbePopStack(Vdbe*,int); void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*); int sqlite3VdbeCursorMoveto(Cursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@ -390,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) ){
@ -180,6 +185,14 @@ int sqlite3_step(sqlite3_stmt *pStmt){
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
if( p->pc<0 ){ if( p->pc<0 ){
/* If there are no other statements currently running, then
** reset the interrupt flag. This prevents a call to sqlite3_interrupt
** from interrupting a statement that has not yet started.
*/
if( db->activeVdbeCnt==0 ){
db->u1.isInterrupted = 0;
}
#ifndef SQLITE_OMIT_TRACE #ifndef SQLITE_OMIT_TRACE
/* Invoke the trace callback if there is one /* Invoke the trace callback if there is one
*/ */
@ -198,7 +211,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
if( db->xProfile && !db->init.busy ){ if( db->xProfile && !db->init.busy ){
double rNow; double rNow;
sqlite3OsCurrentTime(&rNow); sqlite3OsCurrentTime(&rNow);
p->startTime = (int)((rNow - (int)rNow)*3600.0*24.0*1000000000.0); p->startTime = (i64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
} }
#endif #endif
@ -246,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;
}
}
/*
** 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; 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
@ -258,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
@ -375,10 +443,9 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
Vdbe *pVm = (Vdbe *)pStmt; Vdbe *pVm = (Vdbe *)pStmt;
int vals = sqlite3_data_count(pStmt); int vals = sqlite3_data_count(pStmt);
if( i>=vals || i<0 ){ if( i>=vals || i<0 ){
static Mem nullMem; static const Mem nullMem = {0, 0.0, "", 0, MEM_Null, MEM_Null };
if( nullMem.flags==0 ){ nullMem.flags = MEM_Null; }
sqlite3Error(pVm->db, SQLITE_RANGE, 0); sqlite3Error(pVm->db, SQLITE_RANGE, 0);
return &nullMem; return (Mem*)&nullMem;
} }
return &pVm->pTos[(1-vals)+i]; return &pVm->pTos[(1-vals)+i];
} }
@ -454,11 +521,9 @@ const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
columnMallocFailure(pStmt); columnMallocFailure(pStmt);
return val; return val;
} }
#if 0
sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){ sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
return columnMem(pStmt, i); return columnMem(pStmt, i);
} }
#endif
#ifndef SQLITE_OMIT_UTF16 #ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){ const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
const void *val = sqlite3_value_text16( columnMem(pStmt,i) ); const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
@ -713,6 +778,15 @@ int sqlite3_bind_text16(
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
} }
#endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_UTF16 */
int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
if( rc==SQLITE_OK ){
sqlite3VdbeMemCopy(&p->aVar[i-1], pValue);
}
return rc;
}
/* /*
** Return the number of wildcards that can be potentially bound to. ** Return the number of wildcards that can be potentially bound to.
@ -801,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
*/ */
@ -228,7 +268,7 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
** This routine is called once after all opcodes have been inserted. ** This routine is called once after all opcodes have been inserted.
** **
** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument ** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
** to an OP_Function or OP_AggStep opcode. This is used by ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
** **
** The integer *pMaxStack is set to the maximum number of vdbe stack ** The integer *pMaxStack is set to the maximum number of vdbe stack
@ -251,20 +291,25 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
u8 opcode = pOp->opcode; u8 opcode = pOp->opcode;
if( opcode==OP_Function || opcode==OP_AggStep ){ if( opcode==OP_Function || opcode==OP_AggStep
#ifndef SQLITE_OMIT_VIRTUALTABLE
|| opcode==OP_VUpdate
#endif
){
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
}else if( opcode==OP_Halt ){ }else if( opcode==OP_Halt ){
if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
doesStatementRollback = 1; doesStatementRollback = 1;
} }
}else if( opcode==OP_IdxInsert ){
if( pOp->p2 ){
doesStatementRollback = 1;
}
}else if( opcode==OP_Statement ){ }else if( opcode==OP_Statement ){
hasStatementBegin = 1; hasStatementBegin = 1;
}else if( opcode==OP_VFilter ){
int n;
assert( p->nOp - i >= 3 );
assert( pOp[-2].opcode==OP_Integer );
n = pOp[-2].p1;
if( n>nMaxArgs ) nMaxArgs = n;
} }
if( opcodeNoPush(opcode) ){ if( opcodeNoPush(opcode) ){
nMaxStack--; nMaxStack--;
} }
@ -368,6 +413,17 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){
sqlite3VdbeChangeP2(p, addr, p->nOp); sqlite3VdbeChangeP2(p, addr, p->nOp);
} }
/*
** If the input FuncDef structure is ephemeral, then free it. If
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(FuncDef *pDef){
if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){
sqliteFree(pDef);
}
}
/* /*
** Delete a P3 value if necessary. ** Delete a P3 value if necessary.
*/ */
@ -380,12 +436,21 @@ static void freeP3(int p3type, void *p3){
sqliteFree(p3); sqliteFree(p3);
break; break;
} }
case P3_MPRINTF: {
sqlite3_free(p3);
break;
}
case P3_VDBEFUNC: { case P3_VDBEFUNC: {
VdbeFunc *pVdbeFunc = (VdbeFunc *)p3; VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
freeEphemeralFunction(pVdbeFunc->pFunc);
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
sqliteFree(pVdbeFunc); sqliteFree(pVdbeFunc);
break; break;
} }
case P3_FUNCDEF: {
freeEphemeralFunction((FuncDef*)p3);
break;
}
case P3_MEM: { case P3_MEM: {
sqlite3ValueFree((sqlite3_value*)p3); sqlite3ValueFree((sqlite3_value*)p3);
break; break;
@ -558,15 +623,18 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
} }
case P3_FUNCDEF: { case P3_FUNCDEF: {
FuncDef *pDef = (FuncDef*)pOp->p3; FuncDef *pDef = (FuncDef*)pOp->p3;
char zNum[30]; sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
sprintf(zTemp, "%.*s", nTemp, pDef->zName);
sprintf(zNum,"(%d)", pDef->nArg);
if( strlen(zTemp)+strlen(zNum)+1<=(size_t)nTemp ){
strcat(zTemp, zNum);
}
zP3 = zTemp; zP3 = zTemp;
break; break;
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE
case P3_VTAB: {
sqlite3_vtab *pVtab = (sqlite3_vtab*)pOp->p3;
sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
zP3 = zTemp;
break;
}
#endif
default: { default: {
zP3 = pOp->p3; zP3 = pOp->p3;
if( zP3==0 || pOp->opcode==OP_Noop ){ if( zP3==0 || pOp->opcode==OP_Noop ){
@ -574,6 +642,7 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
} }
} }
} }
assert( zP3!=0 );
return zP3; return zP3;
} }
#endif #endif
@ -641,8 +710,7 @@ int sqlite3VdbeList(
if( i>=p->nOp ){ if( i>=p->nOp ){
p->rc = SQLITE_OK; p->rc = SQLITE_OK;
rc = SQLITE_DONE; rc = SQLITE_DONE;
}else if( db->flags & SQLITE_Interrupt ){ }else if( db->u1.isInterrupted ){
db->flags &= ~SQLITE_Interrupt;
p->rc = SQLITE_INTERRUPT; p->rc = SQLITE_INTERRUPT;
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0); sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0);
@ -656,6 +724,7 @@ int sqlite3VdbeList(
pMem->flags = MEM_Static|MEM_Str|MEM_Term; pMem->flags = MEM_Static|MEM_Str|MEM_Term;
pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */ pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */
assert( pMem->z!=0 );
pMem->n = strlen(pMem->z); pMem->n = strlen(pMem->z);
pMem->type = SQLITE_TEXT; pMem->type = SQLITE_TEXT;
pMem->enc = SQLITE_UTF8; pMem->enc = SQLITE_UTF8;
@ -673,6 +742,7 @@ int sqlite3VdbeList(
pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P3 */ pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P3 */
pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort)); pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort));
assert( pMem->z!=0 );
pMem->n = strlen(pMem->z); pMem->n = strlen(pMem->z);
pMem->type = SQLITE_TEXT; pMem->type = SQLITE_TEXT;
pMem->enc = SQLITE_UTF8; pMem->enc = SQLITE_UTF8;
@ -752,7 +822,9 @@ void sqlite3VdbeMakeReady(
resizeOpArray(p, p->nOp); resizeOpArray(p, p->nOp);
assert( nVar>=0 ); assert( nVar>=0 );
assert( nStack<p->nOp ); assert( nStack<p->nOp );
nStack = isExplain ? 10 : nStack; if( isExplain ){
nStack = 10;
}
p->aStack = sqliteMalloc( p->aStack = sqliteMalloc(
nStack*sizeof(p->aStack[0]) /* aStack */ nStack*sizeof(p->aStack[0]) /* aStack */
+ nArg*sizeof(Mem*) /* apArg */ + nArg*sizeof(Mem*) /* apArg */
@ -780,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;
@ -822,7 +879,7 @@ void sqlite3VdbeMakeReady(
** Close a cursor and release all the resources that cursor happens ** Close a cursor and release all the resources that cursor happens
** to hold. ** to hold.
*/ */
void sqlite3VdbeFreeCursor(Cursor *pCx){ void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
if( pCx==0 ){ if( pCx==0 ){
return; return;
} }
@ -832,6 +889,17 @@ void sqlite3VdbeFreeCursor(Cursor *pCx){
if( pCx->pBt ){ if( pCx->pBt ){
sqlite3BtreeClose(pCx->pBt); sqlite3BtreeClose(pCx->pBt);
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pCx->pVtabCursor ){
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
const sqlite3_module *pModule = pCx->pModule;
p->inVtabMethod = 1;
sqlite3SafetyOff(p->db);
pModule->xClose(pVtabCursor);
sqlite3SafetyOn(p->db);
p->inVtabMethod = 0;
}
#endif
sqliteFree(pCx->pData); sqliteFree(pCx->pData);
sqliteFree(pCx->aType); sqliteFree(pCx->aType);
sqliteFree(pCx); sqliteFree(pCx);
@ -844,9 +912,11 @@ static void closeAllCursors(Vdbe *p){
int i; int i;
if( p->apCsr==0 ) return; if( p->apCsr==0 ) return;
for(i=0; i<p->nCursor; i++){ for(i=0; i<p->nCursor; i++){
sqlite3VdbeFreeCursor(p->apCsr[i]); if( !p->inVtabMethod || (p->apCsr[i] && !p->apCsr[i]->pVtabCursor) ){
sqlite3VdbeFreeCursor(p, p->apCsr[i]);
p->apCsr[i] = 0; p->apCsr[i] = 0;
} }
}
} }
/* /*
@ -941,6 +1011,23 @@ static int vdbeCommit(sqlite3 *db){
int rc = SQLITE_OK; int rc = SQLITE_OK;
int needXcommit = 0; int needXcommit = 0;
/* Before doing anything else, call the xSync() callback for any
** virtual module tables written in this transaction. This has to
** be done before determining whether a master journal file is
** required, as an xSync() callback may add an attached database
** to the transaction.
*/
rc = sqlite3VtabSync(db, rc);
if( rc!=SQLITE_OK ){
return rc;
}
/* This loop determines (a) if the commit hook should be invoked and
** (b) how many database files have open write transactions, not
** including the temp database. (b) is important because if more than
** one database file has an open write transaction, a master journal
** file is required for an atomic commit.
*/
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsInTrans(pBt) ){ if( pBt && sqlite3BtreeIsInTrans(pBt) ){
@ -984,6 +1071,7 @@ static int vdbeCommit(sqlite3 *db){
sqlite3BtreeCommit(pBt); sqlite3BtreeCommit(pBt);
} }
} }
sqlite3VtabCommit(db);
} }
} }
@ -1065,25 +1153,26 @@ static int vdbeCommit(sqlite3 *db){
** file name was written into the journal file before the failure ** file name was written into the journal file before the failure
** occured. ** occured.
*/ */
for(i=0; i<db->nDb; i++){ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsInTrans(pBt) ){ if( pBt && sqlite3BtreeIsInTrans(pBt) ){
rc = sqlite3BtreeSync(pBt, zMaster); rc = sqlite3BtreeSync(pBt, zMaster);
if( rc!=SQLITE_OK ){ }
}
sqlite3OsClose(&master); sqlite3OsClose(&master);
if( rc!=SQLITE_OK ){
sqliteFree(zMaster); sqliteFree(zMaster);
return rc; return rc;
} }
}
}
sqlite3OsClose(&master);
/* Delete the master journal file. This commits the transaction. After /* Delete the master journal file. This commits the transaction. After
** doing this the directory is synced again before any individual ** doing this the directory is synced again before any individual
** 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);
@ -1111,29 +1200,13 @@ static int vdbeCommit(sqlite3 *db){
sqlite3BtreeCommit(pBt); sqlite3BtreeCommit(pBt);
} }
} }
sqlite3VtabCommit(db);
} }
#endif #endif
return rc; return rc;
} }
/*
** Find every active VM other than pVdbe and change its status to
** aborted. This happens when one VM causes a rollback due to an
** ON CONFLICT ROLLBACK clause (for example). The other VMs must be
** aborted so that they do not have data rolled out from underneath
** them leading to a segfault.
*/
void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
Vdbe *pOther;
for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
if( pOther==pExcept ) continue;
if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
closeAllCursors(pOther);
pOther->aborted = 1;
}
}
/* /*
** This routine checks that the sqlite3.activeVdbeCnt count variable ** This routine checks that the sqlite3.activeVdbeCnt count variable
** matches the number of vdbe's in the list sqlite3.pVdbe that are ** matches the number of vdbe's in the list sqlite3.pVdbe that are
@ -1160,6 +1233,25 @@ static void checkActiveVdbeCnt(sqlite3 *db){
#define checkActiveVdbeCnt(x) #define checkActiveVdbeCnt(x)
#endif #endif
/*
** Find every active VM other than pVdbe and change its status to
** aborted. This happens when one VM causes a rollback due to an
** ON CONFLICT ROLLBACK clause (for example). The other VMs must be
** aborted so that they do not have data rolled out from underneath
** them leading to a segfault.
*/
void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
Vdbe *pOther;
for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
if( pOther==pExcept ) continue;
if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
checkActiveVdbeCnt(db);
closeAllCursors(pOther);
checkActiveVdbeCnt(db);
pOther->aborted = 1;
}
}
/* /*
** This routine is called the when a VDBE tries to halt. If the VDBE ** This routine is called the when a VDBE tries to halt. If the VDBE
** has made changes and is in autocommit mode, then commit those ** has made changes and is in autocommit mode, then commit those
@ -1212,6 +1304,9 @@ int sqlite3VdbeHalt(Vdbe *p){
if( p->magic!=VDBE_MAGIC_RUN ){ if( p->magic!=VDBE_MAGIC_RUN ){
/* Already halted. Nothing to do. */ /* Already halted. Nothing to do. */
assert( p->magic==VDBE_MAGIC_HALT ); assert( p->magic==VDBE_MAGIC_HALT );
#ifndef SQLITE_OMIT_VIRTUALTABLE
closeAllCursors(p);
#endif
return SQLITE_OK; return SQLITE_OK;
} }
closeAllCursors(p); closeAllCursors(p);
@ -1219,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:
@ -1353,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.
@ -1365,16 +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(db);
sqlite3VdbeHalt(p); sqlite3VdbeHalt(p);
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
@ -1383,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
@ -1432,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;
} }
/* /*
@ -1443,9 +1550,9 @@ int sqlite3VdbeReset(Vdbe *p){
*/ */
int sqlite3VdbeFinalize(Vdbe *p){ 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;
} }
@ -1500,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);
} }
@ -1512,7 +1620,9 @@ void sqlite3VdbeDelete(Vdbe *p){
int sqlite3VdbeCursorMoveto(Cursor *p){ int sqlite3VdbeCursorMoveto(Cursor *p){
if( p->deferredMoveto ){ if( p->deferredMoveto ){
int res, rc; int res, rc;
#ifdef SQLITE_TEST
extern int sqlite3_search_count; extern int sqlite3_search_count;
#endif
assert( p->isTable ); assert( p->isTable );
if( p->isTable ){ if( p->isTable ){
rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res); rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
@ -1528,7 +1638,9 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
rc = sqlite3BtreeNext(p->pCursor, &res); rc = sqlite3BtreeNext(p->pCursor, &res);
if( rc ) return rc; if( rc ) return rc;
} }
#ifdef SQLITE_TEST
sqlite3_search_count++; sqlite3_search_count++;
#endif
p->deferredMoveto = 0; p->deferredMoveto = 0;
p->cacheStatus = CACHE_STALE; p->cacheStatus = CACHE_STALE;
} }
@ -1592,7 +1704,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
i64 i = pMem->i; i64 i = pMem->i;
u64 u; u64 u;
if( file_format>=4 && (i&1)==i ){ if( file_format>=4 && (i&1)==i ){
return 8+(u32)i; return (u32)(8+i);
} }
u = i<0 ? -i : i; u = i<0 ? -i : i;
if( u<=127 ) return 1; if( u<=127 ) return 1;
@ -1648,7 +1760,7 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
} }
len = i = sqlite3VdbeSerialTypeLen(serial_type); len = i = sqlite3VdbeSerialTypeLen(serial_type);
while( i-- ){ while( i-- ){
buf[i] = (char)(v&0xFF); buf[i] = (unsigned char)(v&0xFF);
v >>= 8; v >>= 8;
} }
return len; return len;
@ -1814,14 +1926,13 @@ int sqlite3VdbeRecordCompare(
idx2 += GetVarint( aKey2+idx2, serial_type2 ); idx2 += GetVarint( aKey2+idx2, serial_type2 );
if( d2>=(u32)nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break; if( d2>=(u32)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,9 +130,14 @@ 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;
pMem->flags |= MEM_Term;
} }
return SQLITE_OK; return SQLITE_OK;
} }
@ -776,13 +760,15 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
pVal->flags |= (pVal->flags & MEM_Blob)>>3; pVal->flags |= (pVal->flags & MEM_Blob)>>3;
if( pVal->flags&MEM_Str ){ if( pVal->flags&MEM_Str ){
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(long)pVal->z) ){ if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){
assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 );
if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){ if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){
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

@ -0,0 +1,693 @@
/*
** 2006 June 10
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to help implement virtual tables.
**
** $Id$
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
/*
** External API function used to create a new virtual-table module.
*/
int sqlite3_create_module(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
const sqlite3_module *pModule, /* The definition of the module */
void *pAux /* Context pointer for xCreate/xConnect */
){
int nName = strlen(zName);
Module *pMod = (Module *)sqliteMallocRaw(sizeof(Module) + nName + 1);
if( pMod ){
char *zCopy = (char *)(&pMod[1]);
strcpy(zCopy, zName);
pMod->zName = zCopy;
pMod->pModule = pModule;
pMod->pAux = pAux;
pMod = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod);
sqliteFree(pMod);
sqlite3ResetInternalSchema(db, 0);
}
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.
** This routine is called, for example, just before deleting the Table
** record.
*/
void sqlite3VtabClear(Table *p){
sqlite3_vtab *pVtab = p->pVtab;
if( pVtab ){
assert( p->pMod && p->pMod->pModule );
sqlite3VtabUnlock(pVtab);
p->pVtab = 0;
}
if( p->azModuleArg ){
int i;
for(i=0; i<p->nModuleArg; i++){
sqliteFree(p->azModuleArg[i]);
}
sqliteFree(p->azModuleArg);
}
}
/*
** Add a new module argument to pTable->azModuleArg[].
** The string is not copied - the pointer is stored. The
** string will be freed automatically when the table is
** deleted.
*/
static void addModuleArgument(Table *pTable, char *zArg){
int i = pTable->nModuleArg++;
int nBytes = sizeof(char *)*(1+pTable->nModuleArg);
char **azModuleArg;
azModuleArg = sqliteRealloc(pTable->azModuleArg, nBytes);
if( azModuleArg==0 ){
int j;
for(j=0; j<i; j++){
sqliteFree(pTable->azModuleArg[j]);
}
sqliteFree(zArg);
sqliteFree(pTable->azModuleArg);
pTable->nModuleArg = 0;
}else{
azModuleArg[i] = zArg;
azModuleArg[i+1] = 0;
}
pTable->azModuleArg = azModuleArg;
}
/*
** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE
** statement. The module name has been parsed, but the optional list
** of parameters that follow the module name are still pending.
*/
void sqlite3VtabBeginParse(
Parse *pParse, /* Parsing context */
Token *pName1, /* Name of new table, or database name */
Token *pName2, /* Name of new table or NULL */
Token *pModuleName /* Name of the module for the virtual table */
){
int iDb; /* The database the table is being created in */
Table *pTable; /* The new virtual table */
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
pTable = pParse->pNewTable;
if( pTable==0 || pParse->nErr ) return;
assert( 0==pTable->pIndex );
iDb = sqlite3SchemaToIndex(pParse->db, pTable->pSchema);
assert( iDb>=0 );
pTable->isVirtual = 1;
pTable->nModuleArg = 0;
addModuleArgument(pTable, sqlite3NameFromToken(pModuleName));
addModuleArgument(pTable, sqlite3StrDup(pParse->db->aDb[iDb].zName));
addModuleArgument(pTable, sqlite3StrDup(pTable->zName));
pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z;
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Creating a virtual table invokes the authorization callback twice.
** The first invocation, to obtain permission to INSERT a row into the
** sqlite_master table, has already been made by sqlite3StartTable().
** The second call, to obtain permission to create the table, is made now.
*/
if( pTable->azModuleArg ){
sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
pTable->azModuleArg[0], pParse->db->aDb[iDb].zName);
}
#endif
}
/*
** This routine takes the module argument that has been accumulating
** in pParse->zArg[] and appends it to the list of arguments on the
** virtual table currently under construction in pParse->pTable.
*/
static void addArgumentToVtab(Parse *pParse){
if( pParse->sArg.z && pParse->pNewTable ){
const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n;
addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n));
}
}
/*
** The parser calls this routine after the CREATE VIRTUAL TABLE statement
** has been completely parsed.
*/
void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
Table *pTab; /* The table being constructed */
sqlite3 *db; /* The database connection */
char *zModule; /* The module name of the table: USING modulename */
Module *pMod = 0;
addArgumentToVtab(pParse);
pParse->sArg.z = 0;
/* Lookup the module name. */
pTab = pParse->pNewTable;
if( pTab==0 ) return;
db = pParse->db;
if( pTab->nModuleArg<1 ) return;
zModule = pTab->azModuleArg[0];
pMod = (Module *)sqlite3HashFind(&db->aModule, zModule, strlen(zModule));
pTab->pMod = pMod;
/* If the CREATE VIRTUAL TABLE statement is being entered for the
** first time (in other words if the virtual table is actually being
** created now instead of just being read out of sqlite_master) then
** do additional initialization work and store the statement text
** in the sqlite_master table.
*/
if( !db->init.busy ){
char *zStmt;
char *zWhere;
int iDb;
Vdbe *v;
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */
if( pEnd ){
pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n;
}
zStmt = sqlite3MPrintf("CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
/* A slot for the record has already been allocated in the
** SQLITE_MASTER table. We just need to update that slot with all
** the information we've collected.
**
** The top of the stack is the rootpage allocated by sqlite3StartTable().
** This value is always 0 and is ignored, a virtual table does not have a
** rootpage. The next entry on the stack is the rowid of the record
** in the sqlite_master table.
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3NestedParse(pParse,
"UPDATE %Q.%s "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
"WHERE rowid=#1",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
pTab->zName,
pTab->zName,
zStmt
);
sqliteFree(zStmt);
v = sqlite3GetVdbe(pParse);
sqlite3ChangeCookie(db, v, iDb);
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
zWhere = sqlite3MPrintf("name='%q'", pTab->zName);
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC);
sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1);
}
/* If we are rereading the sqlite_master table create the in-memory
** record of the table. If the module has already been registered,
** also call the xConnect method here.
*/
else {
Table *pOld;
Schema *pSchema = pTab->pSchema;
const char *zName = pTab->zName;
int nName = strlen(zName) + 1;
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
if( pOld ){
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
return;
}
pParse->pNewTable = 0;
}
}
/*
** The parser calls this routine when it sees the first token
** of an argument to the module name in a CREATE VIRTUAL TABLE statement.
*/
void sqlite3VtabArgInit(Parse *pParse){
addArgumentToVtab(pParse);
pParse->sArg.z = 0;
pParse->sArg.n = 0;
}
/*
** The parser calls this routine for each token after the first token
** in an argument to the module name in a CREATE VIRTUAL TABLE statement.
*/
void sqlite3VtabArgExtend(Parse *pParse, Token *p){
Token *pArg = &pParse->sArg;
if( pArg->z==0 ){
pArg->z = p->z;
pArg->n = p->n;
}else{
assert(pArg->z < p->z);
pArg->n = (p->z + p->n - pArg->z);
}
}
/*
** Invoke a virtual table constructor (either xCreate or xConnect). The
** pointer to the function to invoke is passed as the fourth parameter
** to this procedure.
*/
static int vtabCallConstructor(
sqlite3 *db,
Table *pTab,
Module *pMod,
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
char **pzErr
){
int rc;
int rc2;
sqlite3_vtab *pVtab;
const char *const*azArg = (const char *const*)pTab->azModuleArg;
int nArg = pTab->nModuleArg;
char *zErr = 0;
char *zModuleName = sqlite3MPrintf("%s", pTab->zName);
assert( !db->pVTab );
assert( xConstruct );
db->pVTab = pTab;
rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK );
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab, &zErr);
rc2 = sqlite3SafetyOn(db);
pVtab = pTab->pVtab;
if( rc==SQLITE_OK && pVtab ){
pVtab->pModule = pMod->pModule;
pVtab->nRef = 1;
}
if( SQLITE_OK!=rc ){
if( zErr==0 ){
*pzErr = sqlite3MPrintf("vtable constructor failed: %s", zModuleName);
}else {
*pzErr = sqlite3MPrintf("%s", zErr);
sqlite3_free(zErr);
}
}else if( db->pVTab ){
const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(zFormat, pTab->zName);
rc = SQLITE_ERROR;
}
if( rc==SQLITE_OK ){
rc = rc2;
}
db->pVTab = 0;
sqliteFree(zModuleName);
return rc;
}
/*
** This function is invoked by the parser to call the xConnect() method
** of the virtual table pTab. If an error occurs, an error code is returned
** and an error left in pParse.
**
** This call is a no-op if table pTab is not a virtual table.
*/
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
Module *pMod;
int rc = SQLITE_OK;
if( !pTab || !pTab->isVirtual || pTab->pVtab ){
return SQLITE_OK;
}
pMod = pTab->pMod;
if( !pMod ){
const char *zModule = pTab->azModuleArg[0];
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
rc = SQLITE_ERROR;
} else {
char *zErr = 0;
sqlite3 *db = pParse->db;
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
}
sqliteFree(zErr);
}
return rc;
}
/*
** Add the virtual table pVtab to the array sqlite3.aVTrans[].
*/
static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
const int ARRAY_INCR = 5;
/* Grow the sqlite3.aVTrans array if required */
if( (db->nVTrans%ARRAY_INCR)==0 ){
sqlite3_vtab **aVTrans;
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
aVTrans = sqliteRealloc((void *)db->aVTrans, nBytes);
if( !aVTrans ){
return SQLITE_NOMEM;
}
memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR);
db->aVTrans = aVTrans;
}
/* Add pVtab to the end of sqlite3.aVTrans */
db->aVTrans[db->nVTrans++] = pVtab;
sqlite3VtabLock(pVtab);
return SQLITE_OK;
}
/*
** This function is invoked by the vdbe to call the xCreate method
** of the virtual table named zTab in database iDb.
**
** If an error occurs, *pzErr is set to point an an English language
** description of the error and an SQLITE_XXX error code is returned.
** In this case the caller must call sqliteFree() on *pzErr.
*/
int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
int rc = SQLITE_OK;
Table *pTab;
Module *pMod;
const char *zModule;
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
assert(pTab && pTab->isVirtual && !pTab->pVtab);
pMod = pTab->pMod;
zModule = pTab->azModuleArg[0];
/* If the module has been registered and includes a Create method,
** invoke it now. If the module has not been registered, return an
** error. Otherwise, do nothing.
*/
if( !pMod ){
*pzErr = sqlite3MPrintf("no such module: %s", zModule);
rc = SQLITE_ERROR;
}else{
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
}
if( rc==SQLITE_OK && pTab->pVtab ){
rc = addToVTrans(db, pTab->pVtab);
}
return rc;
}
/*
** This function is used to set the schema of a virtual table. It is only
** valid to call this function from within the xCreate() or xConnect() of a
** virtual table module.
*/
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
Parse sParse;
int rc = SQLITE_OK;
Table *pTab = db->pVTab;
char *zErr = 0;
if( !pTab ){
sqlite3Error(db, SQLITE_MISUSE, 0);
return SQLITE_MISUSE;
}
assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0);
memset(&sParse, 0, sizeof(Parse));
sParse.declareVtab = 1;
sParse.db = db;
if(
SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) &&
sParse.pNewTable &&
!sParse.pNewTable->pSelect &&
!sParse.pNewTable->isVirtual
){
pTab->aCol = sParse.pNewTable->aCol;
pTab->nCol = sParse.pNewTable->nCol;
sParse.pNewTable->nCol = 0;
sParse.pNewTable->aCol = 0;
} else {
sqlite3Error(db, SQLITE_ERROR, zErr);
sqliteFree(zErr);
rc = SQLITE_ERROR;
}
sParse.declareVtab = 0;
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
sqlite3DeleteTable(0, sParse.pNewTable);
sParse.pNewTable = 0;
db->pVTab = 0;
assert( (rc&0xff)==rc );
return rc;
}
/*
** This function is invoked by the vdbe to call the xDestroy method
** of the virtual table named zTab in database iDb. This occurs
** when a DROP TABLE is mentioned.
**
** This call is a no-op if zTab is not a virtual table.
*/
int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
{
int rc = SQLITE_OK;
Table *pTab;
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
assert(pTab);
if( pTab->pVtab ){
int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy;
rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK );
if( xDestroy ){
rc = xDestroy(pTab->pVtab);
}
sqlite3SafetyOn(db);
if( rc==SQLITE_OK ){
pTab->pVtab = 0;
}
}
return rc;
}
/*
** This function invokes either the xRollback or xCommit method
** of each of the virtual tables in the sqlite3.aVTrans array. The method
** called is identified by the second argument, "offset", which is
** the offset of the method to call in the sqlite3_module structure.
**
** The array is cleared after invoking the callbacks.
*/
static void callFinaliser(sqlite3 *db, int offset){
int i;
for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){
sqlite3_vtab *pVtab = db->aVTrans[i];
int (*x)(sqlite3_vtab *);
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
if( x ) x(pVtab);
sqlite3VtabUnlock(pVtab);
}
sqliteFree(db->aVTrans);
db->nVTrans = 0;
db->aVTrans = 0;
}
/*
** If argument rc2 is not SQLITE_OK, then return it and do nothing.
** Otherwise, invoke the xSync method of all virtual tables in the
** sqlite3.aVTrans array. Return the error code for the first error
** that occurs, or SQLITE_OK if all xSync operations are successful.
*/
int sqlite3VtabSync(sqlite3 *db, int rc2){
int i;
int rc = SQLITE_OK;
int rcsafety;
sqlite3_vtab **aVTrans = db->aVTrans;
if( rc2!=SQLITE_OK ) return rc2;
rc = sqlite3SafetyOff(db);
db->aVTrans = 0;
for(i=0; rc==SQLITE_OK && i<db->nVTrans && aVTrans[i]; i++){
sqlite3_vtab *pVtab = aVTrans[i];
int (*x)(sqlite3_vtab *);
x = pVtab->pModule->xSync;
if( x ){
rc = x(pVtab);
}
}
db->aVTrans = aVTrans;
rcsafety = sqlite3SafetyOn(db);
if( rc==SQLITE_OK ){
rc = rcsafety;
}
return rc;
}
/*
** Invoke the xRollback method of all virtual tables in the
** sqlite3.aVTrans array. Then clear the array itself.
*/
int sqlite3VtabRollback(sqlite3 *db){
callFinaliser(db, (int)(&((sqlite3_module *)0)->xRollback));
return SQLITE_OK;
}
/*
** Invoke the xCommit method of all virtual tables in the
** sqlite3.aVTrans array. Then clear the array itself.
*/
int sqlite3VtabCommit(sqlite3 *db){
callFinaliser(db, (int)(&((sqlite3_module *)0)->xCommit));
return SQLITE_OK;
}
/*
** If the virtual table pVtab supports the transaction interface
** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is
** not currently open, invoke the xBegin method now.
**
** If the xBegin call is successful, place the sqlite3_vtab pointer
** in the sqlite3.aVTrans array.
*/
int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
int rc = SQLITE_OK;
const sqlite3_module *pModule;
/* Special case: If db->aVTrans is NULL and db->nVTrans is greater
** than zero, then this function is being called from within a
** virtual module xSync() callback. It is illegal to write to
** virtual module tables in this case, so return SQLITE_LOCKED.
*/
if( 0==db->aVTrans && db->nVTrans>0 ){
return SQLITE_LOCKED;
}
if( !pVtab ){
return SQLITE_OK;
}
pModule = pVtab->pModule;
if( pModule->xBegin ){
int i;
/* If pVtab is already in the aVTrans array, return early */
for(i=0; (i<db->nVTrans) && 0!=db->aVTrans[i]; i++){
if( db->aVTrans[i]==pVtab ){
return SQLITE_OK;
}
}
/* Invoke the xBegin method */
rc = pModule->xBegin(pVtab);
if( rc!=SQLITE_OK ){
return rc;
}
rc = addToVTrans(db, pVtab);
}
return rc;
}
/*
** The first parameter (pDef) is a function implementation. The
** second parameter (pExpr) is the first argument to this function.
** If pExpr is a column in a virtual table, then let the virtual
** table implementation have an opportunity to overload the function.
**
** This routine is used to allow virtual table implementations to
** overload MATCH, LIKE, GLOB, and REGEXP operators.
**
** Return either the pDef argument (indicating no change) or a
** new FuncDef structure that is marked as ephemeral using the
** SQLITE_FUNC_EPHEM flag.
*/
FuncDef *sqlite3VtabOverloadFunction(
FuncDef *pDef, /* Function to possibly overload */
int nArg, /* Number of arguments to the function */
Expr *pExpr /* First argument to the function */
){
Table *pTab;
sqlite3_vtab *pVtab;
sqlite3_module *pMod;
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
void *pArg;
FuncDef *pNew;
int rc;
char *zLowerName;
unsigned char *z;
/* Check to see the left operand is a column in a virtual table */
if( pExpr==0 ) return pDef;
if( pExpr->op!=TK_COLUMN ) return pDef;
pTab = pExpr->pTab;
if( pTab==0 ) return pDef;
if( !pTab->isVirtual ) return pDef;
pVtab = pTab->pVtab;
assert( pVtab!=0 );
assert( pVtab->pModule!=0 );
pMod = (sqlite3_module *)pVtab->pModule;
if( pMod->xFindFunction==0 ) return pDef;
/* Call the xFuncFunction method on the virtual table implementation
** to see if the implementation wants to overload this function
*/
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;
}
/* Create a new ephemeral function definition for the overloaded
** function */
pNew = sqliteMalloc( sizeof(*pNew) + strlen(pDef->zName) );
if( pNew==0 ){
return pDef;
}
*pNew = *pDef;
strcpy(pNew->zName, pDef->zName);
pNew->xFunc = xFunc;
pNew->pUserData = pArg;
pNew->flags |= SQLITE_FUNC_EPHEM;
return pNew;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

File diff suppressed because it is too large Load Diff