mirror of
https://github.com/php/php-src.git
synced 2025-08-19 08:49:28 +02:00
Upgraded SQLite 3 to version 3.3.12
This commit is contained in:
parent
7aa2282124
commit
d35449bbfb
49 changed files with 5187 additions and 2911 deletions
1
NEWS
1
NEWS
|
@ -1,6 +1,7 @@
|
|||
PHP NEWS
|
||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
?? ??? 2007, PHP 5.2.2
|
||||
- Upgraded SQLite 3 to version 3.3.12 (Ilia)
|
||||
- Add --ri switch to CLI which allows to check extension information. (Marcus)
|
||||
- Fixed bug #39836 (SplObjectStorage empty after unserialize). (Marcus)
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.3.7
|
||||
3.3.12
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
** This function is used by SQL generated to implement the
|
||||
** 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
|
||||
** 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:
|
||||
**
|
||||
** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
|
||||
|
@ -78,10 +78,10 @@ static void renameTableFunc(
|
|||
}
|
||||
|
||||
#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
|
||||
** 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
|
||||
** TRIGGER, not CREATE INDEX and CREATE TABLE.
|
||||
*/
|
||||
|
|
|
@ -387,17 +387,13 @@ struct BtCursor {
|
|||
CellInfo info; /* A parse of the cell we are pointing at */
|
||||
u8 wrFlag; /* True if writable */
|
||||
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 */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
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
|
||||
** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur
|
||||
** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined.
|
||||
** Potential values for BtCursor.eState.
|
||||
**
|
||||
** CURSOR_VALID:
|
||||
** Cursor points to a valid entry. getPayload() etc. may be called.
|
||||
|
@ -425,7 +421,8 @@ struct BtCursor {
|
|||
*/
|
||||
#if SQLITE_TEST
|
||||
# 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
|
||||
# define TRACE(X)
|
||||
|
@ -434,7 +431,7 @@ int sqlite3_btree_trace=0; /* True to enable tracing */
|
|||
/*
|
||||
** 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.
|
||||
|
@ -509,105 +506,8 @@ struct BtLock {
|
|||
#define queryTableLock(a,b,c) SQLITE_OK
|
||||
#define lockTable(a,b,c) SQLITE_OK
|
||||
#define unlockAllTables(a)
|
||||
#define restoreOrClearCursorPosition(a,b) SQLITE_OK
|
||||
#define saveAllCursors(a,b,c) SQLITE_OK
|
||||
|
||||
#else
|
||||
|
||||
static void releasePage(MemPage *pPage);
|
||||
|
||||
/*
|
||||
** Save the current cursor position in the variables BtCursor.nKey
|
||||
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
|
||||
*/
|
||||
static int saveCursorPosition(BtCursor *pCur){
|
||||
int rc;
|
||||
|
||||
assert( CURSOR_VALID==pCur->eState );
|
||||
assert( 0==pCur->pKey );
|
||||
|
||||
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
|
||||
|
||||
/* If this is an intKey table, then the above call to BtreeKeySize()
|
||||
** stores the integer key in pCur->nKey. In this case this value is
|
||||
** all that is required. Otherwise, if pCur is not open on an intKey
|
||||
** table, then malloc space for and store the pCur->nKey bytes of key
|
||||
** data.
|
||||
*/
|
||||
if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
|
||||
void *pKey = sqliteMalloc(pCur->nKey);
|
||||
if( pKey ){
|
||||
rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->pKey = pKey;
|
||||
}else{
|
||||
sqliteFree(pKey);
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
assert( !pCur->pPage->intKey || !pCur->pKey );
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
releasePage(pCur->pPage);
|
||||
pCur->pPage = 0;
|
||||
pCur->eState = CURSOR_REQUIRESEEK;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Save the positions of all cursors except pExcept open on the table
|
||||
** with root-page iRoot. Usually, this is called just before cursor
|
||||
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
|
||||
*/
|
||||
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
|
||||
BtCursor *p;
|
||||
if( sqlite3ThreadDataReadOnly()->useSharedData ){
|
||||
for(p=pBt->pCursor; p; p=p->pNext){
|
||||
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
|
||||
p->eState==CURSOR_VALID ){
|
||||
int rc = saveCursorPosition(p);
|
||||
if( SQLITE_OK!=rc ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Restore the cursor to the position it was in (or as close to as possible)
|
||||
** when saveCursorPosition() was called. Note that this call deletes the
|
||||
** saved position info stored by saveCursorPosition(), so there can be
|
||||
** at most one effective restoreOrClearCursorPosition() call after each
|
||||
** saveCursorPosition().
|
||||
**
|
||||
** If the second argument argument - doSeek - is false, then instead of
|
||||
** returning the cursor to it's saved position, any saved position is deleted
|
||||
** and the cursor state set to CURSOR_INVALID.
|
||||
*/
|
||||
static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
|
||||
int rc = SQLITE_OK;
|
||||
assert( sqlite3ThreadDataReadOnly()->useSharedData );
|
||||
assert( pCur->eState==CURSOR_REQUIRESEEK );
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
if( doSeek ){
|
||||
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqliteFree(pCur->pKey);
|
||||
pCur->pKey = 0;
|
||||
assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define restoreOrClearCursorPosition(p,x) \
|
||||
(p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
|
||||
|
||||
/*
|
||||
** Query to see if btree handle p may obtain a lock of type eLock
|
||||
|
@ -747,6 +647,98 @@ static void unlockAllTables(Btree *p){
|
|||
}
|
||||
#endif /* SQLITE_OMIT_SHARED_CACHE */
|
||||
|
||||
static void releasePage(MemPage *pPage); /* Forward reference */
|
||||
|
||||
/*
|
||||
** Save the current cursor position in the variables BtCursor.nKey
|
||||
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
|
||||
*/
|
||||
static int saveCursorPosition(BtCursor *pCur){
|
||||
int rc;
|
||||
|
||||
assert( CURSOR_VALID==pCur->eState );
|
||||
assert( 0==pCur->pKey );
|
||||
|
||||
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
|
||||
|
||||
/* If this is an intKey table, then the above call to BtreeKeySize()
|
||||
** stores the integer key in pCur->nKey. In this case this value is
|
||||
** all that is required. Otherwise, if pCur is not open on an intKey
|
||||
** table, then malloc space for and store the pCur->nKey bytes of key
|
||||
** data.
|
||||
*/
|
||||
if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
|
||||
void *pKey = sqliteMalloc(pCur->nKey);
|
||||
if( pKey ){
|
||||
rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->pKey = pKey;
|
||||
}else{
|
||||
sqliteFree(pKey);
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
assert( !pCur->pPage->intKey || !pCur->pKey );
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
releasePage(pCur->pPage);
|
||||
pCur->pPage = 0;
|
||||
pCur->eState = CURSOR_REQUIRESEEK;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Save the positions of all cursors except pExcept open on the table
|
||||
** with root-page iRoot. Usually, this is called just before cursor
|
||||
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
|
||||
*/
|
||||
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
|
||||
BtCursor *p;
|
||||
for(p=pBt->pCursor; p; p=p->pNext){
|
||||
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
|
||||
p->eState==CURSOR_VALID ){
|
||||
int rc = saveCursorPosition(p);
|
||||
if( SQLITE_OK!=rc ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Restore the cursor to the position it was in (or as close to as possible)
|
||||
** when saveCursorPosition() was called. Note that this call deletes the
|
||||
** saved position info stored by saveCursorPosition(), so there can be
|
||||
** at most one effective restoreOrClearCursorPosition() call after each
|
||||
** saveCursorPosition().
|
||||
**
|
||||
** If the second argument argument - doSeek - is false, then instead of
|
||||
** returning the cursor to it's saved position, any saved position is deleted
|
||||
** and the cursor state set to CURSOR_INVALID.
|
||||
*/
|
||||
static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
|
||||
int rc = SQLITE_OK;
|
||||
assert( pCur->eState==CURSOR_REQUIRESEEK );
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
if( doSeek ){
|
||||
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqliteFree(pCur->pKey);
|
||||
pCur->pKey = 0;
|
||||
assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define restoreOrClearCursorPosition(p,x) \
|
||||
(p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
/*
|
||||
** These macros define the location of the pointer-map entry for a
|
||||
|
@ -1048,91 +1040,6 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){
|
|||
#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
|
||||
** of handle p (type Btree*) are internally consistent.
|
||||
*/
|
||||
|
@ -1439,7 +1346,6 @@ static int initPage(
|
|||
}
|
||||
|
||||
pPage->isInit = 1;
|
||||
pageIntegrity(pPage);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -1470,7 +1376,6 @@ static void zeroPage(MemPage *pPage, int flags){
|
|||
pPage->idxShift = 0;
|
||||
pPage->nCell = 0;
|
||||
pPage->isInit = 1;
|
||||
pageIntegrity(pPage);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1591,9 +1496,9 @@ int sqlite3BtreeOpen(
|
|||
*/
|
||||
#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
|
||||
#ifdef SQLITE_OMIT_MEMORYDB
|
||||
const int isMemdb = !zFilename;
|
||||
const int isMemdb = 0;
|
||||
#else
|
||||
const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1);
|
||||
const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -1645,8 +1550,13 @@ int sqlite3BtreeOpen(
|
|||
return SQLITE_NOMEM;
|
||||
}
|
||||
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( pBt->pPager ) sqlite3pager_close(pBt->pPager);
|
||||
if( pBt->pPager ){
|
||||
sqlite3pager_close(pBt->pPager);
|
||||
}
|
||||
sqliteFree(pBt);
|
||||
sqliteFree(p);
|
||||
*ppBtree = 0;
|
||||
|
@ -1659,7 +1569,6 @@ int sqlite3BtreeOpen(
|
|||
pBt->pCursor = 0;
|
||||
pBt->pPage1 = 0;
|
||||
pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager);
|
||||
sqlite3pager_read_fileheader(pBt->pPager, sizeof(zDbHeader), zDbHeader);
|
||||
pBt->pageSize = get2byte(&zDbHeader[16]);
|
||||
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|
||||
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
|
||||
|
@ -2022,13 +1931,15 @@ static int lockBtreeWithRetry(Btree *pRef){
|
|||
*/
|
||||
static void unlockBtreeIfUnused(BtShared *pBt){
|
||||
if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
|
||||
if( pBt->pPage1->aData==0 ){
|
||||
MemPage *pPage = pBt->pPage1;
|
||||
pPage->aData = &((u8*)pPage)[-pBt->pageSize];
|
||||
pPage->pBt = pBt;
|
||||
pPage->pgno = 1;
|
||||
if( sqlite3pager_refcount(pBt->pPager)>=1 ){
|
||||
if( pBt->pPage1->aData==0 ){
|
||||
MemPage *pPage = pBt->pPage1;
|
||||
pPage->aData = &((u8*)pPage)[-pBt->pageSize];
|
||||
pPage->pBt = pBt;
|
||||
pPage->pgno = 1;
|
||||
}
|
||||
releasePage(pBt->pPage1);
|
||||
}
|
||||
releasePage(pBt->pPage1);
|
||||
pBt->pPage1 = 0;
|
||||
pBt->inStmt = 0;
|
||||
}
|
||||
|
@ -2548,7 +2459,7 @@ static int countWriteCursors(BtShared *pBt){
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** Print debugging information about all cursors to standard output.
|
||||
*/
|
||||
|
@ -2778,7 +2689,7 @@ int sqlite3BtreeCursor(
|
|||
if( pBt->readOnly ){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
if( checkReadLocks(pBt, iTable, 0) ){
|
||||
if( checkReadLocks(p, iTable, 0) ){
|
||||
return SQLITE_LOCKED;
|
||||
}
|
||||
}
|
||||
|
@ -2980,7 +2891,6 @@ static int getPayload(
|
|||
assert( pCur->eState==CURSOR_VALID );
|
||||
pBt = pCur->pBtree->pBt;
|
||||
pPage = pCur->pPage;
|
||||
pageIntegrity(pPage);
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
getCellInfo(pCur);
|
||||
aPayload = pCur->info.pCell + pCur->info.nHeader;
|
||||
|
@ -3118,7 +3028,6 @@ static const unsigned char *fetchPayload(
|
|||
assert( pCur!=0 && pCur->pPage!=0 );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
pPage = pCur->pPage;
|
||||
pageIntegrity(pPage);
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
getCellInfo(pCur);
|
||||
aPayload = pCur->info.pCell;
|
||||
|
@ -3180,7 +3089,6 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
|||
assert( pCur->eState==CURSOR_VALID );
|
||||
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
|
||||
if( rc ) return rc;
|
||||
pageIntegrity(pNewPage);
|
||||
pNewPage->idxParent = pCur->idx;
|
||||
pOldPage = pCur->pPage;
|
||||
pOldPage->idxShift = 0;
|
||||
|
@ -3228,10 +3136,8 @@ static void moveToParent(BtCursor *pCur){
|
|||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
assert( !isRootPage(pPage) );
|
||||
pageIntegrity(pPage);
|
||||
pParent = pPage->pParent;
|
||||
assert( pParent!=0 );
|
||||
pageIntegrity(pParent);
|
||||
idxParent = pPage->idxParent;
|
||||
sqlite3pager_ref(pParent->aData);
|
||||
releasePage(pPage);
|
||||
|
@ -3261,7 +3167,6 @@ static int moveToRoot(BtCursor *pCur){
|
|||
return rc;
|
||||
}
|
||||
releasePage(pCur->pPage);
|
||||
pageIntegrity(pRoot);
|
||||
pCur->pPage = pRoot;
|
||||
}
|
||||
pCur->idx = 0;
|
||||
|
@ -3405,7 +3310,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
|
|||
assert( pCur->pPage->nCell==0 );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
for(;;){
|
||||
for(;;){
|
||||
int lwr, upr;
|
||||
Pgno chldPg;
|
||||
MemPage *pPage = pCur->pPage;
|
||||
|
@ -3415,7 +3320,6 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
|
|||
if( !pPage->intKey && pKey==0 ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
pageIntegrity(pPage);
|
||||
while( lwr<=upr ){
|
||||
void *pCellKey;
|
||||
i64 nCellKey;
|
||||
|
@ -3668,14 +3572,14 @@ static int allocatePage(
|
|||
int rc;
|
||||
int n; /* Number of pages on the freelist */
|
||||
int k; /* Number of leaves on the trunk of the freelist */
|
||||
MemPage *pTrunk = 0;
|
||||
MemPage *pPrevTrunk = 0;
|
||||
|
||||
pPage1 = pBt->pPage1;
|
||||
n = get4byte(&pPage1->aData[36]);
|
||||
if( n>0 ){
|
||||
/* There are pages on the freelist. Reuse one of those pages. */
|
||||
MemPage *pTrunk = 0;
|
||||
Pgno iTrunk;
|
||||
MemPage *pPrevTrunk = 0;
|
||||
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
|
||||
|
@ -3716,16 +3620,8 @@ static int allocatePage(
|
|||
}
|
||||
rc = getPage(pBt, iTrunk, &pTrunk);
|
||||
if( rc ){
|
||||
releasePage(pPrevTrunk);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* TODO: This should move to after the loop? */
|
||||
rc = sqlite3pager_write(pTrunk->aData);
|
||||
if( rc ){
|
||||
releasePage(pTrunk);
|
||||
releasePage(pPrevTrunk);
|
||||
return rc;
|
||||
pTrunk = 0;
|
||||
goto end_allocate_page;
|
||||
}
|
||||
|
||||
k = get4byte(&pTrunk->aData[4]);
|
||||
|
@ -3734,6 +3630,10 @@ static int allocatePage(
|
|||
** So extract the trunk page itself and use it as the newly
|
||||
** allocated page */
|
||||
assert( pPrevTrunk==0 );
|
||||
rc = sqlite3pager_write(pTrunk->aData);
|
||||
if( rc ){
|
||||
goto end_allocate_page;
|
||||
}
|
||||
*pPgno = iTrunk;
|
||||
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
|
||||
*ppPage = pTrunk;
|
||||
|
@ -3741,7 +3641,8 @@ static int allocatePage(
|
|||
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
|
||||
}else if( k>pBt->usableSize/4 - 8 ){
|
||||
/* 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
|
||||
}else if( searchList && nearby==iTrunk ){
|
||||
/* The list is being searched and this trunk page is the page
|
||||
|
@ -3750,6 +3651,10 @@ static int allocatePage(
|
|||
assert( *pPgno==iTrunk );
|
||||
*ppPage = pTrunk;
|
||||
searchList = 0;
|
||||
rc = sqlite3pager_write(pTrunk->aData);
|
||||
if( rc ){
|
||||
goto end_allocate_page;
|
||||
}
|
||||
if( k==0 ){
|
||||
if( !pPrevTrunk ){
|
||||
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
|
||||
|
@ -3765,26 +3670,26 @@ static int allocatePage(
|
|||
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
|
||||
rc = getPage(pBt, iNewTrunk, &pNewTrunk);
|
||||
if( rc!=SQLITE_OK ){
|
||||
releasePage(pTrunk);
|
||||
releasePage(pPrevTrunk);
|
||||
return rc;
|
||||
goto end_allocate_page;
|
||||
}
|
||||
rc = sqlite3pager_write(pNewTrunk->aData);
|
||||
if( rc!=SQLITE_OK ){
|
||||
releasePage(pNewTrunk);
|
||||
releasePage(pTrunk);
|
||||
releasePage(pPrevTrunk);
|
||||
return rc;
|
||||
goto end_allocate_page;
|
||||
}
|
||||
memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4);
|
||||
put4byte(&pNewTrunk->aData[4], k-1);
|
||||
memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4);
|
||||
releasePage(pNewTrunk);
|
||||
if( !pPrevTrunk ){
|
||||
put4byte(&pPage1->aData[32], iNewTrunk);
|
||||
}else{
|
||||
rc = sqlite3pager_write(pPrevTrunk->aData);
|
||||
if( rc ){
|
||||
goto end_allocate_page;
|
||||
}
|
||||
put4byte(&pPrevTrunk->aData[0], iNewTrunk);
|
||||
}
|
||||
releasePage(pNewTrunk);
|
||||
}
|
||||
pTrunk = 0;
|
||||
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
|
||||
|
@ -3794,6 +3699,10 @@ static int allocatePage(
|
|||
int closest;
|
||||
Pgno iPage;
|
||||
unsigned char *aData = pTrunk->aData;
|
||||
rc = sqlite3pager_write(aData);
|
||||
if( rc ){
|
||||
goto end_allocate_page;
|
||||
}
|
||||
if( nearby>0 ){
|
||||
int i, dist;
|
||||
closest = 0;
|
||||
|
@ -3837,8 +3746,8 @@ static int allocatePage(
|
|||
}
|
||||
}
|
||||
releasePage(pPrevTrunk);
|
||||
pPrevTrunk = 0;
|
||||
}while( searchList );
|
||||
releasePage(pTrunk);
|
||||
}else{
|
||||
/* There are no pages on the freelist, so create a new page at the
|
||||
** end of the file */
|
||||
|
@ -3867,6 +3776,10 @@ static int allocatePage(
|
|||
}
|
||||
|
||||
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
|
||||
end_allocate_page:
|
||||
releasePage(pTrunk);
|
||||
releasePage(pPrevTrunk);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -4267,7 +4180,6 @@ static int insertCell(
|
|||
put2byte(&data[ins], idx);
|
||||
put2byte(&data[hdr+3], pPage->nCell);
|
||||
pPage->idxShift = 1;
|
||||
pageIntegrity(pPage);
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pPage->pBt->autoVacuum ){
|
||||
/* 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
|
@ -5215,27 +5125,35 @@ static int balance(MemPage *pPage, int insert){
|
|||
|
||||
/*
|
||||
** This routine checks all cursors that point to table pgnoRoot.
|
||||
** If any of those cursors other than pExclude were opened with
|
||||
** wrFlag==0 then this routine returns SQLITE_LOCKED. If all
|
||||
** cursors that point to pgnoRoot were opened with wrFlag==1
|
||||
** then this routine returns SQLITE_OK.
|
||||
** If any of those cursors were opened with wrFlag==0 in a different
|
||||
** database connection (a database connection that shares the pager
|
||||
** cache with the current connection) and that other connection
|
||||
** is not in the ReadUncommmitted state, then this routine returns
|
||||
** SQLITE_LOCKED.
|
||||
**
|
||||
** In addition to checking for read-locks (where a read-lock
|
||||
** means a cursor opened with wrFlag==0) this routine also moves
|
||||
** all cursors other than pExclude so that they are pointing to the
|
||||
** first Cell on root page. This is necessary because an insert
|
||||
** all cursors write cursors so that they are pointing to the
|
||||
** 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
|
||||
** a page entirely and we do not want to leave any cursors
|
||||
** 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;
|
||||
BtShared *pBt = pBtree->pBt;
|
||||
sqlite3 *db = pBtree->pSqlite;
|
||||
for(p=pBt->pCursor; p; p=p->pNext){
|
||||
u32 flags = (p->pBtree->pSqlite ? p->pBtree->pSqlite->flags : 0);
|
||||
if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue;
|
||||
if( p->wrFlag==0 && flags&SQLITE_ReadUncommitted ) continue;
|
||||
if( p->wrFlag==0 ) return SQLITE_LOCKED;
|
||||
if( p->pPage->pgno!=p->pgnoRoot ){
|
||||
if( p==pExclude ) continue;
|
||||
if( p->eState!=CURSOR_VALID ) continue;
|
||||
if( p->pgnoRoot!=pgnoRoot ) continue;
|
||||
if( p->wrFlag==0 ){
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -5272,7 +5190,7 @@ int sqlite3BtreeInsert(
|
|||
if( !pCur->wrFlag ){
|
||||
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 */
|
||||
}
|
||||
|
||||
|
@ -5354,7 +5272,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
|||
if( !pCur->wrFlag ){
|
||||
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 */
|
||||
}
|
||||
|
||||
|
@ -5631,25 +5549,13 @@ cleardatabasepage_out:
|
|||
*/
|
||||
int sqlite3BtreeClearTable(Btree *p, int iTable){
|
||||
int rc;
|
||||
BtCursor *pCur;
|
||||
BtShared *pBt = p->pBt;
|
||||
sqlite3 *db = p->pSqlite;
|
||||
if( p->inTrans!=TRANS_WRITE ){
|
||||
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* If this connection is not in read-uncommitted mode and currently has
|
||||
** a read-cursor open on the table being cleared, return SQLITE_LOCKED.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
rc = checkReadLocks(p, iTable, 0);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Save the position of all cursors open on this table */
|
||||
|
@ -5969,7 +5875,7 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
|
|||
}
|
||||
#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
|
||||
** cursor is pointing to.
|
||||
|
@ -5997,14 +5903,12 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
|
|||
return rc;
|
||||
}
|
||||
|
||||
pageIntegrity(pPage);
|
||||
assert( pPage->isInit );
|
||||
getTempCursor(pCur, &tmpCur);
|
||||
while( upCnt-- ){
|
||||
moveToParent(&tmpCur);
|
||||
}
|
||||
pPage = tmpCur.pPage;
|
||||
pageIntegrity(pPage);
|
||||
aResult[0] = sqlite3pager_pagenumber(pPage->aData);
|
||||
assert( aResult[0]==pPage->pgno );
|
||||
aResult[1] = tmpCur.idx;
|
||||
|
@ -6054,10 +5958,12 @@ Pager *sqlite3BtreePager(Btree *p){
|
|||
typedef struct IntegrityCk IntegrityCk;
|
||||
struct IntegrityCk {
|
||||
BtShared *pBt; /* The tree being checked out */
|
||||
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
|
||||
int nPage; /* Number of pages in the database */
|
||||
int *anRef; /* Number of times each page is referenced */
|
||||
char *zErrMsg; /* An error message. NULL of no errors seen. */
|
||||
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
|
||||
int nPage; /* Number of pages in the database */
|
||||
int *anRef; /* Number of times each page is referenced */
|
||||
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
|
||||
|
@ -6072,6 +5978,9 @@ static void checkAppendMsg(
|
|||
){
|
||||
va_list ap;
|
||||
char *zMsg2;
|
||||
if( !pCheck->mxErr ) return;
|
||||
pCheck->mxErr--;
|
||||
pCheck->nErr++;
|
||||
va_start(ap, zFormat);
|
||||
zMsg2 = sqlite3VMPrintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
|
@ -6155,7 +6064,7 @@ static void checkList(
|
|||
int i;
|
||||
int expected = N;
|
||||
int iFirst = iPage;
|
||||
while( N-- > 0 ){
|
||||
while( N-- > 0 && pCheck->mxErr ){
|
||||
unsigned char *pOvfl;
|
||||
if( iPage<1 ){
|
||||
checkAppendMsg(pCheck, zContext,
|
||||
|
@ -6267,7 +6176,7 @@ static int checkTreePage(
|
|||
/* Check out all the cells.
|
||||
*/
|
||||
depth = 0;
|
||||
for(i=0; i<pPage->nCell; i++){
|
||||
for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
|
||||
u8 *pCell;
|
||||
int sz;
|
||||
CellInfo info;
|
||||
|
@ -6382,7 +6291,13 @@ static int checkTreePage(
|
|||
** and a pointer to that error message is returned. The calling function
|
||||
** 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 nRef;
|
||||
IntegrityCk sCheck;
|
||||
|
@ -6395,6 +6310,9 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
|
|||
sCheck.pBt = pBt;
|
||||
sCheck.pPager = pBt->pPager;
|
||||
sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager);
|
||||
sCheck.mxErr = mxErr;
|
||||
sCheck.nErr = 0;
|
||||
*pnErr = 0;
|
||||
if( sCheck.nPage==0 ){
|
||||
unlockBtreeIfUnused(pBt);
|
||||
return 0;
|
||||
|
@ -6402,6 +6320,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
|
|||
sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
|
||||
if( !sCheck.anRef ){
|
||||
unlockBtreeIfUnused(pBt);
|
||||
*pnErr = 1;
|
||||
return sqlite3MPrintf("Unable to malloc %d bytes",
|
||||
(sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
|
||||
}
|
||||
|
@ -6419,7 +6338,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
|
|||
|
||||
/* Check all the tables.
|
||||
*/
|
||||
for(i=0; i<nRoot; i++){
|
||||
for(i=0; i<nRoot && sCheck.mxErr; i++){
|
||||
if( aRoot[i]==0 ) continue;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum && aRoot[i]>1 ){
|
||||
|
@ -6431,7 +6350,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
|
|||
|
||||
/* Make sure every page in the file is referenced
|
||||
*/
|
||||
for(i=1; i<=sCheck.nPage; i++){
|
||||
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
if( sCheck.anRef[i]==0 ){
|
||||
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
|
||||
|
@ -6464,6 +6383,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
|
|||
/* Clean up and report errors.
|
||||
*/
|
||||
sqliteFree(sCheck.anRef);
|
||||
*pnErr = sCheck.nErr;
|
||||
return sCheck.zErrMsg;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
|
@ -6522,7 +6442,6 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
|||
rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
|
||||
if( rc ) break;
|
||||
rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
|
||||
if( rc ) break;
|
||||
sqlite3pager_unref(pPage);
|
||||
}
|
||||
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
|
||||
|
|
|
@ -131,7 +131,7 @@ const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
|
|||
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
|
||||
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*);
|
||||
|
||||
|
||||
|
|
|
@ -1077,8 +1077,12 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
|
|||
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
|
||||
pCol->zName);
|
||||
}else{
|
||||
Expr *pCopy;
|
||||
sqlite3ExprDelete(pCol->pDflt);
|
||||
pCol->pDflt = sqlite3ExprDup(pExpr);
|
||||
pCol->pDflt = pCopy = sqlite3ExprDup(pExpr);
|
||||
if( pCopy ){
|
||||
sqlite3TokenCopy(&pCopy->span, &pExpr->span);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3ExprDelete(pExpr);
|
||||
|
@ -1586,7 +1590,8 @@ void sqlite3CreateView(
|
|||
Token *pName1, /* 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 */
|
||||
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;
|
||||
int n;
|
||||
|
@ -1601,7 +1606,7 @@ void sqlite3CreateView(
|
|||
sqlite3SelectDelete(pSelect);
|
||||
return;
|
||||
}
|
||||
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, 0);
|
||||
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
|
||||
p = pParse->pNewTable;
|
||||
if( p==0 || pParse->nErr ){
|
||||
sqlite3SelectDelete(pSelect);
|
||||
|
@ -2935,15 +2940,6 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an alias to the last identifier on the given identifier list.
|
||||
*/
|
||||
void sqlite3SrcListAddAlias(SrcList *pList, Token *pToken){
|
||||
if( pList && pList->nSrc>0 ){
|
||||
pList->a[pList->nSrc-1].zAlias = sqlite3NameFromToken(pToken);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete an entire SrcList including all its substructure.
|
||||
*/
|
||||
|
@ -2963,6 +2959,74 @@ void sqlite3SrcListDelete(SrcList *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
|
||||
*/
|
||||
|
|
|
@ -237,11 +237,11 @@ static void computeJD(DateTime *p){
|
|||
X2 = 30.6001*(M+1);
|
||||
p->rJD = X1 + X2 + D + B - 1524.5;
|
||||
p->validJD = 1;
|
||||
p->validYMD = 0;
|
||||
if( p->validHMS ){
|
||||
p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
|
||||
if( p->validTZ ){
|
||||
p->rJD -= p->tz*60/86400.0;
|
||||
p->validYMD = 0;
|
||||
p->validHMS = 0;
|
||||
p->validTZ = 0;
|
||||
}
|
||||
|
@ -360,6 +360,7 @@ static void computeYMD(DateTime *p){
|
|||
static void computeHMS(DateTime *p){
|
||||
int Z, s;
|
||||
if( p->validHMS ) return;
|
||||
computeJD(p);
|
||||
Z = p->rJD + 0.5;
|
||||
s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
|
||||
p->s = 0.001*s;
|
||||
|
@ -415,8 +416,7 @@ static double localtimeOffset(DateTime *p){
|
|||
computeJD(&x);
|
||||
t = (x.rJD-2440587.5)*86400.0 + 0.5;
|
||||
sqlite3OsEnterMutex();
|
||||
pTm = php_localtime_r
|
||||
(&t, &tmbuf);
|
||||
pTm = php_localtime_r(&t, &tmbuf);
|
||||
y.Y = pTm->tm_year + 1900;
|
||||
y.M = pTm->tm_mon + 1;
|
||||
y.D = pTm->tm_mday;
|
||||
|
@ -585,7 +585,7 @@ static int parseModifier(const char *zMod, DateTime *p){
|
|||
if( z[0]=='-' ) tx.rJD = -tx.rJD;
|
||||
computeJD(p);
|
||||
clearYMD_HMS_TZ(p);
|
||||
p->rJD += tx.rJD;
|
||||
p->rJD += tx.rJD;
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -813,9 +813,9 @@ static void strftimeFunc(
|
|||
switch( zFmt[i] ){
|
||||
case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break;
|
||||
case 'f': {
|
||||
int s = x.s;
|
||||
int ms = (x.s - s)*1000.0;
|
||||
sprintf(&z[j],"%02d.%03d",s,ms);
|
||||
double s = x.s;
|
||||
if( s>59.999 ) s = 59.999;
|
||||
sqlite3_snprintf(7, &z[j],"%02.3f", s);
|
||||
j += strlen(&z[j]);
|
||||
break;
|
||||
}
|
||||
|
@ -828,7 +828,7 @@ static void strftimeFunc(
|
|||
y.M = 1;
|
||||
y.D = 1;
|
||||
computeJD(&y);
|
||||
nDay = x.rJD - y.rJD;
|
||||
nDay = x.rJD - y.rJD + 0.5;
|
||||
if( zFmt[i]=='W' ){
|
||||
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
|
||||
wd = ((int)(x.rJD+0.5)) % 7;
|
||||
|
@ -848,7 +848,7 @@ static void strftimeFunc(
|
|||
j += strlen(&z[j]);
|
||||
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 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
|
||||
case '%': z[j++] = '%'; break;
|
||||
|
@ -948,9 +948,21 @@ static void currentTimeFunc(
|
|||
}
|
||||
#endif
|
||||
|
||||
sqlite3OsEnterMutex();
|
||||
strftime(zBuf, 20, zFormat, gmtime(&t));
|
||||
sqlite3OsLeaveMutex();
|
||||
#ifdef HAVE_GMTIME_R
|
||||
{
|
||||
struct tm sNow;
|
||||
gmtime_r(&t, &sNow);
|
||||
strftime(zBuf, 20, zFormat, &sNow);
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct tm *pTm;
|
||||
sqlite3OsEnterMutex();
|
||||
pTm = gmtime(&t);
|
||||
strftime(zBuf, 20, zFormat, pTm);
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
|
|
@ -891,22 +891,23 @@ static int lookupName(
|
|||
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
||||
pExpr->affinity = pTab->aCol[j].affinity;
|
||||
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
||||
if( pItem->jointype & JT_NATURAL ){
|
||||
/* If this match occurred in the left table of a natural join,
|
||||
** then skip the right table to avoid a duplicate match */
|
||||
pItem++;
|
||||
i++;
|
||||
}
|
||||
if( (pUsing = pItem->pUsing)!=0 ){
|
||||
/* 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
|
||||
** to avoid a duplicate match there. */
|
||||
int k;
|
||||
for(k=0; k<pUsing->nId; k++){
|
||||
if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
|
||||
pItem++;
|
||||
i++;
|
||||
break;
|
||||
if( i<pSrcList->nSrc-1 ){
|
||||
if( pItem[1].jointype & JT_NATURAL ){
|
||||
/* If this match occurred in the left table of a natural join,
|
||||
** then skip the right table to avoid a duplicate match */
|
||||
pItem++;
|
||||
i++;
|
||||
}else if( (pUsing = pItem[1].pUsing)!=0 ){
|
||||
/* 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
|
||||
** to avoid a duplicate match there. */
|
||||
int k;
|
||||
for(k=0; k<pUsing->nId; k++){
|
||||
if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
|
||||
pItem++;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1161,6 +1162,7 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
|
|||
int wrong_num_args = 0; /* True if wrong number of arguments */
|
||||
int is_agg = 0; /* True if is an aggregate function */
|
||||
int i;
|
||||
int auth; /* Authorization to use the function */
|
||||
int nId; /* Number of characters in function name */
|
||||
const char *zId; /* The function name. */
|
||||
FuncDef *pDef; /* Information about the function */
|
||||
|
@ -1179,6 +1181,20 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
|
|||
}else{
|
||||
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 ){
|
||||
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
|
||||
pNC->nErr++;
|
||||
|
@ -2192,6 +2208,7 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
|
|||
|
||||
|
||||
switch( pExpr->op ){
|
||||
case TK_AGG_COLUMN:
|
||||
case TK_COLUMN: {
|
||||
/* Check to see if the column is in one of the tables in the FROM
|
||||
** clause of the aggregate query */
|
||||
|
|
|
@ -547,19 +547,6 @@ static void versionFunc(
|
|||
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
|
||||
}
|
||||
|
||||
/*
|
||||
** The MATCH() function is unimplemented. If anybody tries to use it,
|
||||
** return an error.
|
||||
*/
|
||||
static void matchStub(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
static const char zErr[] = "MATCH is not implemented";
|
||||
sqlite3_result_error(context, zErr, sizeof(zErr)-1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** EXPERIMENTAL - This is not an official function. The interface may
|
||||
|
@ -654,14 +641,20 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
|
|||
};
|
||||
assert( argc==1 );
|
||||
zIn = (u8*)sqlite3_value_text(argv[0]);
|
||||
if( zIn==0 ) zIn = "";
|
||||
if( zIn==0 ) zIn = (u8*)"";
|
||||
for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
|
||||
if( zIn[i] ){
|
||||
u8 prevcode = iCode[zIn[i]&0x7f];
|
||||
zResult[0] = toupper(zIn[i]);
|
||||
for(j=1; j<4 && zIn[i]; i++){
|
||||
int code = iCode[zIn[i]&0x7f];
|
||||
if( code>0 ){
|
||||
zResult[j++] = code + '0';
|
||||
if( code!=prevcode ){
|
||||
prevcode = code;
|
||||
zResult[j++] = code + '0';
|
||||
}
|
||||
}else{
|
||||
prevcode = 0;
|
||||
}
|
||||
}
|
||||
while( j<4 ){
|
||||
|
@ -1036,7 +1029,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
{ "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
|
||||
{ "changes", 0, 1, SQLITE_UTF8, 0, changes },
|
||||
{ "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
|
||||
{ "match", 2, 0, SQLITE_UTF8, 0, matchStub },
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
|
||||
#endif
|
||||
|
@ -1109,6 +1101,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
}
|
||||
}
|
||||
sqlite3RegisterDateTimeFunctions(db);
|
||||
sqlite3_overload_function(db, "MATCH", 2);
|
||||
#ifdef SQLITE_SSE
|
||||
(void)sqlite3SseFunctions(db);
|
||||
#endif
|
||||
|
|
|
@ -387,11 +387,9 @@ void sqlite3Insert(
|
|||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
assert( pList!=0 );
|
||||
srcTab = -1;
|
||||
useTempTable = 0;
|
||||
assert( pList );
|
||||
nColumn = pList->nExpr;
|
||||
nColumn = pList ? pList->nExpr : 0;
|
||||
for(i=0; i<nColumn; i++){
|
||||
if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){
|
||||
goto insert_cleanup;
|
||||
|
@ -402,7 +400,7 @@ void sqlite3Insert(
|
|||
/* Make sure the number of columns in the source data matches the number
|
||||
** of columns to be inserted into the table.
|
||||
*/
|
||||
if( pColumn==0 && nColumn!=pTab->nCol ){
|
||||
if( pColumn==0 && nColumn && nColumn!=pTab->nCol ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"table %S has %d columns but %d values were supplied",
|
||||
pTabList, 0, pTab->nCol, nColumn);
|
||||
|
@ -455,7 +453,7 @@ void sqlite3Insert(
|
|||
** key, the set the keyColumn variable to the primary key column index
|
||||
** in the original table definition.
|
||||
*/
|
||||
if( pColumn==0 ){
|
||||
if( pColumn==0 && nColumn>0 ){
|
||||
keyColumn = pTab->iPKey;
|
||||
}
|
||||
|
||||
|
@ -618,12 +616,12 @@ void sqlite3Insert(
|
|||
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);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
|
||||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j+IsVirtual(pTab), 1);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pList->a[j].pExpr);
|
||||
}
|
||||
|
|
|
@ -131,5 +131,6 @@ exec_out:
|
|||
*pzErrMsg = 0;
|
||||
}
|
||||
|
||||
assert( (rc&db->errMask)==rc );
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#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>
|
||||
|
||||
|
@ -74,6 +75,20 @@
|
|||
# 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
|
||||
|
@ -89,7 +104,7 @@
|
|||
** also check to make sure that the pointer to the function is
|
||||
** not NULL before calling it.
|
||||
*/
|
||||
const sqlite3_api_routines sqlite3_api = {
|
||||
const sqlite3_api_routines sqlite3_apis = {
|
||||
sqlite3_aggregate_context,
|
||||
sqlite3_aggregate_count,
|
||||
sqlite3_bind_blob,
|
||||
|
@ -153,7 +168,7 @@ const sqlite3_api_routines sqlite3_api = {
|
|||
sqlite3_get_autocommit,
|
||||
sqlite3_get_auxdata,
|
||||
sqlite3_get_table,
|
||||
sqlite3_global_recover,
|
||||
0, /* Was sqlite3_global_recover(), but that function is deprecated */
|
||||
sqlite3_interrupt,
|
||||
sqlite3_last_insert_rowid,
|
||||
sqlite3_libversion,
|
||||
|
@ -213,30 +228,9 @@ const sqlite3_api_routines sqlite3_api = {
|
|||
** a library that is new enough to support that API.
|
||||
*************************************************************************
|
||||
*/
|
||||
sqlite3_overload_function,
|
||||
};
|
||||
|
||||
/*
|
||||
** The windows implementation of shared-library loaders
|
||||
*/
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# include <windows.h>
|
||||
# define SQLITE_LIBRARY_TYPE HANDLE
|
||||
# define SQLITE_OPEN_LIBRARY(A) LoadLibrary(A)
|
||||
# define SQLITE_FIND_SYMBOL(A,B) GetProcAddress(A,B)
|
||||
# define SQLITE_CLOSE_LIBRARY(A) FreeLibrary(A)
|
||||
#endif /* windows */
|
||||
|
||||
/*
|
||||
** The unix implementation of shared-library loaders
|
||||
*/
|
||||
#if defined(HAVE_DLOPEN) && !defined(SQLITE_LIBRARY_TYPE)
|
||||
# include <dlfcn.h>
|
||||
# define SQLITE_LIBRARY_TYPE void*
|
||||
# define SQLITE_OPEN_LIBRARY(A) dlopen(A, RTLD_NOW | RTLD_GLOBAL)
|
||||
# define SQLITE_FIND_SYMBOL(A,B) dlsym(A,B)
|
||||
# define SQLITE_CLOSE_LIBRARY(A) dlclose(A)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Attempt to load an SQLite extension library contained in the file
|
||||
** zFile. The entry point is zProc. zProc may be 0 in which case a
|
||||
|
@ -255,11 +249,10 @@ int sqlite3_load_extension(
|
|||
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
|
||||
char **pzErrMsg /* Put error message here if not 0 */
|
||||
){
|
||||
#ifdef SQLITE_LIBRARY_TYPE
|
||||
SQLITE_LIBRARY_TYPE handle;
|
||||
void *handle;
|
||||
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
char *zErrmsg = 0;
|
||||
SQLITE_LIBRARY_TYPE *aHandle;
|
||||
void **aHandle;
|
||||
|
||||
/* Ticket #1863. To avoid a creating security problems for older
|
||||
** applications that relink against newer versions of SQLite, the
|
||||
|
@ -278,7 +271,7 @@ int sqlite3_load_extension(
|
|||
zProc = "sqlite3_extension_init";
|
||||
}
|
||||
|
||||
handle = SQLITE_OPEN_LIBRARY(zFile);
|
||||
handle = sqlite3OsDlopen(zFile);
|
||||
if( handle==0 ){
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile);
|
||||
|
@ -286,20 +279,20 @@ int sqlite3_load_extension(
|
|||
return SQLITE_ERROR;
|
||||
}
|
||||
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
|
||||
SQLITE_FIND_SYMBOL(handle, zProc);
|
||||
sqlite3OsDlsym(handle, zProc);
|
||||
if( xInit==0 ){
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("no entry point [%s] in shared library [%s]",
|
||||
zProc, zFile);
|
||||
}
|
||||
SQLITE_CLOSE_LIBRARY(handle);
|
||||
sqlite3OsDlclose(handle);
|
||||
return SQLITE_ERROR;
|
||||
}else if( xInit(db, &zErrmsg, &sqlite3_api) ){
|
||||
}else if( xInit(db, &zErrmsg, &sqlite3_apis) ){
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
|
||||
}
|
||||
sqlite3_free(zErrmsg);
|
||||
SQLITE_CLOSE_LIBRARY(handle);
|
||||
sqlite3OsDlclose(handle);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -315,14 +308,8 @@ int sqlite3_load_extension(
|
|||
sqliteFree(db->aExtension);
|
||||
db->aExtension = aHandle;
|
||||
|
||||
((SQLITE_LIBRARY_TYPE*)db->aExtension)[db->nExtension-1] = handle;
|
||||
db->aExtension[db->nExtension-1] = handle;
|
||||
return SQLITE_OK;
|
||||
#else
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("extension loading is disabled");
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -330,13 +317,11 @@ int sqlite3_load_extension(
|
|||
** to clean up loaded extensions
|
||||
*/
|
||||
void sqlite3CloseExtensions(sqlite3 *db){
|
||||
#ifdef SQLITE_LIBRARY_TYPE
|
||||
int i;
|
||||
for(i=0; i<db->nExtension; i++){
|
||||
SQLITE_CLOSE_LIBRARY(((SQLITE_LIBRARY_TYPE*)db->aExtension)[i]);
|
||||
sqlite3OsDlclose(db->aExtension[i]);
|
||||
}
|
||||
sqliteFree(db->aExtension);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -352,4 +337,86 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
|
|||
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 */
|
||||
|
|
|
@ -223,7 +223,7 @@ void sqlite3RollbackAll(sqlite3 *db){
|
|||
*/
|
||||
const char *sqlite3ErrStr(int rc){
|
||||
const char *z;
|
||||
switch( rc ){
|
||||
switch( rc & 0xff ){
|
||||
case SQLITE_ROW:
|
||||
case SQLITE_DONE:
|
||||
case SQLITE_OK: z = "not an error"; break;
|
||||
|
@ -541,6 +541,32 @@ int sqlite3_create_function16(
|
|||
}
|
||||
#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
|
||||
/*
|
||||
** Register a trace function. The pArg from the previously registered trace
|
||||
|
@ -763,7 +789,7 @@ int sqlite3_errcode(sqlite3 *db){
|
|||
if( sqlite3SafetyCheck(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
return db->errCode;
|
||||
return db->errCode & db->errMask;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -841,6 +867,7 @@ static int openDatabase(
|
|||
/* Allocate the sqlite data structure */
|
||||
db = sqliteMalloc( sizeof(sqlite3) );
|
||||
if( db==0 ) goto opendb_out;
|
||||
db->errMask = 0xff;
|
||||
db->priorNewRowid = 0;
|
||||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
db->nDb = 2;
|
||||
|
@ -907,11 +934,30 @@ static int openDatabase(
|
|||
** is accessed.
|
||||
*/
|
||||
if( !sqlite3MallocFailed() ){
|
||||
sqlite3RegisterBuiltinFunctions(db);
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
sqlite3RegisterBuiltinFunctions(db);
|
||||
}
|
||||
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:
|
||||
if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
|
||||
sqlite3_close(db);
|
||||
|
@ -999,6 +1045,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
|
|||
}else{
|
||||
rc = sqlite3VdbeReset((Vdbe*)pStmt);
|
||||
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
|
||||
assert( (rc & (sqlite3_db_handle(pStmt)->errMask))==rc );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -1285,3 +1332,11 @@ int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -2,136 +2,148 @@
|
|||
/* See the mkopcodec.awk script for details. */
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
const char *const sqlite3OpcodeNames[] = { "?",
|
||||
/* 1 */ "MemLoad",
|
||||
/* 2 */ "Column",
|
||||
/* 3 */ "SetCookie",
|
||||
/* 4 */ "IfMemPos",
|
||||
/* 5 */ "MoveGt",
|
||||
/* 6 */ "AggFocus",
|
||||
/* 7 */ "RowKey",
|
||||
/* 8 */ "IdxRecno",
|
||||
/* 9 */ "AggNext",
|
||||
/* 10 */ "OpenWrite",
|
||||
/* 11 */ "If",
|
||||
/* 12 */ "PutStrKey",
|
||||
/* 13 */ "Pop",
|
||||
/* 14 */ "SortPut",
|
||||
/* 15 */ "AggContextPush",
|
||||
/* 16 */ "CollSeq",
|
||||
/* 17 */ "OpenRead",
|
||||
/* 18 */ "Expire",
|
||||
/* 19 */ "SortReset",
|
||||
/* 20 */ "AutoCommit",
|
||||
/* 21 */ "Sort",
|
||||
/* 22 */ "ListRewind",
|
||||
/* 23 */ "IntegrityCk",
|
||||
/* 24 */ "Function",
|
||||
/* 25 */ "Noop",
|
||||
/* 26 */ "Return",
|
||||
/* 27 */ "Variable",
|
||||
/* 28 */ "String",
|
||||
/* 29 */ "ParseSchema",
|
||||
/* 30 */ "PutIntKey",
|
||||
/* 31 */ "AggFunc",
|
||||
/* 32 */ "Close",
|
||||
/* 33 */ "ListWrite",
|
||||
/* 34 */ "CreateIndex",
|
||||
/* 35 */ "IsUnique",
|
||||
/* 36 */ "IdxIsNull",
|
||||
/* 37 */ "NotFound",
|
||||
/* 38 */ "MustBeInt",
|
||||
/* 39 */ "Halt",
|
||||
/* 40 */ "IdxLT",
|
||||
/* 41 */ "AddImm",
|
||||
/* 42 */ "Statement",
|
||||
/* 43 */ "RowData",
|
||||
/* 44 */ "MemMax",
|
||||
/* 45 */ "Push",
|
||||
/* 46 */ "KeyAsData",
|
||||
/* 47 */ "NotExists",
|
||||
/* 48 */ "OpenTemp",
|
||||
/* 49 */ "MemIncr",
|
||||
/* 50 */ "Gosub",
|
||||
/* 51 */ "AggSet",
|
||||
/* 52 */ "Integer",
|
||||
/* 53 */ "SortNext",
|
||||
/* 54 */ "Prev",
|
||||
/* 55 */ "CreateTable",
|
||||
/* 56 */ "Last",
|
||||
/* 57 */ "ResetCount",
|
||||
/* 58 */ "Callback",
|
||||
/* 59 */ "ContextPush",
|
||||
/* 60 */ "DropTrigger",
|
||||
/* 61 */ "DropIndex",
|
||||
/* 62 */ "FullKey",
|
||||
/* 63 */ "IdxGE",
|
||||
/* 64 */ "Or",
|
||||
/* 65 */ "And",
|
||||
/* 66 */ "Not",
|
||||
/* 67 */ "IdxDelete",
|
||||
/* 68 */ "Vacuum",
|
||||
/* 69 */ "MoveLe",
|
||||
/* 70 */ "IsNull",
|
||||
/* 71 */ "NotNull",
|
||||
/* 72 */ "Ne",
|
||||
/* 73 */ "Eq",
|
||||
/* 74 */ "Gt",
|
||||
/* 75 */ "Le",
|
||||
/* 76 */ "Lt",
|
||||
/* 77 */ "Ge",
|
||||
/* 78 */ "IfNot",
|
||||
/* 79 */ "BitAnd",
|
||||
/* 80 */ "BitOr",
|
||||
/* 81 */ "ShiftLeft",
|
||||
/* 82 */ "ShiftRight",
|
||||
/* 83 */ "Add",
|
||||
/* 84 */ "Subtract",
|
||||
/* 85 */ "Multiply",
|
||||
/* 86 */ "Divide",
|
||||
/* 87 */ "Remainder",
|
||||
/* 88 */ "Concat",
|
||||
/* 89 */ "Negative",
|
||||
/* 90 */ "DropTable",
|
||||
/* 91 */ "BitNot",
|
||||
/* 92 */ "String8",
|
||||
/* 93 */ "MakeRecord",
|
||||
/* 94 */ "Delete",
|
||||
/* 95 */ "AggContextPop",
|
||||
/* 96 */ "ListRead",
|
||||
/* 97 */ "ListReset",
|
||||
/* 98 */ "Dup",
|
||||
/* 99 */ "Goto",
|
||||
/* 100 */ "Clear",
|
||||
/* 101 */ "IdxGT",
|
||||
/* 102 */ "MoveLt",
|
||||
/* 103 */ "VerifyCookie",
|
||||
/* 104 */ "Pull",
|
||||
/* 105 */ "SetNumColumns",
|
||||
/* 106 */ "AbsValue",
|
||||
/* 107 */ "Transaction",
|
||||
/* 108 */ "AggGet",
|
||||
/* 109 */ "ContextPop",
|
||||
/* 110 */ "Next",
|
||||
/* 111 */ "AggInit",
|
||||
/* 112 */ "Distinct",
|
||||
/* 113 */ "NewRecno",
|
||||
/* 114 */ "AggReset",
|
||||
/* 115 */ "Destroy",
|
||||
/* 116 */ "ReadCookie",
|
||||
/* 117 */ "ForceInt",
|
||||
/* 118 */ "Recno",
|
||||
/* 119 */ "OpenPseudo",
|
||||
/* 120 */ "Blob",
|
||||
/* 121 */ "MemStore",
|
||||
/* 122 */ "Rewind",
|
||||
/* 123 */ "MoveGe",
|
||||
/* 124 */ "IdxPut",
|
||||
/* 125 */ "Found",
|
||||
/* 126 */ "NullRow",
|
||||
/* 127 */ "NotUsed_127",
|
||||
/* 128 */ "NotUsed_128",
|
||||
/* 129 */ "NotUsed_129",
|
||||
/* 130 */ "Real",
|
||||
/* 131 */ "HexBlob",
|
||||
/* 1 */ "NotExists",
|
||||
/* 2 */ "Dup",
|
||||
/* 3 */ "MoveLt",
|
||||
/* 4 */ "VCreate",
|
||||
/* 5 */ "DropTrigger",
|
||||
/* 6 */ "OpenPseudo",
|
||||
/* 7 */ "MemInt",
|
||||
/* 8 */ "IntegrityCk",
|
||||
/* 9 */ "RowKey",
|
||||
/* 10 */ "LoadAnalysis",
|
||||
/* 11 */ "IdxGT",
|
||||
/* 12 */ "Last",
|
||||
/* 13 */ "MemLoad",
|
||||
/* 14 */ "SetCookie",
|
||||
/* 15 */ "Sequence",
|
||||
/* 16 */ "Not",
|
||||
/* 17 */ "Pull",
|
||||
/* 18 */ "VUpdate",
|
||||
/* 19 */ "VColumn",
|
||||
/* 20 */ "DropTable",
|
||||
/* 21 */ "MemStore",
|
||||
/* 22 */ "ContextPush",
|
||||
/* 23 */ "Rowid",
|
||||
/* 24 */ "VFilter",
|
||||
/* 25 */ "NullRow",
|
||||
/* 26 */ "Noop",
|
||||
/* 27 */ "VRowid",
|
||||
/* 28 */ "ParseSchema",
|
||||
/* 29 */ "Statement",
|
||||
/* 30 */ "CollSeq",
|
||||
/* 31 */ "ContextPop",
|
||||
/* 32 */ "MemIncr",
|
||||
/* 33 */ "MoveGe",
|
||||
/* 34 */ "If",
|
||||
/* 35 */ "IfNot",
|
||||
/* 36 */ "Destroy",
|
||||
/* 37 */ "Distinct",
|
||||
/* 38 */ "CreateIndex",
|
||||
/* 39 */ "SetNumColumns",
|
||||
/* 40 */ "ResetCount",
|
||||
/* 41 */ "MakeIdxRec",
|
||||
/* 42 */ "Goto",
|
||||
/* 43 */ "IdxDelete",
|
||||
/* 44 */ "MemMove",
|
||||
/* 45 */ "Found",
|
||||
/* 46 */ "MoveGt",
|
||||
/* 47 */ "IfMemZero",
|
||||
/* 48 */ "MustBeInt",
|
||||
/* 49 */ "Prev",
|
||||
/* 50 */ "MemNull",
|
||||
/* 51 */ "AutoCommit",
|
||||
/* 52 */ "String",
|
||||
/* 53 */ "FifoWrite",
|
||||
/* 54 */ "Return",
|
||||
/* 55 */ "Callback",
|
||||
/* 56 */ "AddImm",
|
||||
/* 57 */ "Function",
|
||||
/* 58 */ "NewRowid",
|
||||
/* 59 */ "Blob",
|
||||
/* 60 */ "Next",
|
||||
/* 61 */ "Or",
|
||||
/* 62 */ "And",
|
||||
/* 63 */ "ForceInt",
|
||||
/* 64 */ "ReadCookie",
|
||||
/* 65 */ "Halt",
|
||||
/* 66 */ "IsNull",
|
||||
/* 67 */ "NotNull",
|
||||
/* 68 */ "Ne",
|
||||
/* 69 */ "Eq",
|
||||
/* 70 */ "Gt",
|
||||
/* 71 */ "Le",
|
||||
/* 72 */ "Lt",
|
||||
/* 73 */ "Ge",
|
||||
/* 74 */ "Expire",
|
||||
/* 75 */ "BitAnd",
|
||||
/* 76 */ "BitOr",
|
||||
/* 77 */ "ShiftLeft",
|
||||
/* 78 */ "ShiftRight",
|
||||
/* 79 */ "Add",
|
||||
/* 80 */ "Subtract",
|
||||
/* 81 */ "Multiply",
|
||||
/* 82 */ "Divide",
|
||||
/* 83 */ "Remainder",
|
||||
/* 84 */ "Concat",
|
||||
/* 85 */ "Negative",
|
||||
/* 86 */ "DropIndex",
|
||||
/* 87 */ "BitNot",
|
||||
/* 88 */ "String8",
|
||||
/* 89 */ "IdxInsert",
|
||||
/* 90 */ "FifoRead",
|
||||
/* 91 */ "Column",
|
||||
/* 92 */ "Int64",
|
||||
/* 93 */ "Gosub",
|
||||
/* 94 */ "IfMemNeg",
|
||||
/* 95 */ "RowData",
|
||||
/* 96 */ "MemMax",
|
||||
/* 97 */ "Close",
|
||||
/* 98 */ "VerifyCookie",
|
||||
/* 99 */ "IfMemPos",
|
||||
/* 100 */ "Null",
|
||||
/* 101 */ "Integer",
|
||||
/* 102 */ "Transaction",
|
||||
/* 103 */ "IdxLT",
|
||||
/* 104 */ "Delete",
|
||||
/* 105 */ "Rewind",
|
||||
/* 106 */ "Push",
|
||||
/* 107 */ "RealAffinity",
|
||||
/* 108 */ "Clear",
|
||||
/* 109 */ "AggStep",
|
||||
/* 110 */ "Explain",
|
||||
/* 111 */ "Vacuum",
|
||||
/* 112 */ "VDestroy",
|
||||
/* 113 */ "IsUnique",
|
||||
/* 114 */ "VOpen",
|
||||
/* 115 */ "AggFinal",
|
||||
/* 116 */ "OpenWrite",
|
||||
/* 117 */ "VNext",
|
||||
/* 118 */ "AbsValue",
|
||||
/* 119 */ "Sort",
|
||||
/* 120 */ "NotFound",
|
||||
/* 121 */ "MoveLe",
|
||||
/* 122 */ "MakeRecord",
|
||||
/* 123 */ "Variable",
|
||||
/* 124 */ "CreateTable",
|
||||
/* 125 */ "Insert",
|
||||
/* 126 */ "Real",
|
||||
/* 127 */ "HexBlob",
|
||||
/* 128 */ "IdxGE",
|
||||
/* 129 */ "OpenRead",
|
||||
/* 130 */ "IdxRowid",
|
||||
/* 131 */ "VBegin",
|
||||
/* 132 */ "TableLock",
|
||||
/* 133 */ "OpenEphemeral",
|
||||
/* 134 */ "Pop",
|
||||
/* 135 */ "NotUsed_135",
|
||||
/* 136 */ "NotUsed_136",
|
||||
/* 137 */ "NotUsed_137",
|
||||
/* 138 */ "NotUsed_138",
|
||||
/* 139 */ "ToText",
|
||||
/* 140 */ "ToBlob",
|
||||
/* 141 */ "ToNumeric",
|
||||
/* 142 */ "ToInt",
|
||||
/* 143 */ "ToReal",
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -1,147 +1,147 @@
|
|||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodeh.awk script for details */
|
||||
#define OP_MemLoad 1
|
||||
#define OP_VNext 2
|
||||
#define OP_HexBlob 127 /* same as TK_BLOB */
|
||||
#define OP_Column 3
|
||||
#define OP_SetCookie 4
|
||||
#define OP_IfMemPos 5
|
||||
#define OP_Real 126 /* same as TK_FLOAT */
|
||||
#define OP_Sequence 6
|
||||
#define OP_MoveGt 7
|
||||
#define OP_Ge 73 /* same as TK_GE */
|
||||
#define OP_RowKey 8
|
||||
#define OP_Eq 69 /* same as TK_EQ */
|
||||
#define OP_OpenWrite 9
|
||||
#define OP_NotNull 67 /* same as TK_NOTNULL */
|
||||
#define OP_If 10
|
||||
#define OP_ToInt 142 /* same as TK_TO_INT */
|
||||
#define OP_String8 88 /* same as TK_STRING */
|
||||
#define OP_Pop 11
|
||||
#define OP_VRowid 12
|
||||
#define OP_CollSeq 13
|
||||
#define OP_OpenRead 14
|
||||
#define OP_Expire 15
|
||||
#define OP_AutoCommit 17
|
||||
#define OP_Gt 70 /* same as TK_GT */
|
||||
#define OP_IntegrityCk 18
|
||||
#define OP_Sort 19
|
||||
#define OP_Function 20
|
||||
#define OP_And 62 /* same as TK_AND */
|
||||
#define OP_Subtract 80 /* same as TK_MINUS */
|
||||
#define OP_Noop 21
|
||||
#define OP_Return 22
|
||||
#define OP_Remainder 83 /* same as TK_REM */
|
||||
#define OP_NewRowid 23
|
||||
#define OP_NotExists 1
|
||||
#define OP_Dup 2
|
||||
#define OP_MoveLt 3
|
||||
#define OP_Multiply 81 /* same as TK_STAR */
|
||||
#define OP_IfMemNeg 24
|
||||
#define OP_Variable 25
|
||||
#define OP_String 26
|
||||
#define OP_RealAffinity 27
|
||||
#define OP_ParseSchema 28
|
||||
#define OP_VOpen 29
|
||||
#define OP_Close 30
|
||||
#define OP_CreateIndex 31
|
||||
#define OP_IsUnique 32
|
||||
#define OP_IdxIsNull 33
|
||||
#define OP_NotFound 34
|
||||
#define OP_Int64 35
|
||||
#define OP_MustBeInt 36
|
||||
#define OP_Halt 37
|
||||
#define OP_Rowid 38
|
||||
#define OP_IdxLT 39
|
||||
#define OP_AddImm 40
|
||||
#define OP_Statement 41
|
||||
#define OP_RowData 42
|
||||
#define OP_MemMax 43
|
||||
#define OP_Push 44
|
||||
#define OP_Or 61 /* same as TK_OR */
|
||||
#define OP_NotExists 45
|
||||
#define OP_MemIncr 46
|
||||
#define OP_Gosub 47
|
||||
#define OP_Divide 82 /* same as TK_SLASH */
|
||||
#define OP_Integer 48
|
||||
#define OP_ToNumeric 141 /* same as TK_TO_NUMERIC*/
|
||||
#define OP_MemInt 49
|
||||
#define OP_Prev 50
|
||||
#define OP_Concat 84 /* same as TK_CONCAT */
|
||||
#define OP_VCreate 4
|
||||
#define OP_BitAnd 75 /* same as TK_BITAND */
|
||||
#define OP_VColumn 51
|
||||
#define OP_CreateTable 52
|
||||
#define OP_Last 53
|
||||
#define OP_IsNull 66 /* same as TK_ISNULL */
|
||||
#define OP_IdxRowid 54
|
||||
#define OP_MakeIdxRec 55
|
||||
#define OP_ShiftRight 78 /* same as TK_RSHIFT */
|
||||
#define OP_ResetCount 56
|
||||
#define OP_FifoWrite 57
|
||||
#define OP_Callback 58
|
||||
#define OP_ContextPush 59
|
||||
#define OP_DropTrigger 60
|
||||
#define OP_DropIndex 63
|
||||
#define OP_IdxGE 64
|
||||
#define OP_IdxDelete 65
|
||||
#define OP_Vacuum 74
|
||||
#define OP_MoveLe 86
|
||||
#define OP_IfNot 89
|
||||
#define OP_DropTable 90
|
||||
#define OP_MakeRecord 91
|
||||
#define OP_ToBlob 140 /* same as TK_TO_BLOB */
|
||||
#define OP_Delete 92
|
||||
#define OP_AggFinal 93
|
||||
#define OP_ShiftLeft 77 /* same as TK_LSHIFT */
|
||||
#define OP_Dup 94
|
||||
#define OP_Goto 95
|
||||
#define OP_TableLock 96
|
||||
#define OP_FifoRead 97
|
||||
#define OP_Clear 98
|
||||
#define OP_IdxGT 99
|
||||
#define OP_MoveLt 100
|
||||
#define OP_Le 71 /* same as TK_LE */
|
||||
#define OP_VerifyCookie 101
|
||||
#define OP_AggStep 102
|
||||
#define OP_Pull 103
|
||||
#define OP_ToText 139 /* same as TK_TO_TEXT */
|
||||
#define OP_Not 16 /* same as TK_NOT */
|
||||
#define OP_ToReal 143 /* same as TK_TO_REAL */
|
||||
#define OP_SetNumColumns 104
|
||||
#define OP_AbsValue 105
|
||||
#define OP_Transaction 106
|
||||
#define OP_VFilter 107
|
||||
#define OP_Negative 85 /* same as TK_UMINUS */
|
||||
#define OP_Ne 68 /* same as TK_NE */
|
||||
#define OP_VDestroy 108
|
||||
#define OP_ContextPop 109
|
||||
#define OP_BitOr 76 /* same as TK_BITOR */
|
||||
#define OP_Next 110
|
||||
#define OP_IdxInsert 111
|
||||
#define OP_Distinct 112
|
||||
#define OP_Lt 72 /* same as TK_LT */
|
||||
#define OP_Insert 113
|
||||
#define OP_Destroy 114
|
||||
#define OP_ReadCookie 115
|
||||
#define OP_ForceInt 116
|
||||
#define OP_LoadAnalysis 117
|
||||
#define OP_Explain 118
|
||||
#define OP_IfMemZero 119
|
||||
#define OP_OpenPseudo 120
|
||||
#define OP_OpenEphemeral 121
|
||||
#define OP_Null 122
|
||||
#define OP_Blob 123
|
||||
#define OP_Add 79 /* same as TK_PLUS */
|
||||
#define OP_MemStore 124
|
||||
#define OP_Rewind 125
|
||||
#define OP_MoveGe 128
|
||||
#define OP_VBegin 129
|
||||
#define OP_VUpdate 130
|
||||
#define OP_DropTrigger 5
|
||||
#define OP_OpenPseudo 6
|
||||
#define OP_MemInt 7
|
||||
#define OP_IntegrityCk 8
|
||||
#define OP_RowKey 9
|
||||
#define OP_LoadAnalysis 10
|
||||
#define OP_IdxGT 11
|
||||
#define OP_Last 12
|
||||
#define OP_Subtract 80 /* same as TK_MINUS */
|
||||
#define OP_MemLoad 13
|
||||
#define OP_Remainder 83 /* same as TK_REM */
|
||||
#define OP_SetCookie 14
|
||||
#define OP_Sequence 15
|
||||
#define OP_Pull 17
|
||||
#define OP_VUpdate 18
|
||||
#define OP_VColumn 19
|
||||
#define OP_DropTable 20
|
||||
#define OP_MemStore 21
|
||||
#define OP_ContextPush 22
|
||||
#define OP_NotNull 67 /* same as TK_NOTNULL */
|
||||
#define OP_Rowid 23
|
||||
#define OP_Real 126 /* same as TK_FLOAT */
|
||||
#define OP_String8 88 /* same as TK_STRING */
|
||||
#define OP_And 62 /* same as TK_AND */
|
||||
#define OP_BitNot 87 /* same as TK_BITNOT */
|
||||
#define OP_VCreate 131
|
||||
#define OP_MemMove 132
|
||||
#define OP_MemNull 133
|
||||
#define OP_Found 134
|
||||
#define OP_NullRow 135
|
||||
#define OP_VFilter 24
|
||||
#define OP_NullRow 25
|
||||
#define OP_Noop 26
|
||||
#define OP_VRowid 27
|
||||
#define OP_Ge 73 /* same as TK_GE */
|
||||
#define OP_HexBlob 127 /* same as TK_BLOB */
|
||||
#define OP_ParseSchema 28
|
||||
#define OP_Statement 29
|
||||
#define OP_CollSeq 30
|
||||
#define OP_ContextPop 31
|
||||
#define OP_ToText 139 /* same as TK_TO_TEXT */
|
||||
#define OP_MemIncr 32
|
||||
#define OP_MoveGe 33
|
||||
#define OP_Eq 69 /* same as TK_EQ */
|
||||
#define OP_ToNumeric 141 /* same as TK_TO_NUMERIC*/
|
||||
#define OP_If 34
|
||||
#define OP_IfNot 35
|
||||
#define OP_ShiftRight 78 /* same as TK_RSHIFT */
|
||||
#define OP_Destroy 36
|
||||
#define OP_Distinct 37
|
||||
#define OP_CreateIndex 38
|
||||
#define OP_SetNumColumns 39
|
||||
#define OP_Not 16 /* same as TK_NOT */
|
||||
#define OP_Gt 70 /* same as TK_GT */
|
||||
#define OP_ResetCount 40
|
||||
#define OP_MakeIdxRec 41
|
||||
#define OP_Goto 42
|
||||
#define OP_IdxDelete 43
|
||||
#define OP_MemMove 44
|
||||
#define OP_Found 45
|
||||
#define OP_MoveGt 46
|
||||
#define OP_IfMemZero 47
|
||||
#define OP_MustBeInt 48
|
||||
#define OP_Prev 49
|
||||
#define OP_MemNull 50
|
||||
#define OP_AutoCommit 51
|
||||
#define OP_String 52
|
||||
#define OP_FifoWrite 53
|
||||
#define OP_ToInt 142 /* same as TK_TO_INT */
|
||||
#define OP_Return 54
|
||||
#define OP_Callback 55
|
||||
#define OP_AddImm 56
|
||||
#define OP_Function 57
|
||||
#define OP_Concat 84 /* same as TK_CONCAT */
|
||||
#define OP_NewRowid 58
|
||||
#define OP_Blob 59
|
||||
#define OP_IsNull 66 /* same as TK_ISNULL */
|
||||
#define OP_Next 60
|
||||
#define OP_ForceInt 63
|
||||
#define OP_ReadCookie 64
|
||||
#define OP_Halt 65
|
||||
#define OP_Expire 74
|
||||
#define OP_Or 61 /* same as TK_OR */
|
||||
#define OP_DropIndex 86
|
||||
#define OP_IdxInsert 89
|
||||
#define OP_ShiftLeft 77 /* same as TK_LSHIFT */
|
||||
#define OP_FifoRead 90
|
||||
#define OP_Column 91
|
||||
#define OP_Int64 92
|
||||
#define OP_Gosub 93
|
||||
#define OP_IfMemNeg 94
|
||||
#define OP_RowData 95
|
||||
#define OP_BitOr 76 /* same as TK_BITOR */
|
||||
#define OP_MemMax 96
|
||||
#define OP_Close 97
|
||||
#define OP_ToReal 143 /* same as TK_TO_REAL */
|
||||
#define OP_VerifyCookie 98
|
||||
#define OP_IfMemPos 99
|
||||
#define OP_Null 100
|
||||
#define OP_Integer 101
|
||||
#define OP_Transaction 102
|
||||
#define OP_Divide 82 /* same as TK_SLASH */
|
||||
#define OP_IdxLT 103
|
||||
#define OP_Delete 104
|
||||
#define OP_Rewind 105
|
||||
#define OP_Push 106
|
||||
#define OP_RealAffinity 107
|
||||
#define OP_Clear 108
|
||||
#define OP_AggStep 109
|
||||
#define OP_Explain 110
|
||||
#define OP_Vacuum 111
|
||||
#define OP_VDestroy 112
|
||||
#define OP_IsUnique 113
|
||||
#define OP_VOpen 114
|
||||
#define OP_AggFinal 115
|
||||
#define OP_OpenWrite 116
|
||||
#define OP_Negative 85 /* same as TK_UMINUS */
|
||||
#define OP_Le 71 /* same as TK_LE */
|
||||
#define OP_VNext 117
|
||||
#define OP_AbsValue 118
|
||||
#define OP_Sort 119
|
||||
#define OP_NotFound 120
|
||||
#define OP_MoveLe 121
|
||||
#define OP_MakeRecord 122
|
||||
#define OP_Add 79 /* same as TK_PLUS */
|
||||
#define OP_Ne 68 /* same as TK_NE */
|
||||
#define OP_Variable 123
|
||||
#define OP_CreateTable 124
|
||||
#define OP_Insert 125
|
||||
#define OP_IdxGE 128
|
||||
#define OP_OpenRead 129
|
||||
#define OP_IdxRowid 130
|
||||
#define OP_ToBlob 140 /* same as TK_TO_BLOB */
|
||||
#define OP_VBegin 131
|
||||
#define OP_TableLock 132
|
||||
#define OP_OpenEphemeral 133
|
||||
#define OP_Lt 72 /* same as TK_LT */
|
||||
#define OP_Pop 134
|
||||
|
||||
/* The following opcode values are never used */
|
||||
#define OP_NotUsed_135 135
|
||||
#define OP_NotUsed_136 136
|
||||
#define OP_NotUsed_137 137
|
||||
#define OP_NotUsed_138 138
|
||||
|
@ -149,13 +149,13 @@
|
|||
/* Opcodes that are guaranteed to never push a value onto the stack
|
||||
** contain a 1 their corresponding position of the following mask
|
||||
** set. See the opcodeNoPush() function in vdbeaux.c */
|
||||
#define NOPUSH_MASK_0 0xeeb4
|
||||
#define NOPUSH_MASK_1 0x796b
|
||||
#define NOPUSH_MASK_2 0xfbb7
|
||||
#define NOPUSH_MASK_3 0xff24
|
||||
#define NOPUSH_MASK_4 0xffff
|
||||
#define NOPUSH_MASK_5 0xb6ef
|
||||
#define NOPUSH_MASK_6 0xfdfd
|
||||
#define NOPUSH_MASK_7 0x33b3
|
||||
#define NOPUSH_MASK_8 0xf8cf
|
||||
#define NOPUSH_MASK_0 0x5c7a
|
||||
#define NOPUSH_MASK_1 0xf777
|
||||
#define NOPUSH_MASK_2 0xedaf
|
||||
#define NOPUSH_MASK_3 0xf1eb
|
||||
#define NOPUSH_MASK_4 0xfffe
|
||||
#define NOPUSH_MASK_5 0x62ef
|
||||
#define NOPUSH_MASK_6 0xbfcf
|
||||
#define NOPUSH_MASK_7 0x23bf
|
||||
#define NOPUSH_MASK_8 0xf87b
|
||||
#define NOPUSH_MASK_9 0x0000
|
||||
|
|
|
@ -81,9 +81,21 @@
|
|||
** 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
|
||||
** 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
|
||||
# define TEMP_FILE_PREFIX "sqlite_"
|
||||
# define TEMP_FILE_PREFIX "etilqs_"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -110,6 +122,9 @@
|
|||
#define sqlite3OsRealloc sqlite3GenericRealloc
|
||||
#define sqlite3OsFree sqlite3GenericFree
|
||||
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
|
||||
#define sqlite3OsDlopen sqlite3UnixDlopen
|
||||
#define sqlite3OsDlsym sqlite3UnixDlsym
|
||||
#define sqlite3OsDlclose sqlite3UnixDlclose
|
||||
#endif
|
||||
#if OS_WIN
|
||||
#define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite
|
||||
|
@ -132,6 +147,9 @@
|
|||
#define sqlite3OsRealloc sqlite3GenericRealloc
|
||||
#define sqlite3OsFree sqlite3GenericFree
|
||||
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
|
||||
#define sqlite3OsDlopen sqlite3WinDlopen
|
||||
#define sqlite3OsDlsym sqlite3WinDlsym
|
||||
#define sqlite3OsDlclose sqlite3WinDlclose
|
||||
#endif
|
||||
#if OS_OS2
|
||||
#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite
|
||||
|
@ -154,6 +172,9 @@
|
|||
#define sqlite3OsRealloc sqlite3GenericRealloc
|
||||
#define sqlite3OsFree sqlite3GenericFree
|
||||
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
|
||||
#define sqlite3OsDlopen sqlite3Os2Dlopen
|
||||
#define sqlite3OsDlsym sqlite3Os2Dlsym
|
||||
#define sqlite3OsDlclose sqlite3Os2Dlclose
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -337,6 +358,9 @@ void *sqlite3OsMalloc(int);
|
|||
void *sqlite3OsRealloc(void *, int);
|
||||
void sqlite3OsFree(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
|
||||
|
@ -381,16 +405,26 @@ struct sqlite3OsVtbl {
|
|||
void *(*xRealloc)(void *, int);
|
||||
void (*xFree)(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
|
||||
** no disk I/O
|
||||
** no disk I/O or extension loading
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_DISKIO
|
||||
# define IF_DISKIO(X) 0
|
||||
#else
|
||||
# define IF_DISKIO(X) X
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_LOAD_EXTENSION
|
||||
# define IF_DLOPEN(X) 0
|
||||
#else
|
||||
# define IF_DLOPEN(X) X
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _SQLITE_OS_C_
|
||||
/*
|
||||
|
@ -416,7 +450,10 @@ struct sqlite3OsVtbl {
|
|||
sqlite3OsMalloc,
|
||||
sqlite3OsRealloc,
|
||||
sqlite3OsFree,
|
||||
sqlite3OsAllocationSize
|
||||
sqlite3OsAllocationSize,
|
||||
IF_DLOPEN( sqlite3OsDlopen ),
|
||||
IF_DLOPEN( sqlite3OsDlsym ),
|
||||
IF_DLOPEN( sqlite3OsDlclose ),
|
||||
};
|
||||
#else
|
||||
/*
|
||||
|
|
|
@ -92,25 +92,25 @@ int sqlite3_io_error_hit = 0;
|
|||
int sqlite3_io_error_pending = 0;
|
||||
int sqlite3_diskfull_pending = 0;
|
||||
int sqlite3_diskfull = 0;
|
||||
#define SimulateIOError(A) \
|
||||
#define SimulateIOError(CODE) \
|
||||
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(){
|
||||
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 == 1 ){ \
|
||||
local_ioerr(); \
|
||||
sqlite3_diskfull = 1; \
|
||||
return SQLITE_FULL; \
|
||||
CODE; \
|
||||
}else{ \
|
||||
sqlite3_diskfull_pending--; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define SimulateIOError(A)
|
||||
#define SimulateDiskfullError
|
||||
#define SimulateDiskfullError(A)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -40,6 +40,7 @@
|
|||
*/
|
||||
#if defined(_WIN32_WCE)
|
||||
# define OS_WINCE 1
|
||||
# define AreFileApisANSI() 1
|
||||
#else
|
||||
# define OS_WINCE 0
|
||||
#endif
|
||||
|
@ -124,16 +125,14 @@ int sqlite3_os_type = 0;
|
|||
#endif /* OS_WINCE */
|
||||
|
||||
/*
|
||||
** Convert a UTF-8 string to UTF-32. Space to hold the returned string
|
||||
** is obtained from sqliteMalloc.
|
||||
** Convert a UTF-8 string to microsoft unicode (UTF-16?).
|
||||
**
|
||||
** Space to hold the returned string is obtained from sqliteMalloc.
|
||||
*/
|
||||
static WCHAR *utf8ToUnicode(const char *zFilename){
|
||||
int nChar;
|
||||
WCHAR *zWideFilename;
|
||||
|
||||
if( !isNT() ){
|
||||
return 0;
|
||||
}
|
||||
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
|
||||
zWideFilename = sqliteMalloc( nChar*sizeof(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().
|
||||
*/
|
||||
static char *unicodeToUtf8(const WCHAR *zWideFilename){
|
||||
|
@ -169,6 +168,91 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){
|
|||
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
|
||||
/*************************************************************************
|
||||
** This section contains code for WinCE only.
|
||||
|
@ -475,6 +559,23 @@ static BOOL winceLockFileEx(
|
|||
*****************************************************************************/
|
||||
#endif /* OS_WINCE */
|
||||
|
||||
/*
|
||||
** Convert a UTF-8 filename into whatever form the underlying
|
||||
** operating system wants filenames in. Space to hold the result
|
||||
** is obtained from sqliteMalloc and must be freed by the calling
|
||||
** function.
|
||||
*/
|
||||
static void *convertUtf8Filename(const char *zFilename){
|
||||
void *zConverted = 0;
|
||||
if( isNT() ){
|
||||
zConverted = utf8ToUnicode(zFilename);
|
||||
}else{
|
||||
zConverted = utf8ToMbcs(zFilename);
|
||||
}
|
||||
/* caller will handle out of memory */
|
||||
return zConverted;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the named file.
|
||||
**
|
||||
|
@ -489,25 +590,30 @@ static BOOL winceLockFileEx(
|
|||
*/
|
||||
#define MX_DELETION_ATTEMPTS 3
|
||||
int sqlite3WinDelete(const char *zFilename){
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
int cnt = 0;
|
||||
int rc;
|
||||
if( zWide ){
|
||||
void *zConverted = convertUtf8Filename(zFilename);
|
||||
if( zConverted==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( isNT() ){
|
||||
do{
|
||||
rc = DeleteFileW(zWide);
|
||||
}while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
|
||||
sqliteFree(zWide);
|
||||
rc = DeleteFileW(zConverted);
|
||||
}while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff
|
||||
&& cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
|
||||
}else{
|
||||
#if OS_WINCE
|
||||
return SQLITE_NOMEM;
|
||||
#else
|
||||
do{
|
||||
rc = DeleteFileA(zFilename);
|
||||
}while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
|
||||
rc = DeleteFileA(zConverted);
|
||||
}while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff
|
||||
&& cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
|
||||
#endif
|
||||
}
|
||||
sqliteFree(zConverted);
|
||||
TRACE2("DELETE \"%s\"\n", zFilename);
|
||||
return rc==0 ? SQLITE_OK : SQLITE_IOERR;
|
||||
return rc!=0 ? SQLITE_OK : SQLITE_IOERR;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -515,17 +621,20 @@ int sqlite3WinDelete(const char *zFilename){
|
|||
*/
|
||||
int sqlite3WinFileExists(const char *zFilename){
|
||||
int exists = 0;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
if( zWide ){
|
||||
exists = GetFileAttributesW(zWide) != 0xffffffff;
|
||||
sqliteFree(zWide);
|
||||
void *zConverted = convertUtf8Filename(zFilename);
|
||||
if( zConverted==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( isNT() ){
|
||||
exists = GetFileAttributesW((WCHAR*)zConverted) != 0xffffffff;
|
||||
}else{
|
||||
#if OS_WINCE
|
||||
return SQLITE_NOMEM;
|
||||
#else
|
||||
exists = GetFileAttributesA(zFilename) != 0xffffffff;
|
||||
exists = GetFileAttributesA((char*)zConverted) != 0xffffffff;
|
||||
#endif
|
||||
}
|
||||
sqliteFree(zConverted);
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
@ -552,10 +661,14 @@ int sqlite3WinOpenReadWrite(
|
|||
){
|
||||
winFile f;
|
||||
HANDLE h;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
void *zConverted = convertUtf8Filename(zFilename);
|
||||
if( zConverted==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( *pId==0 );
|
||||
if( zWide ){
|
||||
h = CreateFileW(zWide,
|
||||
|
||||
if( isNT() ){
|
||||
h = CreateFileW((WCHAR*)zConverted,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
|
@ -564,7 +677,7 @@ int sqlite3WinOpenReadWrite(
|
|||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
h = CreateFileW(zWide,
|
||||
h = CreateFileW((WCHAR*)zConverted,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
|
@ -573,7 +686,7 @@ int sqlite3WinOpenReadWrite(
|
|||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
sqliteFree(zWide);
|
||||
sqliteFree(zConverted);
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
*pReadonly = 1;
|
||||
|
@ -583,16 +696,15 @@ int sqlite3WinOpenReadWrite(
|
|||
#if OS_WINCE
|
||||
if (!winceCreateLock(zFilename, &f)){
|
||||
CloseHandle(h);
|
||||
sqliteFree(zWide);
|
||||
sqliteFree(zConverted);
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
#endif
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
#if OS_WINCE
|
||||
return SQLITE_NOMEM;
|
||||
#else
|
||||
h = CreateFileA(zFilename,
|
||||
h = CreateFileA((char*)zConverted,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
|
@ -601,7 +713,7 @@ int sqlite3WinOpenReadWrite(
|
|||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
h = CreateFileA(zFilename,
|
||||
h = CreateFileA((char*)zConverted,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
|
@ -610,6 +722,7 @@ int sqlite3WinOpenReadWrite(
|
|||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
sqliteFree(zConverted);
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
*pReadonly = 1;
|
||||
|
@ -618,6 +731,9 @@ int sqlite3WinOpenReadWrite(
|
|||
}
|
||||
#endif /* OS_WINCE */
|
||||
}
|
||||
|
||||
sqliteFree(zConverted);
|
||||
|
||||
f.h = h;
|
||||
#if OS_WINCE
|
||||
f.zDeleteOnClose = 0;
|
||||
|
@ -650,8 +766,11 @@ int sqlite3WinOpenReadWrite(
|
|||
int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
|
||||
winFile f;
|
||||
HANDLE h;
|
||||
int fileflags;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
DWORD fileflags;
|
||||
void *zConverted = convertUtf8Filename(zFilename);
|
||||
if( zConverted==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( *pId == 0 );
|
||||
fileflags = FILE_FLAG_RANDOM_ACCESS;
|
||||
#if !OS_WINCE
|
||||
|
@ -659,10 +778,10 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
|
|||
fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
|
||||
}
|
||||
#endif
|
||||
if( zWide ){
|
||||
if( isNT() ){
|
||||
int cnt = 0;
|
||||
do{
|
||||
h = CreateFileW(zWide,
|
||||
h = CreateFileW((WCHAR*)zConverted,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
|
@ -671,14 +790,13 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
|
|||
NULL
|
||||
);
|
||||
}while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
#if OS_WINCE
|
||||
return SQLITE_NOMEM;
|
||||
#else
|
||||
int cnt = 0;
|
||||
do{
|
||||
h = CreateFileA(zFilename,
|
||||
h = CreateFileA((char*)zConverted,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
|
@ -689,14 +807,18 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
|
|||
}while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
|
||||
#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 ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
f.h = h;
|
||||
#if OS_WINCE
|
||||
f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0;
|
||||
f.hMutex = NULL;
|
||||
#endif
|
||||
TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
|
||||
return allocateWinFile(&f, pId);
|
||||
}
|
||||
|
@ -711,10 +833,13 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
|
|||
int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
|
||||
winFile f;
|
||||
HANDLE h;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
void *zConverted = convertUtf8Filename(zFilename);
|
||||
if( zConverted==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( *pId==0 );
|
||||
if( zWide ){
|
||||
h = CreateFileW(zWide,
|
||||
if( isNT() ){
|
||||
h = CreateFileW((WCHAR*)zConverted,
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
|
@ -722,12 +847,11 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
|
|||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
#if OS_WINCE
|
||||
return SQLITE_NOMEM;
|
||||
#else
|
||||
h = CreateFileA(zFilename,
|
||||
h = CreateFileA((char*)zConverted,
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
|
@ -737,6 +861,7 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
|
|||
);
|
||||
#endif
|
||||
}
|
||||
sqliteFree(zConverted);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
|
@ -802,9 +927,21 @@ int sqlite3WinTempFileName(char *zBuf){
|
|||
strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
|
||||
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
|
||||
sqliteFree(zMulti);
|
||||
}else{
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}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--){}
|
||||
zTempPath[i] = 0;
|
||||
|
@ -864,15 +1001,16 @@ static int winClose(OsFile **pId){
|
|||
static int winRead(OsFile *id, void *pBuf, int amt){
|
||||
DWORD got;
|
||||
assert( id!=0 );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateIOError(return SQLITE_IOERR_READ);
|
||||
TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
|
||||
if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
|
||||
got = 0;
|
||||
return SQLITE_IOERR_READ;
|
||||
}
|
||||
if( got==(DWORD)amt ){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
return SQLITE_IOERR;
|
||||
memset(&((char*)pBuf)[got], 0, amt-got);
|
||||
return SQLITE_IOERR_SHORT_READ;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -884,8 +1022,8 @@ static int winWrite(OsFile *id, const void *pBuf, int amt){
|
|||
int rc = 0;
|
||||
DWORD wrote;
|
||||
assert( id!=0 );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateDiskfullError;
|
||||
SimulateIOError(return SQLITE_IOERR_READ);
|
||||
SimulateDiskfullError(return SQLITE_FULL);
|
||||
TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
|
||||
assert( amt>0 );
|
||||
while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
|
||||
|
@ -915,7 +1053,7 @@ static int winSeek(OsFile *id, i64 offset){
|
|||
DWORD rc;
|
||||
assert( id!=0 );
|
||||
#ifdef SQLITE_TEST
|
||||
if( offset ) SimulateDiskfullError
|
||||
if( offset ) SimulateDiskfullError(return SQLITE_FULL);
|
||||
#endif
|
||||
SEEK(offset/1024 + 1);
|
||||
rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
|
@ -944,7 +1082,7 @@ static int winSync(OsFile *id, int dataOnly){
|
|||
** than UNIX.
|
||||
*/
|
||||
int sqlite3WinSyncDirectory(const char *zDirname){
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateIOError(return SQLITE_IOERR_READ);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -955,7 +1093,7 @@ static int winTruncate(OsFile *id, i64 nByte){
|
|||
LONG upperBits = nByte>>32;
|
||||
assert( id!=0 );
|
||||
TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
|
||||
SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
|
||||
SetEndOfFile(((winFile*)id)->h);
|
||||
return SQLITE_OK;
|
||||
|
@ -967,7 +1105,7 @@ static int winTruncate(OsFile *id, i64 nByte){
|
|||
static int winFileSize(OsFile *id, i64 *pSize){
|
||||
DWORD upperBits, lowerBits;
|
||||
assert( id!=0 );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateIOError(return SQLITE_IOERR_FSTAT);
|
||||
lowerBits = GetFileSize(((winFile*)id)->h, &upperBits);
|
||||
*pSize = (((i64)upperBits)<<32) + lowerBits;
|
||||
return SQLITE_OK;
|
||||
|
@ -1022,20 +1160,24 @@ static int unlockReadLock(winFile *pFile){
|
|||
*/
|
||||
int sqlite3WinIsDirWritable(char *zDirname){
|
||||
int fileAttr;
|
||||
WCHAR *zWide;
|
||||
void *zConverted;
|
||||
if( zDirname==0 ) return 0;
|
||||
if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
|
||||
zWide = utf8ToUnicode(zDirname);
|
||||
if( zWide ){
|
||||
fileAttr = GetFileAttributesW(zWide);
|
||||
sqliteFree(zWide);
|
||||
|
||||
zConverted = convertUtf8Filename(zDirname);
|
||||
if( zConverted==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( isNT() ){
|
||||
fileAttr = GetFileAttributesW((WCHAR*)zConverted);
|
||||
}else{
|
||||
#if OS_WINCE
|
||||
return 0;
|
||||
#else
|
||||
fileAttr = GetFileAttributesA(zDirname);
|
||||
fileAttr = GetFileAttributesA((char*)zConverted);
|
||||
#endif
|
||||
}
|
||||
sqliteFree(zConverted);
|
||||
if( fileAttr == 0xffffffff ) return 0;
|
||||
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
|
||||
return 0;
|
||||
|
@ -1224,7 +1366,7 @@ static int winUnlock(OsFile *id, int locktype){
|
|||
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
|
||||
/* This should never happen. We should always be able to
|
||||
** reacquire the read lock */
|
||||
rc = SQLITE_IOERR;
|
||||
rc = SQLITE_IOERR_UNLOCK;
|
||||
}
|
||||
}
|
||||
if( type>=RESERVED_LOCK ){
|
||||
|
@ -1258,24 +1400,33 @@ char *sqlite3WinFullPathname(const char *zRelative){
|
|||
/* WinCE has no concept of a relative pathname, or so I am told. */
|
||||
zFull = sqliteStrDup(zRelative);
|
||||
#else
|
||||
char *zNotUsed;
|
||||
WCHAR *zWide;
|
||||
int nByte;
|
||||
zWide = utf8ToUnicode(zRelative);
|
||||
if( zWide ){
|
||||
WCHAR *zTemp, *zNotUsedW;
|
||||
nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1;
|
||||
void *zConverted;
|
||||
zConverted = convertUtf8Filename(zRelative);
|
||||
if( isNT() ){
|
||||
WCHAR *zTemp;
|
||||
nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
|
||||
zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
|
||||
if( zTemp==0 ) return 0;
|
||||
GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW);
|
||||
sqliteFree(zWide);
|
||||
if( zTemp==0 ){
|
||||
sqliteFree(zConverted);
|
||||
return 0;
|
||||
}
|
||||
GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
|
||||
sqliteFree(zConverted);
|
||||
zFull = unicodeToUtf8(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
}else{
|
||||
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
|
||||
zFull = sqliteMalloc( nByte*sizeof(zFull[0]) );
|
||||
if( zFull==0 ) return 0;
|
||||
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
|
||||
char *zTemp;
|
||||
nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
|
||||
zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
|
||||
if( zTemp==0 ){
|
||||
sqliteFree(zConverted);
|
||||
return 0;
|
||||
}
|
||||
GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
|
||||
sqliteFree(zConverted);
|
||||
zFull = mbcsToUtf8(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
}
|
||||
#endif
|
||||
return zFull;
|
||||
|
@ -1357,6 +1508,45 @@ static int allocateWinFile(winFile *pInit, OsFile **pId){
|
|||
** 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
|
||||
** is written into the buffer zBuf[256]. The calling function must
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
** Macros for troubleshooting. Normally turned off
|
||||
*/
|
||||
#if 0
|
||||
#define sqlite3DebugPrintf printf
|
||||
#define TRACE1(X) sqlite3DebugPrintf(X)
|
||||
#define TRACE2(X,Y) sqlite3DebugPrintf(X,Y)
|
||||
#define TRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
|
||||
|
@ -231,7 +232,6 @@ struct Pager {
|
|||
u8 fullSync; /* Do extra syncs of the journal for robustness */
|
||||
u8 full_fsync; /* Use F_FULLFSYNC when available */
|
||||
u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
|
||||
u8 errCode; /* One of several kinds of errors */
|
||||
u8 tempFile; /* zFilename is a temporary file */
|
||||
u8 readOnly; /* True for a read-only database */
|
||||
u8 needSync; /* True if an fsync() is needed on the journal */
|
||||
|
@ -239,6 +239,7 @@ struct Pager {
|
|||
u8 alwaysRollback; /* Disable dont_rollback() for all pages */
|
||||
u8 memDb; /* True to inhibit all file I/O */
|
||||
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 origDbSize; /* dbSize before the current change */
|
||||
int stmtSize; /* Size of database (in pages) at stmt_begin() */
|
||||
|
@ -350,7 +351,9 @@ static const unsigned char aJournalMagic[] = {
|
|||
/*
|
||||
** The default size of a disk sector
|
||||
*/
|
||||
#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
|
||||
|
@ -376,8 +379,8 @@ static const unsigned char aJournalMagic[] = {
|
|||
static int cnt = 0;
|
||||
if( !pager3_refinfo_enable ) return;
|
||||
sqlite3DebugPrintf(
|
||||
"REFCNT: %4d addr=%p nRef=%d\n",
|
||||
p->pgno, PGHDR_TO_DATA(p), p->nRef
|
||||
"REFCNT: %4d addr=%p nRef=%-3d total=%d\n",
|
||||
p->pgno, PGHDR_TO_DATA(p), p->nRef, p->pPager->nRef
|
||||
);
|
||||
cnt++; /* Something to set a breakpoint on */
|
||||
}
|
||||
|
@ -476,12 +479,13 @@ static u32 retrieve32bits(PgHdr *p, int offset){
|
|||
** will immediately return the same error code.
|
||||
*/
|
||||
static int pager_error(Pager *pPager, int rc){
|
||||
int rc2 = rc & 0xff;
|
||||
assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK );
|
||||
if(
|
||||
rc==SQLITE_FULL ||
|
||||
rc==SQLITE_IOERR ||
|
||||
rc==SQLITE_CORRUPT ||
|
||||
rc==SQLITE_PROTOCOL
|
||||
rc2==SQLITE_FULL ||
|
||||
rc2==SQLITE_IOERR ||
|
||||
rc2==SQLITE_CORRUPT ||
|
||||
rc2==SQLITE_PROTOCOL
|
||||
){
|
||||
pPager->errCode = rc;
|
||||
}
|
||||
|
@ -846,6 +850,23 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
|
|||
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
|
||||
** sets the state of the pager back to what it was when it was first
|
||||
|
@ -870,11 +891,9 @@ static void pager_reset(Pager *pPager){
|
|||
if( pPager->state>=PAGER_RESERVED ){
|
||||
sqlite3pager_rollback(pPager);
|
||||
}
|
||||
sqlite3OsUnlock(pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
pPager->dbSize = -1;
|
||||
pager_unlock(pPager);
|
||||
pPager->nRef = 0;
|
||||
assert( pPager->journalOpen==0 );
|
||||
assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -926,6 +945,7 @@ static int pager_unwritelock(Pager *pPager){
|
|||
pPager->setMaster = 0;
|
||||
pPager->needSync = 0;
|
||||
pPager->pFirstSynced = pPager->pFirst;
|
||||
pPager->dbSize = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1340,6 +1360,10 @@ static int pager_playback(Pager *pPager){
|
|||
pPager->journalOff = szJ;
|
||||
break;
|
||||
}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;
|
||||
}
|
||||
}
|
||||
|
@ -1416,6 +1440,7 @@ static int pager_stmt_playback(Pager *pPager){
|
|||
if( pPager->state>=PAGER_EXCLUSIVE ){
|
||||
rc = pager_truncate(pPager, pPager->stmtSize);
|
||||
}
|
||||
assert( pPager->state>=PAGER_SHARED );
|
||||
pPager->dbSize = pPager->stmtSize;
|
||||
|
||||
/* Figure out how many records are in the statement journal.
|
||||
|
@ -1793,14 +1818,19 @@ void enable_simulated_io_errors(void){
|
|||
** 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).
|
||||
*/
|
||||
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);
|
||||
if( MEMDB==0 ){
|
||||
disable_simulated_io_errors();
|
||||
sqlite3OsSeek(pPager->fd, 0);
|
||||
sqlite3OsRead(pPager->fd, pDest, N);
|
||||
enable_simulated_io_errors();
|
||||
rc = sqlite3OsRead(pPager->fd, pDest, N);
|
||||
if( rc==SQLITE_IOERR_SHORT_READ ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1814,12 +1844,13 @@ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
|
|||
*/
|
||||
int sqlite3pager_pagecount(Pager *pPager){
|
||||
i64 n;
|
||||
int rc;
|
||||
assert( pPager!=0 );
|
||||
if( pPager->dbSize>=0 ){
|
||||
n = pPager->dbSize;
|
||||
} else {
|
||||
if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){
|
||||
pager_error(pPager, SQLITE_IOERR);
|
||||
if( (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){
|
||||
pager_error(pPager, rc);
|
||||
return 0;
|
||||
}
|
||||
if( n>0 && n<pPager->pageSize ){
|
||||
|
@ -1959,9 +1990,15 @@ static void memoryTruncate(Pager *pPager){
|
|||
*/
|
||||
static int pager_wait_on_lock(Pager *pPager, int locktype){
|
||||
int rc;
|
||||
|
||||
/* The OS lock values must be the same as the Pager lock values */
|
||||
assert( PAGER_SHARED==SHARED_LOCK );
|
||||
assert( PAGER_RESERVED==RESERVED_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 ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
|
@ -1980,6 +2017,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
|
|||
*/
|
||||
int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
|
||||
int rc;
|
||||
assert( pPager->state>=PAGER_SHARED || MEMDB );
|
||||
sqlite3pager_pagecount(pPager);
|
||||
if( pPager->errCode ){
|
||||
rc = pPager->errCode;
|
||||
|
@ -2026,7 +2064,6 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
|
|||
** to the caller.
|
||||
*/
|
||||
int sqlite3pager_close(Pager *pPager){
|
||||
PgHdr *pPg, *pNext;
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
/* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to
|
||||
** malloc() must have already been made by this thread before it gets
|
||||
|
@ -2038,46 +2075,10 @@ int sqlite3pager_close(Pager *pPager){
|
|||
assert( pTsd && pTsd->nAlloc );
|
||||
#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();
|
||||
sqlite3pager_rollback(pPager);
|
||||
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);
|
||||
}
|
||||
disable_simulated_io_errors();
|
||||
pPager->errCode = 0;
|
||||
pager_reset(pPager);
|
||||
enable_simulated_io_errors();
|
||||
TRACE2("CLOSE %d\n", PAGERID(pPager));
|
||||
assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
|
||||
if( pPager->journalOpen ){
|
||||
|
@ -2578,7 +2579,7 @@ int sqlite3pager_release_memory(int nReq){
|
|||
** The error will be returned to the user (or users, in the case
|
||||
** 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 );
|
||||
pager_error(p, rc);
|
||||
}
|
||||
|
@ -2659,8 +2660,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
|||
*/
|
||||
rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsUnlock(pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
pager_unlock(pPager);
|
||||
return pager_error(pPager, rc);
|
||||
}
|
||||
pPager->state = PAGER_EXCLUSIVE;
|
||||
|
@ -2675,8 +2675,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
|||
*/
|
||||
rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsUnlock(pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
pager_unlock(pPager);
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
pPager->journalOpen = 1;
|
||||
|
@ -2783,19 +2782,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
|||
}
|
||||
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||
if( rc!=SQLITE_OK ){
|
||||
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;
|
||||
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
|
||||
return rc;
|
||||
}else{
|
||||
clear_simulated_io_error();
|
||||
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
|
||||
}
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
|
||||
pPg->pgno = 0;
|
||||
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
|
||||
return rc;
|
||||
}else{
|
||||
TEST_INCR(pPager->nRead);
|
||||
}
|
||||
|
@ -2967,8 +2957,7 @@ failed_to_open_journal:
|
|||
*/
|
||||
sqlite3OsDelete(pPager->zJournal);
|
||||
}else{
|
||||
sqlite3OsUnlock(pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
pager_reset(pPager);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -3227,6 +3216,7 @@ int sqlite3pager_write(void *pData){
|
|||
|
||||
/* Update the database size and return.
|
||||
*/
|
||||
assert( pPager->state>=PAGER_SHARED );
|
||||
if( pPager->dbSize<(int)pPg->pgno ){
|
||||
pPager->dbSize = pPg->pgno;
|
||||
if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
|
||||
|
@ -3302,6 +3292,7 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
|
|||
assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */
|
||||
pPg->alwaysRollback = 1;
|
||||
if( pPg->dirty && !pPager->stmtInUse ){
|
||||
assert( pPager->state>=PAGER_SHARED );
|
||||
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
|
||||
** during the current transaction, then do NOT mark the page as clean.
|
||||
|
@ -3331,7 +3322,8 @@ void sqlite3pager_dont_rollback(void *pData){
|
|||
PgHdr *pPg = DATA_TO_PGHDR(pData);
|
||||
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->inJournal && (int)pPg->pgno <= pPager->origDbSize ){
|
||||
assert( pPager->aInJournal!=0 );
|
||||
|
@ -3399,14 +3391,12 @@ int sqlite3pager_commit(Pager *pPager){
|
|||
** if there have been no changes to the database file. */
|
||||
assert( pPager->needSync==0 );
|
||||
rc = pager_unwritelock(pPager);
|
||||
pPager->dbSize = -1;
|
||||
return rc;
|
||||
}
|
||||
assert( pPager->journalOpen );
|
||||
rc = sqlite3pager_sync(pPager, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_unwritelock(pPager);
|
||||
pPager->dbSize = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -3464,7 +3454,6 @@ int sqlite3pager_rollback(Pager *pPager){
|
|||
|
||||
if( !pPager->dirtyCache || !pPager->journalOpen ){
|
||||
rc = pager_unwritelock(pPager);
|
||||
pPager->dbSize = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -3540,6 +3529,7 @@ int sqlite3pager_stmt_begin(Pager *pPager){
|
|||
int rc;
|
||||
char zTemp[SQLITE_TEMPNAME_SIZE];
|
||||
assert( !pPager->stmtInUse );
|
||||
assert( pPager->state>=PAGER_SHARED );
|
||||
assert( pPager->dbSize>=0 );
|
||||
TRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
|
||||
if( MEMDB ){
|
||||
|
|
|
@ -75,7 +75,7 @@ void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
|
|||
void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
|
||||
void sqlite3pager_set_reiniter(Pager*, void(*)(void*,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);
|
||||
int sqlite3pager_close(Pager *pPager);
|
||||
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -104,7 +104,7 @@ explain ::= . { sqlite3BeginParse(pParse, 0); }
|
|||
%ifndef SQLITE_OMIT_EXPLAIN
|
||||
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
|
||||
explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); }
|
||||
%endif
|
||||
%endif SQLITE_OMIT_EXPLAIN
|
||||
|
||||
///////////////////// Begin and end transactions. ////////////////////////////
|
||||
//
|
||||
|
@ -134,7 +134,7 @@ ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
|
|||
%type temp {int}
|
||||
%ifndef SQLITE_OMIT_TEMPDB
|
||||
temp(A) ::= TEMP. {A = 1;}
|
||||
%endif
|
||||
%endif SQLITE_OMIT_TEMPDB
|
||||
temp(A) ::= . {A = 0;}
|
||||
create_table_args ::= LP columnlist conslist_opt(X) RP(Y). {
|
||||
sqlite3EndTable(pParse,&X,&Y,0);
|
||||
|
@ -179,7 +179,7 @@ id(A) ::= ID(X). {A = X;}
|
|||
TEMP TRIGGER VACUUM VIEW VIRTUAL
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
%endif
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
%wildcard ANY.
|
||||
|
@ -249,14 +249,14 @@ carglist ::= carglist carg.
|
|||
carglist ::= .
|
||||
carg ::= CONSTRAINT nm ccons.
|
||||
carg ::= ccons.
|
||||
carg ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
|
||||
carg ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
|
||||
carg ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
|
||||
carg ::= DEFAULT MINUS term(X). {
|
||||
ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
|
||||
ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
|
||||
ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
|
||||
ccons ::= DEFAULT MINUS term(X). {
|
||||
Expr *p = sqlite3Expr(TK_UMINUS, X, 0, 0);
|
||||
sqlite3AddDefaultValue(pParse,p);
|
||||
}
|
||||
carg ::= DEFAULT id(X). {
|
||||
ccons ::= DEFAULT id(X). {
|
||||
Expr *p = sqlite3Expr(TK_STRING, 0, 0, &X);
|
||||
sqlite3AddDefaultValue(pParse,p);
|
||||
}
|
||||
|
@ -355,13 +355,13 @@ ifexists(A) ::= . {A = 0;}
|
|||
///////////////////// The CREATE VIEW statement /////////////////////////////
|
||||
//
|
||||
%ifndef SQLITE_OMIT_VIEW
|
||||
cmd ::= CREATE(X) temp(T) VIEW nm(Y) dbnm(Z) AS select(S). {
|
||||
sqlite3CreateView(pParse, &X, &Y, &Z, S, T);
|
||||
cmd ::= CREATE(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
|
||||
sqlite3CreateView(pParse, &X, &Y, &Z, S, T, E);
|
||||
}
|
||||
cmd ::= DROP VIEW ifexists(E) fullname(X). {
|
||||
sqlite3DropTable(pParse, X, 1, E);
|
||||
}
|
||||
%endif // SQLITE_OMIT_VIEW
|
||||
%endif SQLITE_OMIT_VIEW
|
||||
|
||||
//////////////////////// The SELECT statement /////////////////////////////////
|
||||
//
|
||||
|
@ -388,7 +388,7 @@ select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
|
|||
multiselect_op(A) ::= UNION(OP). {A = @OP;}
|
||||
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
|
||||
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
|
||||
%endif // SQLITE_OMIT_COMPOUND_SELECT
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
|
||||
A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
|
||||
|
@ -444,7 +444,10 @@ as(X) ::= . {X.n = 0;}
|
|||
// A complete FROM clause.
|
||||
//
|
||||
from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
|
||||
from(A) ::= FROM seltablist(X). {A = X;}
|
||||
from(A) ::= FROM seltablist(X). {
|
||||
A = X;
|
||||
sqlite3SrcListShiftJoinType(A);
|
||||
}
|
||||
|
||||
// "seltablist" is a "Select Table List" - the content of the FROM clause
|
||||
// in a SELECT statement. "stl_prefix" is a prefix of this list.
|
||||
|
@ -455,31 +458,12 @@ stl_prefix(A) ::= seltablist(X) joinop(Y). {
|
|||
}
|
||||
stl_prefix(A) ::= . {A = 0;}
|
||||
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppend(X,&Y,&D);
|
||||
if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
|
||||
if( N ){
|
||||
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
|
||||
else { sqlite3ExprDelete(N); }
|
||||
}
|
||||
if( U ){
|
||||
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
|
||||
else { sqlite3IdListDelete(U); }
|
||||
}
|
||||
A = sqlite3SrcListAppendFromTerm(X,&Y,&D,&Z,0,N,U);
|
||||
}
|
||||
%ifndef SQLITE_OMIT_SUBQUERY
|
||||
seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
|
||||
as(Z) on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppend(X,0,0);
|
||||
if( A && A->nSrc>0 ) A->a[A->nSrc-1].pSelect = S;
|
||||
if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
|
||||
if( N ){
|
||||
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
|
||||
else { sqlite3ExprDelete(N); }
|
||||
}
|
||||
if( U ){
|
||||
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
|
||||
else { sqlite3IdListDelete(U); }
|
||||
}
|
||||
A = sqlite3SrcListAppendFromTerm(X,0,0,&Z,S,N,U);
|
||||
}
|
||||
|
||||
// A seltablist_paren nonterminal represents anything in a FROM that
|
||||
|
@ -490,9 +474,10 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
|
|||
%destructor seltablist_paren {sqlite3SelectDelete($$);}
|
||||
seltablist_paren(A) ::= select(S). {A = S;}
|
||||
seltablist_paren(A) ::= seltablist(F). {
|
||||
sqlite3SrcListShiftJoinType(F);
|
||||
A = sqlite3SelectNew(0,F,0,0,0,0,0,0,0);
|
||||
}
|
||||
%endif // SQLITE_OMIT_SUBQUERY
|
||||
%endif SQLITE_OMIT_SUBQUERY
|
||||
|
||||
%type dbnm {Token}
|
||||
dbnm(A) ::= . {A.z=0; A.n=0;}
|
||||
|
@ -600,6 +585,8 @@ cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F)
|
|||
{sqlite3Insert(pParse, X, Y, 0, F, R);}
|
||||
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S).
|
||||
{sqlite3Insert(pParse, X, 0, S, F, R);}
|
||||
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
|
||||
{sqlite3Insert(pParse, X, 0, 0, F, R);}
|
||||
|
||||
%type insert_cmd {int}
|
||||
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
|
||||
|
@ -660,7 +647,7 @@ expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
|
|||
A = sqlite3Expr(TK_CAST, E, 0, &T);
|
||||
sqlite3ExprSpan(A,&X,&Y);
|
||||
}
|
||||
%endif // SQLITE_OMIT_CAST
|
||||
%endif SQLITE_OMIT_CAST
|
||||
expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
|
||||
A = sqlite3ExprFunction(Y, &X);
|
||||
sqlite3ExprSpan(A,&X,&E);
|
||||
|
@ -676,7 +663,10 @@ term(A) ::= CTIME_KW(OP). {
|
|||
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
|
||||
** treated as functions that return constants */
|
||||
A = sqlite3ExprFunction(0,&OP);
|
||||
if( A ) A->op = TK_CONST_FUNC;
|
||||
if( A ){
|
||||
A->op = TK_CONST_FUNC;
|
||||
A->span = OP;
|
||||
}
|
||||
}
|
||||
expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
|
||||
expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
|
||||
|
@ -805,7 +795,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||
sqlite3SelectDelete(Y);
|
||||
}
|
||||
}
|
||||
%endif // SQLITE_OMIT_SUBQUERY
|
||||
%endif SQLITE_OMIT_SUBQUERY
|
||||
|
||||
/* CASE expressions */
|
||||
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
|
||||
|
@ -894,21 +884,24 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
|
|||
|
||||
///////////////////////////// The VACUUM command /////////////////////////////
|
||||
//
|
||||
%ifndef SQLITE_OMIT_VACUUM
|
||||
cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
|
||||
cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
|
||||
%endif SQLITE_OMIT_VACUUM
|
||||
|
||||
///////////////////////////// The PRAGMA command /////////////////////////////
|
||||
//
|
||||
%ifndef SQLITE_OMIT_PRAGMA
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nm(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) EQ plus_num(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
|
||||
sqlite3Pragma(pParse,&X,&Z,&Y,1);
|
||||
}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) LP nm(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
|
||||
%endif // SQLITE_OMIT_PRAGMA
|
||||
nmnum(A) ::= plus_num(X). {A = X;}
|
||||
nmnum(A) ::= nm(X). {A = X;}
|
||||
%endif SQLITE_OMIT_PRAGMA
|
||||
plus_num(A) ::= plus_opt number(X). {A = X;}
|
||||
minus_num(A) ::= MINUS number(X). {A = X;}
|
||||
number(A) ::= INTEGER|FLOAT(X). {A = X;}
|
||||
|
@ -926,10 +919,10 @@ cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
|
|||
sqlite3FinishTrigger(pParse, S, &all);
|
||||
}
|
||||
|
||||
trigger_decl(A) ::= temp(T) TRIGGER nm(B) dbnm(Z) trigger_time(C)
|
||||
trigger_event(D)
|
||||
trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z)
|
||||
trigger_time(C) trigger_event(D)
|
||||
ON fullname(E) foreach_clause(F) when_clause(G). {
|
||||
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T);
|
||||
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T, NOERR);
|
||||
A = (Z.n==0?B:Z);
|
||||
}
|
||||
|
||||
|
@ -1004,7 +997,7 @@ expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
|
|||
sqlite3ExprSpan(A, &X, &Y);
|
||||
}
|
||||
}
|
||||
%endif // !SQLITE_OMIT_TRIGGER
|
||||
%endif !SQLITE_OMIT_TRIGGER
|
||||
|
||||
%type raisetype {int}
|
||||
raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
|
||||
|
@ -1014,10 +1007,10 @@ raisetype(A) ::= FAIL. {A = OE_Fail;}
|
|||
|
||||
//////////////////////// DROP TRIGGER statement //////////////////////////////
|
||||
%ifndef SQLITE_OMIT_TRIGGER
|
||||
cmd ::= DROP TRIGGER fullname(X). {
|
||||
sqlite3DropTrigger(pParse,X);
|
||||
cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
|
||||
sqlite3DropTrigger(pParse,X,NOERR);
|
||||
}
|
||||
%endif // !SQLITE_OMIT_TRIGGER
|
||||
%endif !SQLITE_OMIT_TRIGGER
|
||||
|
||||
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
|
||||
cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
|
||||
|
@ -1040,7 +1033,7 @@ cmd ::= DETACH database_kw_opt expr(D). {
|
|||
%ifndef SQLITE_OMIT_REINDEX
|
||||
cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);}
|
||||
cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);}
|
||||
%endif
|
||||
%endif SQLITE_OMIT_REINDEX
|
||||
|
||||
/////////////////////////////////// ANALYZE ///////////////////////////////////
|
||||
%ifndef SQLITE_OMIT_ANALYZE
|
||||
|
@ -1061,7 +1054,7 @@ add_column_fullname ::= fullname(X). {
|
|||
}
|
||||
kwcolumn_opt ::= .
|
||||
kwcolumn_opt ::= COLUMNKW.
|
||||
%endif
|
||||
%endif SQLITE_OMIT_ALTERTABLE
|
||||
|
||||
//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
|
||||
%ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
@ -1079,4 +1072,4 @@ vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);}
|
|||
lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);}
|
||||
anylist ::= .
|
||||
anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
|
||||
%endif
|
||||
%endif SQLITE_OMIT_VIRTUALTABLE
|
||||
|
|
|
@ -482,12 +482,17 @@ void sqlite3Pragma(
|
|||
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC);
|
||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
const Token *pDflt;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
pCol->zType ? pCol->zType : "", 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_Callback, 6, 0);
|
||||
}
|
||||
|
@ -635,9 +640,13 @@ void sqlite3Pragma(
|
|||
}
|
||||
}else
|
||||
|
||||
#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
|
||||
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
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
|
||||
** messages have been generated, output OK. Otherwise output the
|
||||
|
@ -655,7 +664,16 @@ void sqlite3Pragma(
|
|||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
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 */
|
||||
for(i=0; i<db->nDb; i++){
|
||||
|
@ -666,6 +684,9 @@ void sqlite3Pragma(
|
|||
if( OMIT_TEMPDB && i==1 ) continue;
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -680,28 +701,28 @@ void sqlite3Pragma(
|
|||
cnt++;
|
||||
}
|
||||
}
|
||||
assert( cnt>0 );
|
||||
sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
|
||||
addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
|
||||
if( cnt==0 ) continue;
|
||||
sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i);
|
||||
addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
|
||||
P3_DYNAMIC);
|
||||
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_MemIncr, 1, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
/* Make sure all the indices are constructed correctly.
|
||||
*/
|
||||
sqlite3CodeVerifySchema(pParse, i);
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
int loopTop;
|
||||
|
||||
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);
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
|
||||
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
|
||||
|
@ -709,7 +730,7 @@ void sqlite3Pragma(
|
|||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int jmp2;
|
||||
static const VdbeOpList idxErr[] = {
|
||||
{ OP_MemIncr, 1, 0, 0},
|
||||
{ OP_MemIncr, -1, 0, 0},
|
||||
{ OP_String8, 0, 0, "rowid "},
|
||||
{ OP_Rowid, 1, 0, 0},
|
||||
{ OP_String8, 0, 0, " missing from index "},
|
||||
|
@ -734,13 +755,16 @@ void sqlite3Pragma(
|
|||
{ OP_MemLoad, 1, 0, 0},
|
||||
{ OP_MemLoad, 2, 0, 0},
|
||||
{ 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, 0}, /* 9 */
|
||||
{ OP_Concat, 0, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
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);
|
||||
sqlite3VdbeChangeP1(v, addr+1, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+1, addr+4);
|
||||
|
@ -752,6 +776,7 @@ void sqlite3Pragma(
|
|||
}
|
||||
}
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||
sqlite3VdbeChangeP1(v, addr+1, mxErr);
|
||||
sqlite3VdbeJumpHere(v, addr+2);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
|
@ -889,6 +914,7 @@ void sqlite3Pragma(
|
|||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
sqlite3VdbeChangeP2(v, addr, iCookie);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, P3_TRANSIENT);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
|
||||
|
@ -940,6 +966,22 @@ void sqlite3Pragma(
|
|||
sqlite3_key(db, zRight, strlen(zRight));
|
||||
}else
|
||||
#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
|
||||
|
||||
{}
|
||||
|
||||
|
|
|
@ -41,28 +41,26 @@ static void corruptSchema(InitData *pData, const char *zExtra){
|
|||
** argv[0] = name of thing being created
|
||||
** argv[1] = root page number for table or index. 0 for trigger or view.
|
||||
** 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){
|
||||
InitData *pData = (InitData*)pInit;
|
||||
sqlite3 *db = pData->db;
|
||||
int iDb;
|
||||
int iDb = pData->iDb;
|
||||
|
||||
pData->rc = SQLITE_OK;
|
||||
DbClearProperty(db, iDb, DB_Empty);
|
||||
if( sqlite3MallocFailed() ){
|
||||
corruptSchema(pData, 0);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
assert( argc==4 );
|
||||
assert( argc==3 );
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
iDb = atoi(argv[3]);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
if( argv[2] && argv[2][0] ){
|
||||
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
||||
|
@ -125,8 +123,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||
int size;
|
||||
Table *pTab;
|
||||
Db *pDb;
|
||||
char const *azArg[5];
|
||||
char zDbNum[30];
|
||||
char const *azArg[4];
|
||||
int meta[10];
|
||||
InitData initData;
|
||||
char const *zMasterSchema;
|
||||
|
@ -177,12 +174,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||
azArg[0] = zMasterName;
|
||||
azArg[1] = "1";
|
||||
azArg[2] = zMasterSchema;
|
||||
sprintf(zDbNum, "%d", iDb);
|
||||
azArg[3] = zDbNum;
|
||||
azArg[4] = 0;
|
||||
azArg[3] = 0;
|
||||
initData.db = db;
|
||||
initData.iDb = iDb;
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0);
|
||||
rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
|
||||
if( rc ){
|
||||
sqlite3SafetyOn(db);
|
||||
return initData.rc;
|
||||
|
@ -295,8 +291,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||
}else{
|
||||
char *zSql;
|
||||
zSql = sqlite3MPrintf(
|
||||
"SELECT name, rootpage, sql, '%s' FROM '%q'.%s",
|
||||
zDbNum, db->aDb[iDb].zName, zMasterName);
|
||||
"SELECT name, rootpage, sql FROM '%q'.%s",
|
||||
db->aDb[iDb].zName, zMasterName);
|
||||
sqlite3SafetyOff(db);
|
||||
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
|
||||
if( rc==SQLITE_ABORT ) rc = initData.rc;
|
||||
|
@ -449,12 +445,13 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
|||
/*
|
||||
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
int sqlite3_prepare(
|
||||
int sqlite3Prepare(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const char *zSql, /* UTF-8 encoded SQL statement. */
|
||||
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 */
|
||||
const char** pzTail /* OUT: End of parsed string */
|
||||
const char **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
Parse sParse;
|
||||
char *zErrMsg = 0;
|
||||
|
@ -507,7 +504,9 @@ int sqlite3_prepare(
|
|||
if( sqlite3MallocFailed() ){
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( pzTail ) *pzTail = sParse.zTail;
|
||||
if( pzTail ){
|
||||
*pzTail = sParse.zTail;
|
||||
}
|
||||
rc = sParse.rc;
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
|
@ -525,13 +524,16 @@ int sqlite3_prepare(
|
|||
sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( sqlite3SafetyOff(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
if( saveSqlFlag ){
|
||||
sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql);
|
||||
}
|
||||
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
|
||||
}else if( sParse.pVdbe ){
|
||||
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
|
||||
|
@ -546,17 +548,78 @@ int sqlite3_prepare(
|
|||
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3ReleaseThreadData();
|
||||
assert( (rc&db->errMask)==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
|
||||
/*
|
||||
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
int sqlite3_prepare16(
|
||||
static int sqlite3Prepare16(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const void *zSql, /* UTF-8 encoded SQL statement. */
|
||||
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 */
|
||||
const void **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
|
@ -573,7 +636,7 @@ int sqlite3_prepare16(
|
|||
}
|
||||
zSql8 = sqlite3utf16to8(zSql, nBytes);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
|
||||
rc = sqlite3Prepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8);
|
||||
}
|
||||
|
||||
if( zTail8 && pzTail ){
|
||||
|
@ -588,4 +651,32 @@ int sqlite3_prepare16(
|
|||
sqliteFree(zSql8);
|
||||
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 */
|
||||
|
|
|
@ -857,7 +857,7 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
|
|||
va_start(ap, zFormat);
|
||||
base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
|
||||
va_end(ap);
|
||||
fprintf(stdout,"%d: %s", getpid(), zBuf);
|
||||
fprintf(stdout,"%s", zBuf);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
** (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.
|
||||
*/
|
||||
static int randomByte(){
|
||||
static int randomByte(void){
|
||||
unsigned char t;
|
||||
|
||||
/* All threads share a single random number generator.
|
||||
|
|
|
@ -299,8 +299,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
|||
/* When the NATURAL keyword is present, add WHERE clause terms for
|
||||
** every column that the two tables have in common.
|
||||
*/
|
||||
if( pLeft->jointype & JT_NATURAL ){
|
||||
if( pLeft->pOn || pLeft->pUsing ){
|
||||
if( pRight->jointype & JT_NATURAL ){
|
||||
if( pRight->pOn || pRight->pUsing ){
|
||||
sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
|
||||
"an ON or USING clause", 0);
|
||||
return 1;
|
||||
|
@ -318,7 +318,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
|||
|
||||
/* 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 "
|
||||
"clauses in the same join");
|
||||
return 1;
|
||||
|
@ -327,10 +327,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
|||
/* Add the ON clause to the end of the WHERE clause, connected by
|
||||
** an AND operator.
|
||||
*/
|
||||
if( pLeft->pOn ){
|
||||
setJoinExpr(pLeft->pOn, pRight->iCursor);
|
||||
p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn);
|
||||
pLeft->pOn = 0;
|
||||
if( pRight->pOn ){
|
||||
setJoinExpr(pRight->pOn, pRight->iCursor);
|
||||
p->pWhere = sqlite3ExprAnd(p->pWhere, pRight->pOn);
|
||||
pRight->pOn = 0;
|
||||
}
|
||||
|
||||
/* Create extra terms on the WHERE clause for each column named
|
||||
|
@ -340,8 +340,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
|||
** Report an error if any column mentioned in the USING clause is
|
||||
** not contained in both tables to be joined.
|
||||
*/
|
||||
if( pLeft->pUsing ){
|
||||
IdList *pList = pLeft->pUsing;
|
||||
if( pRight->pUsing ){
|
||||
IdList *pList = pRight->pUsing;
|
||||
for(j=0; j<pList->nId; j++){
|
||||
char *zName = pList->a[j].zName;
|
||||
if( columnIndex(pLeftTab, zName)<0 || columnIndex(pRightTab, zName)<0 ){
|
||||
|
@ -1069,7 +1069,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
|||
Expr *p, *pR;
|
||||
char *zType;
|
||||
char *zName;
|
||||
char *zBasename;
|
||||
int nName;
|
||||
CollSeq *pColl;
|
||||
int cnt;
|
||||
NameContext sNC;
|
||||
|
@ -1102,17 +1102,15 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
|||
/* Make sure the column name is unique. If the name is not unique,
|
||||
** append a integer to the name so that it becomes unique.
|
||||
*/
|
||||
zBasename = zName;
|
||||
nName = strlen(zName);
|
||||
for(j=cnt=0; j<i; j++){
|
||||
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
|
||||
zName = sqlite3MPrintf("%s:%d", zBasename, ++cnt);
|
||||
zName[nName] = 0;
|
||||
zName = sqlite3MPrintf("%z:%d", zName, ++cnt);
|
||||
j = -1;
|
||||
if( zName==0 ) break;
|
||||
}
|
||||
}
|
||||
if( zBasename!=zName ){
|
||||
sqliteFree(zBasename);
|
||||
}
|
||||
pCol->zName = zName;
|
||||
|
||||
/* Get the typename, type affinity, and collating sequence for the
|
||||
|
@ -1309,13 +1307,13 @@ static int prepSelectStmt(Parse *pParse, Select *p){
|
|||
|
||||
if( i>0 ){
|
||||
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 ){
|
||||
/* In a NATURAL join, omit the join columns from the
|
||||
** table on the right */
|
||||
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
|
||||
** using clause from the table on the right. */
|
||||
continue;
|
||||
|
@ -1936,6 +1934,7 @@ static int multiSelect(
|
|||
}
|
||||
sqlite3VdbeChangeP2(v, addr, nCol);
|
||||
sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO);
|
||||
pLoop->addrOpenEphm[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2175,7 +2174,7 @@ static int flattenSubquery(
|
|||
**
|
||||
** which is not at all the same thing.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2192,8 +2191,7 @@ static int flattenSubquery(
|
|||
** 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.
|
||||
*/
|
||||
if( iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0
|
||||
&& pSub->pWhere!=0 ){
|
||||
if( (pSubitem->jointype & JT_OUTER)!=0 && pSub->pWhere!=0 ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2232,7 +2230,7 @@ static int flattenSubquery(
|
|||
pSrc->a[i+iFrom] = 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
|
||||
|
@ -2605,7 +2603,14 @@ int sqlite3SelectResolve(
|
|||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3293,3 +3298,99 @@ select_end:
|
|||
sqliteFree(sAggInfo.aFunc);
|
||||
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) */
|
||||
|
|
|
@ -52,9 +52,25 @@
|
|||
# define stifle_history(X)
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
# include <io.h>
|
||||
#else
|
||||
/* Make sure isatty() has a prototype.
|
||||
*/
|
||||
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
|
||||
|
@ -180,10 +196,7 @@ static char *local_getline(char *zPrompt, FILE *in){
|
|||
}
|
||||
|
||||
/*
|
||||
** Retrieve a single line of input text. "isatty" is true if 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.
|
||||
** Retrieve a single line of input text.
|
||||
**
|
||||
** zPrior is a string of prior text retrieved. If not the empty
|
||||
** string, then issue a continuation prompt.
|
||||
|
@ -212,6 +225,7 @@ struct previous_mode_data {
|
|||
int showHeader;
|
||||
int colWidth[100];
|
||||
};
|
||||
|
||||
/*
|
||||
** An pointer to an instance of this structure is passed from
|
||||
** the main program to the callback. This is used to communicate
|
||||
|
@ -223,6 +237,7 @@ struct callback_data {
|
|||
int cnt; /* Number of records displayed so far */
|
||||
FILE *out; /* Write results here */
|
||||
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 */
|
||||
char *zDestTable; /* Name of destination table when MODE_Insert */
|
||||
char separator[20]; /* Separator character for MODE_List */
|
||||
|
@ -235,7 +250,6 @@ struct callback_data {
|
|||
** .explain ON */
|
||||
char outfile[FILENAME_MAX]; /* Filename for *out */
|
||||
const char *zDbFilename; /* name of the database file */
|
||||
char *zKey; /* Encryption key */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -347,6 +361,29 @@ static void output_html_string(FILE *out, const char *z){
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If a field contains any character identified by a 1 in the following
|
||||
** array, then the string must be quoted for CSV.
|
||||
*/
|
||||
static const char needCsvQuote[] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
/*
|
||||
** Output a single term of CSV. Actually, p->separator is used for
|
||||
** the separator, which may or may not be a comma. p->nullvalue is
|
||||
|
@ -354,12 +391,27 @@ static void output_html_string(FILE *out, const char *z){
|
|||
** appear outside of quotes.
|
||||
*/
|
||||
static void output_csv(struct callback_data *p, const char *z, int bSep){
|
||||
FILE *out = p->out;
|
||||
if( z==0 ){
|
||||
fprintf(p->out,"%s",p->nullvalue);
|
||||
}else if( isNumber(z, 0) ){
|
||||
fprintf(p->out,"%s",z);
|
||||
fprintf(out,"%s",p->nullvalue);
|
||||
}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 ){
|
||||
fprintf(p->out, p->separator);
|
||||
|
@ -584,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
|
||||
** 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 i;
|
||||
int nAppend = strlen(zAppend);
|
||||
|
@ -625,6 +677,9 @@ static char * appendText(char *zIn, char const *zAppend, char quote){
|
|||
/*
|
||||
** Execute a query statement that has a single result column. Print
|
||||
** 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){
|
||||
sqlite3_stmt *pSelect;
|
||||
|
@ -666,6 +721,19 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
|||
fprintf(p->out, "ANALYZE sqlite_master;\n");
|
||||
}else if( strncmp(zTable, "sqlite_", 7)==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{
|
||||
fprintf(p->out, "%s;\n", zSql);
|
||||
}
|
||||
|
@ -699,7 +767,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
|||
zSelect = appendText(zSelect, zText, '"');
|
||||
rc = sqlite3_step(pTableInfo);
|
||||
if( rc==SQLITE_ROW ){
|
||||
zSelect = appendText(zSelect, ") || ', ' || ", 0);
|
||||
zSelect = appendText(zSelect, ") || ',' || ", 0);
|
||||
}else{
|
||||
zSelect = appendText(zSelect, ") ", 0);
|
||||
}
|
||||
|
@ -718,15 +786,14 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
|||
rc = run_table_dump_query(p->out, p->db, zSelect);
|
||||
}
|
||||
if( zSelect ) free(zSelect);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
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
|
||||
** "ORDER BY rowid DESC" to the end.
|
||||
*/
|
||||
|
@ -754,6 +821,7 @@ static int run_schema_dump_query(
|
|||
** Text of a help message
|
||||
*/
|
||||
static char zHelp[] =
|
||||
".bail ON|OFF Stop after hitting an error. Default OFF\n"
|
||||
".databases List names and files of attached databases\n"
|
||||
".dump ?TABLE? ... Dump the database in an SQL text format\n"
|
||||
".echo ON|OFF Turn command echo on or off\n"
|
||||
|
@ -790,7 +858,7 @@ static char zHelp[] =
|
|||
;
|
||||
|
||||
/* 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
|
||||
|
@ -850,11 +918,28 @@ static void resolve_backslashes(char *z){
|
|||
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
|
||||
** 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){
|
||||
int i = 1;
|
||||
|
@ -889,6 +974,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
if( nArg==0 ) return rc;
|
||||
n = strlen(azArg[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 ){
|
||||
struct callback_data data;
|
||||
char *zErrMsg = 0;
|
||||
|
@ -911,14 +1000,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
char *zErrMsg = 0;
|
||||
open_db(p);
|
||||
fprintf(p->out, "BEGIN TRANSACTION;\n");
|
||||
p->writableSchema = 0;
|
||||
if( nArg==1 ){
|
||||
run_schema_dump_query(p,
|
||||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL AND type=='table'", 0
|
||||
);
|
||||
run_schema_dump_query(p,
|
||||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL AND type!='table' AND type!='meta'", 0
|
||||
run_table_dump_query(p->out, p->db,
|
||||
"SELECT sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL AND type IN ('index','trigger','view')"
|
||||
);
|
||||
}else{
|
||||
int i;
|
||||
|
@ -928,13 +1018,19 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE tbl_name LIKE shellstatic() AND type=='table'"
|
||||
" AND sql NOT NULL", 0);
|
||||
run_schema_dump_query(p,
|
||||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE tbl_name LIKE shellstatic() AND type!='table'"
|
||||
" AND type!='meta' AND sql NOT NULL", 0);
|
||||
run_table_dump_query(p->out, p->db,
|
||||
"SELECT sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL"
|
||||
" AND type IN ('index','trigger','view')"
|
||||
" AND tbl_name LIKE shellstatic()"
|
||||
);
|
||||
zShellStatic = 0;
|
||||
}
|
||||
}
|
||||
if( p->writableSchema ){
|
||||
fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
|
||||
p->writableSchema = 0;
|
||||
}
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr,"Error: %s\n", zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
|
@ -944,37 +1040,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
|
||||
int j;
|
||||
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;
|
||||
p->echoOn = booleanValue(azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
|
||||
rc = 1;
|
||||
rc = 2;
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
|
||||
int j;
|
||||
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;
|
||||
}
|
||||
int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
|
||||
if(val == 1) {
|
||||
if(!p->explainPrev.valid) {
|
||||
p->explainPrev.valid = 1;
|
||||
|
@ -1005,21 +1079,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
}
|
||||
}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 ){
|
||||
int j;
|
||||
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;
|
||||
p->showHeader = booleanValue(azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
|
||||
|
@ -1056,6 +1118,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
if( rc ){
|
||||
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
|
||||
nCol = 0;
|
||||
rc = 1;
|
||||
}else{
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
}
|
||||
|
@ -1076,7 +1139,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
if( rc ){
|
||||
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
in = fopen(zFile, "rb");
|
||||
if( in==0 ){
|
||||
|
@ -1122,6 +1185,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
if( rc!=SQLITE_OK ){
|
||||
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
|
||||
zCommit = "ROLLBACK";
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1167,6 +1231,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
if( rc!=SQLITE_OK ){
|
||||
fprintf(stderr, "%s\n", zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
rc = 1;
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
@ -1201,7 +1266,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
set_table_name(p, "table");
|
||||
}
|
||||
}else {
|
||||
fprintf(stderr,"mode should be on of: "
|
||||
fprintf(stderr,"mode should be one of: "
|
||||
"column csv html insert line list tabs tcl\n");
|
||||
}
|
||||
}else
|
||||
|
@ -1238,7 +1303,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
}else
|
||||
|
||||
if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
|
||||
rc = 1;
|
||||
rc = 2;
|
||||
}else
|
||||
|
||||
if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
|
||||
|
@ -1390,6 +1455,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
}
|
||||
printf("\n");
|
||||
}
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
sqlite3_free_table(azResult);
|
||||
}else
|
||||
|
@ -1469,24 +1536,40 @@ static int _is_command_terminator(const char *zLine){
|
|||
** is coming from a file or device. A prompt is issued and history
|
||||
** is saved only if input is interactive. An interrupt signal will
|
||||
** 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 *zSql = 0;
|
||||
int nSql = 0;
|
||||
char *zErrMsg;
|
||||
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( in!=0 ) break;
|
||||
seenInterrupt = 0;
|
||||
}
|
||||
lineno++;
|
||||
if( p->echoOn ) printf("%s\n", zLine);
|
||||
if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
|
||||
if( zLine && zLine[0]=='.' && nSql==0 ){
|
||||
int rc = do_meta_command(zLine, p);
|
||||
rc = do_meta_command(zLine, p);
|
||||
free(zLine);
|
||||
if( rc ) break;
|
||||
if( rc==2 ){
|
||||
break;
|
||||
}else if( rc ){
|
||||
errCnt++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if( _is_command_terminator(zLine) ){
|
||||
|
@ -1503,6 +1586,7 @@ static void process_input(struct callback_data *p, FILE *in){
|
|||
exit(1);
|
||||
}
|
||||
strcpy(zSql, zLine);
|
||||
startline = lineno;
|
||||
}
|
||||
}else{
|
||||
int len = strlen(zLine);
|
||||
|
@ -1521,14 +1605,20 @@ static void process_input(struct callback_data *p, FILE *in){
|
|||
open_db(p);
|
||||
rc = sqlite3_exec(p->db, zSql, callback, p, &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 ){
|
||||
printf("SQL error: %s\n", zErrMsg);
|
||||
printf("%s %s\n", zPrefix, zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
zErrMsg = 0;
|
||||
}else{
|
||||
printf("SQL error: %s\n", sqlite3_errmsg(p->db));
|
||||
printf("%s %s\n", zPrefix, sqlite3_errmsg(p->db));
|
||||
}
|
||||
errCnt++;
|
||||
}
|
||||
free(zSql);
|
||||
zSql = 0;
|
||||
|
@ -1539,6 +1629,7 @@ static void process_input(struct callback_data *p, FILE *in){
|
|||
if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
|
||||
free(zSql);
|
||||
}
|
||||
return errCnt;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1563,16 +1654,30 @@ static char *find_home_dir(void){
|
|||
home_dir = getcwd(home_path, _MAX_PATH);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
|
||||
if (!home_dir) {
|
||||
home_dir = getenv("USERPROFILE");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!home_dir) {
|
||||
home_dir = getenv("HOME");
|
||||
if (!home_dir) {
|
||||
home_dir = getenv("HOMEPATH"); /* Windows? */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
|
||||
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
|
||||
|
||||
|
@ -1615,7 +1720,7 @@ static void process_sqliterc(
|
|||
}
|
||||
in = fopen(sqliterc,"rb");
|
||||
if( in ){
|
||||
if( isatty(fileno(stdout)) ){
|
||||
if( stdin_is_interactive ){
|
||||
printf("Loading resources from %s\n",sqliterc);
|
||||
}
|
||||
process_input(p,in);
|
||||
|
@ -1632,19 +1737,25 @@ static const char zOptions[] =
|
|||
" -init filename read/process named file\n"
|
||||
" -echo print commands before execution\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"
|
||||
" -csv set output mode to 'csv'\n"
|
||||
" -html set output mode to HTML\n"
|
||||
" -line set output mode to 'line'\n"
|
||||
" -list set output mode to 'list'\n"
|
||||
" -separator 'x' set output field separator (|)\n"
|
||||
" -nullvalue 'text' set text string for NULL values\n"
|
||||
" -version show SQLite version\n"
|
||||
" -help show this text, also show dot-commands\n"
|
||||
;
|
||||
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 ){
|
||||
fprintf(stderr, "Options are:\n%s", zOptions);
|
||||
fprintf(stderr, "OPTIONS include:\n%s", zOptions);
|
||||
}else{
|
||||
fprintf(stderr, "Use the -help option for additional information\n");
|
||||
}
|
||||
|
@ -1669,6 +1780,7 @@ int main(int argc, char **argv){
|
|||
const char *zInitFile = 0;
|
||||
char *zFirstCmd = 0;
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
#ifdef __MACOS__
|
||||
argc = ccommand(&argv);
|
||||
|
@ -1676,6 +1788,7 @@ int main(int argc, char **argv){
|
|||
|
||||
Argv0 = argv[0];
|
||||
main_init(&data);
|
||||
stdin_is_interactive = isatty(0);
|
||||
|
||||
/* Make sure we have a valid signal handler early, before anything
|
||||
** else is done.
|
||||
|
@ -1689,15 +1802,15 @@ int main(int argc, char **argv){
|
|||
** and the first command to execute.
|
||||
*/
|
||||
for(i=1; i<argc-1; i++){
|
||||
char *z;
|
||||
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 ){
|
||||
i++;
|
||||
}else if( strcmp(argv[i],"-init")==0 ){
|
||||
i++;
|
||||
zInitFile = argv[i];
|
||||
}else if( strcmp(argv[i],"-key")==0 ){
|
||||
i++;
|
||||
data.zKey = sqlite3_mprintf("%s",argv[i]);
|
||||
}
|
||||
}
|
||||
if( i<argc ){
|
||||
|
@ -1743,7 +1856,8 @@ int main(int argc, char **argv){
|
|||
*/
|
||||
for(i=1; i<argc && argv[i][0]=='-'; i++){
|
||||
char *z = argv[i];
|
||||
if( strcmp(z,"-init")==0 || strcmp(z,"-key")==0 ){
|
||||
if( z[1]=='-' ){ z++; }
|
||||
if( strcmp(z,"-init")==0 ){
|
||||
i++;
|
||||
}else if( strcmp(z,"-html")==0 ){
|
||||
data.mode = MODE_Html;
|
||||
|
@ -1753,6 +1867,9 @@ int main(int argc, char **argv){
|
|||
data.mode = MODE_Line;
|
||||
}else if( strcmp(z,"-column")==0 ){
|
||||
data.mode = MODE_Column;
|
||||
}else if( strcmp(z,"-csv")==0 ){
|
||||
data.mode = MODE_Csv;
|
||||
strcpy(data.separator,",");
|
||||
}else if( strcmp(z,"-separator")==0 ){
|
||||
i++;
|
||||
sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
|
||||
|
@ -1765,10 +1882,16 @@ int main(int argc, char **argv){
|
|||
data.showHeader = 0;
|
||||
}else if( strcmp(z,"-echo")==0 ){
|
||||
data.echoOn = 1;
|
||||
}else if( strcmp(z,"-bail")==0 ){
|
||||
bail_on_error = 1;
|
||||
}else if( strcmp(z,"-version")==0 ){
|
||||
printf("%s\n", sqlite3_libversion());
|
||||
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);
|
||||
}else{
|
||||
fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
|
||||
|
@ -1795,7 +1918,7 @@ int main(int argc, char **argv){
|
|||
}else{
|
||||
/* Run commands received from standard input
|
||||
*/
|
||||
if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){
|
||||
if( stdin_is_interactive ){
|
||||
char *zHome;
|
||||
char *zHistory = 0;
|
||||
printf(
|
||||
|
@ -1810,7 +1933,7 @@ int main(int argc, char **argv){
|
|||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
if( zHistory ) read_history(zHistory);
|
||||
#endif
|
||||
process_input(&data, 0);
|
||||
rc = process_input(&data, 0);
|
||||
if( zHistory ){
|
||||
stifle_history(100);
|
||||
write_history(zHistory);
|
||||
|
@ -1818,7 +1941,7 @@ int main(int argc, char **argv){
|
|||
}
|
||||
free(zHome);
|
||||
}else{
|
||||
process_input(&data, stdin);
|
||||
rc = process_input(&data, stdin);
|
||||
}
|
||||
}
|
||||
set_table_name(&data, 0);
|
||||
|
@ -1827,5 +1950,5 @@ int main(int argc, char **argv){
|
|||
fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
|||
** value then the query is aborted, all subsequent SQL statements
|
||||
** 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.
|
||||
**
|
||||
** 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 */
|
||||
/* 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
|
||||
** 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
|
||||
** is NULL, then sqlite3_exec() returns SQLITE_BUSY immediately if
|
||||
** it finds a locked table. If the busy callback is not NULL, then
|
||||
** sqlite3_exec() invokes the callback with three arguments. The
|
||||
** second argument is the name of the locked table and the third
|
||||
** argument is the number of times the table has been busy. If the
|
||||
** sqlite3_exec() invokes the callback with two arguments. The
|
||||
** first argument to the handler is a copy of the void* pointer which
|
||||
** 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
|
||||
** SQLITE_BUSY. If the callback returns non-zero, then sqlite3_exec()
|
||||
** 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.
|
||||
**
|
||||
** Sqlite is re-entrant, so the busy handler may start a new query.
|
||||
|
@ -478,6 +533,7 @@ int sqlite3_set_authorizer(
|
|||
#define SQLITE_ANALYZE 28 /* Table Name NULL */
|
||||
#define SQLITE_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
|
||||
|
@ -653,6 +709,31 @@ int sqlite3_prepare16(
|
|||
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
|
||||
** with the implementations of user-defined functions.
|
||||
|
@ -1104,9 +1185,13 @@ void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
|
|||
** SQLITE_TRANSIENT value means that the content will likely change in
|
||||
** the near future and that SQLite should make its own private copy of
|
||||
** 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)
|
||||
#define SQLITE_TRANSIENT ((void(*)(void *))-1)
|
||||
typedef void (*sqlite3_destructor_type)(void*);
|
||||
#define SQLITE_STATIC ((sqlite3_destructor_type)0)
|
||||
#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
|
||||
|
||||
/*
|
||||
** User-defined functions invoke the following routines in order to
|
||||
|
@ -1517,6 +1602,42 @@ int sqlite3_load_extension(
|
|||
*/
|
||||
int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
|
||||
|
||||
/*
|
||||
****** 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 **************
|
||||
**
|
||||
|
@ -1544,11 +1665,11 @@ typedef struct sqlite3_module sqlite3_module;
|
|||
struct sqlite3_module {
|
||||
int iVersion;
|
||||
int (*xCreate)(sqlite3*, void *pAux,
|
||||
int argc, char **argv,
|
||||
sqlite3_vtab **ppVTab);
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVTab, char**);
|
||||
int (*xConnect)(sqlite3*, void *pAux,
|
||||
int argc, char **argv,
|
||||
sqlite3_vtab **ppVTab);
|
||||
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);
|
||||
|
@ -1668,10 +1789,21 @@ int sqlite3_create_module(
|
|||
** 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 */
|
||||
};
|
||||
|
||||
|
@ -1696,6 +1828,24 @@ struct sqlite3_vtab_cursor {
|
|||
*/
|
||||
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
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
#ifndef _SQLITE3EXT_H_
|
||||
#define _SQLITE3EXT_H_
|
||||
#include <sqlite3.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
|
||||
|
@ -92,7 +92,7 @@ struct sqlite3_api_routines {
|
|||
void * (*get_auxdata)(sqlite3_context*,int);
|
||||
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||
int (*global_recover)(void);
|
||||
void (*interrupt)(sqlite3*);
|
||||
void (*interruptx)(sqlite3*);
|
||||
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||
const char * (*libversion)(void);
|
||||
int (*libversion_number)(void);
|
||||
|
@ -143,6 +143,7 @@ struct sqlite3_api_routines {
|
|||
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);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -221,7 +222,7 @@ struct sqlite3_api_routines {
|
|||
#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->interrupt
|
||||
#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
|
||||
|
@ -272,6 +273,7 @@ struct sqlite3_api_routines {
|
|||
#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;
|
||||
|
|
|
@ -447,6 +447,7 @@ struct sqlite3 {
|
|||
Db *aDb; /* All backends */
|
||||
int flags; /* Miscellanous flags. See below */
|
||||
int errCode; /* Most recent error code (SQLITE_*) */
|
||||
int errMask; /* & result codes with this before returning */
|
||||
u8 autoCommit; /* The auto-commit flag. */
|
||||
u8 temp_store; /* 1: file 2: memory 0: default */
|
||||
int nTable; /* Number of tables in the database */
|
||||
|
@ -462,7 +463,7 @@ struct sqlite3 {
|
|||
u8 busy; /* TRUE if currently initializing */
|
||||
} init;
|
||||
int nExtension; /* Number of loaded extensions */
|
||||
void *aExtension; /* Array of shared libraray handles */
|
||||
void **aExtension; /* Array of shared libraray handles */
|
||||
struct Vdbe *pVdbe; /* List of active virtual machines */
|
||||
int activeVdbeCnt; /* Number of vdbes currently executing */
|
||||
void (*xTrace)(void*,const char*); /* Trace function */
|
||||
|
@ -1090,6 +1091,11 @@ typedef unsigned int Bitmask;
|
|||
** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
|
||||
** 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.
|
||||
**
|
||||
** 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 {
|
||||
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||
|
@ -1101,7 +1107,7 @@ struct SrcList {
|
|||
Table *pTab; /* An SQL table corresponding to zName */
|
||||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
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 */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
|
@ -1512,6 +1518,7 @@ struct DbFixer {
|
|||
*/
|
||||
typedef struct {
|
||||
sqlite3 *db; /* The database being initialized */
|
||||
int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
|
||||
char **pzErrMsg; /* Error message stored here */
|
||||
int rc; /* Result code stored here */
|
||||
} InitData;
|
||||
|
@ -1600,7 +1607,7 @@ void sqlite3AddDefaultValue(Parse*,Expr*);
|
|||
void sqlite3AddCollateType(Parse*, const char*, int);
|
||||
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||
|
||||
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
|
||||
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
int sqlite3ViewGetColumnNames(Parse*,Table*);
|
||||
|
@ -1615,7 +1622,9 @@ int sqlite3ArrayAllocate(void**,int,int);
|
|||
IdList *sqlite3IdListAppend(IdList*, Token*);
|
||||
int sqlite3IdListIndex(IdList*,const char*);
|
||||
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 sqlite3IdListDelete(IdList*);
|
||||
void sqlite3SrcListDelete(SrcList*);
|
||||
|
@ -1691,9 +1700,9 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
|
|||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
|
||||
int,Expr*,int);
|
||||
int,Expr*,int, int);
|
||||
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
|
||||
void sqlite3DropTrigger(Parse*, SrcList*);
|
||||
void sqlite3DropTrigger(Parse*, SrcList*, int);
|
||||
void sqlite3DropTriggerPtr(Parse*, Trigger*);
|
||||
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
|
||||
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
|
||||
|
@ -1821,8 +1830,10 @@ 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
|
||||
|
@ -1860,6 +1871,8 @@ int sqlite3OpenTempDatabase(Parse *);
|
|||
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*);
|
||||
|
@ -1869,6 +1882,8 @@ 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
|
||||
#include "sseInt.h"
|
||||
|
|
|
@ -146,7 +146,7 @@ int sqlite3_get_table(
|
|||
assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
|
||||
res.azResult[0] = (char*)res.nData;
|
||||
}
|
||||
if( rc==SQLITE_ABORT ){
|
||||
if( (rc&0xff)==SQLITE_ABORT ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
if( res.zErrMsg ){
|
||||
if( pzErrMsg ){
|
||||
|
@ -156,12 +156,12 @@ int sqlite3_get_table(
|
|||
sqliteFree(res.zErrMsg);
|
||||
}
|
||||
db->errCode = res.rc;
|
||||
return res.rc;
|
||||
return res.rc & db->errMask;
|
||||
}
|
||||
sqliteFree(res.zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
return rc;
|
||||
return rc & db->errMask;
|
||||
}
|
||||
if( res.nAlloc>res.nData ){
|
||||
char **azNew;
|
||||
|
@ -176,7 +176,7 @@ int sqlite3_get_table(
|
|||
*pazResult = &res.azResult[1];
|
||||
if( pnColumn ) *pnColumn = res.nColumn;
|
||||
if( pnRow ) *pnRow = res.nRow;
|
||||
return rc;
|
||||
return rc & db->errMask;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -553,6 +553,7 @@ static int auth_callback(
|
|||
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;
|
||||
}
|
||||
Tcl_DStringInit(&str);
|
||||
|
@ -1035,7 +1036,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
nSep = strlen(zSep);
|
||||
nNull = strlen(zNull);
|
||||
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;
|
||||
}
|
||||
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
|
||||
|
@ -1172,6 +1173,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
** default.
|
||||
*/
|
||||
case DB_ENABLE_LOAD_EXTENSION: {
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
int onoff;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
|
||||
|
@ -1182,6 +1184,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}
|
||||
sqlite3_enable_load_extension(pDb->db, onoff);
|
||||
break;
|
||||
#else
|
||||
Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
|
||||
0);
|
||||
return TCL_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2001,6 +2008,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
const char *zArg;
|
||||
char *zErrMsg;
|
||||
const char *zFile;
|
||||
Tcl_DString translatedFilename;
|
||||
if( objc==2 ){
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
if( strcmp(zArg,"-version")==0 ){
|
||||
|
@ -2049,9 +2057,11 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}
|
||||
memset(p, 0, sizeof(*p));
|
||||
zFile = Tcl_GetStringFromObj(objv[2], 0);
|
||||
zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
|
||||
sqlite3_open(zFile, &p->db);
|
||||
Tcl_DStringFree(&translatedFilename);
|
||||
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);
|
||||
p->db = 0;
|
||||
}
|
||||
|
@ -2061,10 +2071,11 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
if( p->db==0 ){
|
||||
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
|
||||
Tcl_Free((char*)p);
|
||||
free(zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p->maxStmt = NUM_PREPARED_STMTS;
|
||||
p->interp = interp;
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
|
||||
|
||||
|
@ -2084,7 +2095,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
#endif
|
||||
}
|
||||
#endif
|
||||
p->interp = interp;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -2200,6 +2210,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
|||
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);
|
||||
Sqlitetest2_Init(interp);
|
||||
|
@ -2212,6 +2223,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
|||
Sqlitetestasync_Init(interp);
|
||||
Sqlitetesttclvar_Init(interp);
|
||||
Sqlitetestschema_Init(interp);
|
||||
Sqlitetest_autoext_Init(interp);
|
||||
Md5_Init(interp);
|
||||
#ifdef SQLITE_SSE
|
||||
Sqlitetestsse_Init(interp);
|
||||
|
@ -2220,6 +2232,9 @@ int TCLSH_MAIN(int argc, char **argv){
|
|||
#endif
|
||||
if( argc>=2 || TCLSH==2 ){
|
||||
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,"argv", "", TCL_GLOBAL_ONLY);
|
||||
for(i=3-TCLSH; i<argc; i++){
|
||||
|
|
|
@ -63,9 +63,25 @@ static int get_sqlite_pointer(
|
|||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decode a pointer to an sqlite3 object.
|
||||
*/
|
||||
static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
|
||||
struct SqliteDb *p;
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
if( Tcl_GetCommandInfo(interp, zA, &cmdInfo) ){
|
||||
p = (struct SqliteDb*)cmdInfo.objClientData;
|
||||
*ppDb = p->db;
|
||||
}else{
|
||||
*ppDb = (sqlite3*)sqlite3TextToPtr(zA);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
const char *sqlite3TestErrorName(int rc){
|
||||
const char *zName = 0;
|
||||
switch( rc ){
|
||||
switch( rc & 0xff ){
|
||||
case SQLITE_OK: zName = "SQLITE_OK"; break;
|
||||
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
|
||||
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
|
||||
|
@ -121,14 +137,6 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decode a pointer to an sqlite3 object.
|
||||
*/
|
||||
static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
|
||||
*ppDb = (sqlite3*)sqlite3TextToPtr(zA);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decode a pointer to an sqlite3_stmt object.
|
||||
*/
|
||||
|
@ -227,6 +235,65 @@ static int test_exec_printf(
|
|||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_exec DB SQL
|
||||
**
|
||||
** Invoke the sqlite3_exec interface using the open database DB
|
||||
*/
|
||||
static int test_exec(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
sqlite3 *db;
|
||||
Tcl_DString str;
|
||||
int rc;
|
||||
char *zErr = 0;
|
||||
char zBuf[30];
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" DB SQL", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
Tcl_DStringInit(&str);
|
||||
rc = sqlite3_exec(db, argv[2], exec_printf_cb, &str, &zErr);
|
||||
sprintf(zBuf, "%d", rc);
|
||||
Tcl_AppendElement(interp, zBuf);
|
||||
Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
|
||||
Tcl_DStringFree(&str);
|
||||
if( zErr ) sqlite3_free(zErr);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_exec_nr DB SQL
|
||||
**
|
||||
** Invoke the sqlite3_exec interface using the open database DB. Discard
|
||||
** all results
|
||||
*/
|
||||
static int test_exec_nr(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
char *zErr = 0;
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" DB SQL", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ...
|
||||
**
|
||||
|
@ -442,6 +509,34 @@ static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** These are test functions. hex8() interprets its argument as
|
||||
** UTF8 and returns a hex encoding. hex16le() interprets its argument
|
||||
** as UTF16le and returns a hex encoding.
|
||||
*/
|
||||
static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){
|
||||
const unsigned char *z;
|
||||
int i;
|
||||
char zBuf[200];
|
||||
z = sqlite3_value_text(argv[0]);
|
||||
for(i=0; i<sizeof(zBuf)/2 - 2 && z[i]; i++){
|
||||
sprintf(&zBuf[i*2], "%02x", z[i]&0xff);
|
||||
}
|
||||
zBuf[i*2] = 0;
|
||||
sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){
|
||||
const unsigned short int *z;
|
||||
int i;
|
||||
char zBuf[400];
|
||||
z = sqlite3_value_text16(argv[0]);
|
||||
for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){
|
||||
sprintf(&zBuf[i*4], "%04x", z[i]&0xff);
|
||||
}
|
||||
zBuf[i*4] = 0;
|
||||
sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** A structure into which to accumulate text.
|
||||
*/
|
||||
|
@ -548,6 +643,14 @@ static int test_create_function(
|
|||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0,
|
||||
ifnullFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0,
|
||||
hex8Func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0,
|
||||
hex16Func, 0, 0);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
|
||||
|
@ -657,6 +760,30 @@ static int test_create_aggregate(
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: printf TEXT
|
||||
**
|
||||
** Send output to printf. Use this rather than puts to merge the output
|
||||
** in the correct sequence with debugging printfs inserted into C code.
|
||||
** Puts uses a separate buffer and debugging statements will be out of
|
||||
** sequence if it is used.
|
||||
*/
|
||||
static int test_printf(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" TEXT\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
printf("%s\n", argv[1]);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
|
||||
|
@ -1025,6 +1152,29 @@ static int test_enable_shared(
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_extended_result_codes DB BOOLEAN
|
||||
**
|
||||
*/
|
||||
static int test_extended_result_codes(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
int enable;
|
||||
sqlite3 *db;
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[2], &enable) ) return TCL_ERROR;
|
||||
sqlite3_extended_result_codes(db, enable);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_libversion_number
|
||||
**
|
||||
|
@ -1289,7 +1439,7 @@ static int test_finalize(
|
|||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
sqlite3 *db;
|
||||
sqlite3 *db = 0;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
|
@ -1417,6 +1567,7 @@ static int test_changes(
|
|||
** the FLAG option of sqlite3_bind is "static"
|
||||
*/
|
||||
static char *sqlite_static_bind_value = 0;
|
||||
static int sqlite_static_bind_nbyte = 0;
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_bind VM IDX VALUE FLAGS
|
||||
|
@ -1449,6 +1600,9 @@ static int test_bind(
|
|||
rc = sqlite3_bind_null(pStmt, idx);
|
||||
}else if( strcmp(argv[4],"static")==0 ){
|
||||
rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
|
||||
}else if( strcmp(argv[4],"static-nbytes")==0 ){
|
||||
rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value,
|
||||
sqlite_static_bind_nbyte, 0);
|
||||
}else if( strcmp(argv[4],"normal")==0 ){
|
||||
rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
|
||||
}else if( strcmp(argv[4],"blob10")==0 ){
|
||||
|
@ -2291,6 +2445,8 @@ static int test_errcode(
|
|||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
char zBuf[30];
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
|
@ -2298,7 +2454,13 @@ static int test_errcode(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
|
||||
rc = sqlite3_errcode(db);
|
||||
if( (rc&0xff)==rc ){
|
||||
zBuf[0] = 0;
|
||||
}else{
|
||||
sprintf(zBuf,"+%d", rc>>8);
|
||||
}
|
||||
Tcl_AppendResult(interp, (char *)errorName(rc), zBuf, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -2418,7 +2580,60 @@ static int test_prepare(
|
|||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_prepare DB sql bytes tailvar
|
||||
** Usage: sqlite3_prepare_v2 DB sql bytes tailvar
|
||||
**
|
||||
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
|
||||
** database handle <DB>. The parameter <tailval> is the name of a global
|
||||
** variable that is set to the unused portion of <sql> (if any). A
|
||||
** STMT handle is returned.
|
||||
*/
|
||||
static int test_prepare_v2(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zSql;
|
||||
int bytes;
|
||||
const char *zTail = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char zBuf[50];
|
||||
int rc;
|
||||
|
||||
if( objc!=5 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zSql = Tcl_GetString(objv[2]);
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
if( zTail ){
|
||||
if( bytes>=0 ){
|
||||
bytes = bytes - (zTail-zSql);
|
||||
}
|
||||
Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( pStmt==0 );
|
||||
sprintf(zBuf, "(%d) ", rc);
|
||||
Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( pStmt ){
|
||||
if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_prepare16 DB sql bytes tailvar
|
||||
**
|
||||
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
|
||||
** database handle <DB>. The parameter <tailval> is the name of a global
|
||||
|
@ -2475,6 +2690,64 @@ static int test_prepare16(
|
|||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_prepare16_v2 DB sql bytes tailvar
|
||||
**
|
||||
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
|
||||
** database handle <DB>. The parameter <tailval> is the name of a global
|
||||
** variable that is set to the unused portion of <sql> (if any). A
|
||||
** STMT handle is returned.
|
||||
*/
|
||||
static int test_prepare16_v2(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
sqlite3 *db;
|
||||
const void *zSql;
|
||||
const void *zTail = 0;
|
||||
Tcl_Obj *pTail = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char zBuf[50];
|
||||
int rc;
|
||||
int bytes; /* The integer specified as arg 3 */
|
||||
int objlen; /* The byte-array length of arg 2 */
|
||||
|
||||
if( objc!=5 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3_prepare16_v2(db, zSql, bytes, &pStmt, &zTail);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
if( rc ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( zTail ){
|
||||
objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
|
||||
}else{
|
||||
objlen = 0;
|
||||
}
|
||||
pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
|
||||
Tcl_IncrRefCount(pTail);
|
||||
Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
|
||||
Tcl_DecrRefCount(pTail);
|
||||
|
||||
if( pStmt ){
|
||||
if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
|
||||
}
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_open filename ?options-list?
|
||||
*/
|
||||
|
@ -3540,6 +3813,18 @@ static void set_options(Tcl_Interp *interp){
|
|||
Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS1
|
||||
Tcl_SetVar2(interp, "sqlite_options", "fts1", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "fts1", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS2
|
||||
Tcl_SetVar2(interp, "sqlite_options", "fts2", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "fts2", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_GLOBALRECOVER
|
||||
Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
@ -3698,6 +3983,35 @@ static void set_options(Tcl_Interp *interp){
|
|||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: working_64bit_int
|
||||
**
|
||||
** Some TCL builds (ex: cygwin) do not support 64-bit integers. This
|
||||
** leads to a number of test failures. The present command checks the
|
||||
** TCL build to see whether or not it supports 64-bit integers. It
|
||||
** returns TRUE if it does and FALSE if not.
|
||||
**
|
||||
** This command is used to warn users that their TCL build is defective
|
||||
** and that the errors they are seeing in the test scripts might be
|
||||
** a result of their defective TCL rather than problems in SQLite.
|
||||
*/
|
||||
static int working_64bit_int(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
Tcl_Obj *pTestObj;
|
||||
int working = 0;
|
||||
|
||||
pTestObj = Tcl_NewWideIntObj(1000000*(i64)1234567890);
|
||||
working = strcmp(Tcl_GetString(pTestObj), "1234567890000000")==0;
|
||||
Tcl_DecrRefCount(pTestObj);
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(working));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
|
@ -3722,6 +4036,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
{ "sqlite3_mprintf_n_test", (Tcl_CmdProc*)test_mprintf_n },
|
||||
{ "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
|
||||
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
|
||||
{ "sqlite3_exec", (Tcl_CmdProc*)test_exec },
|
||||
{ "sqlite3_exec_nr", (Tcl_CmdProc*)test_exec_nr },
|
||||
{ "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
|
||||
{ "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close },
|
||||
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
|
||||
|
@ -3743,6 +4059,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
|
||||
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
|
||||
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
|
||||
{ "printf", (Tcl_CmdProc*)test_printf },
|
||||
};
|
||||
static struct {
|
||||
char *zName;
|
||||
|
@ -3771,6 +4088,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
|
||||
{ "sqlite3_prepare", test_prepare ,0 },
|
||||
{ "sqlite3_prepare16", test_prepare16 ,0 },
|
||||
{ "sqlite3_prepare_v2", test_prepare_v2 ,0 },
|
||||
{ "sqlite3_prepare16_v2", test_prepare16_v2 ,0 },
|
||||
{ "sqlite3_finalize", test_finalize ,0 },
|
||||
{ "sqlite3_reset", test_reset ,0 },
|
||||
{ "sqlite3_expired", test_expired ,0 },
|
||||
|
@ -3786,6 +4105,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
|
||||
{ "sqlite3_load_extension", test_load_extension, 0},
|
||||
{ "sqlite3_enable_load_extension", test_enable_load, 0},
|
||||
{ "sqlite3_extended_result_codes", test_extended_result_codes, 0},
|
||||
|
||||
/* sqlite3_column_*() API */
|
||||
{ "sqlite3_column_count", test_column_count ,0 },
|
||||
|
@ -3819,6 +4139,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
#endif
|
||||
#endif
|
||||
{ "sqlite3_global_recover", test_global_recover, 0 },
|
||||
{ "working_64bit_int", working_64bit_int, 0 },
|
||||
|
||||
/* Functions from os.h */
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
|
@ -3938,6 +4259,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
#endif
|
||||
Tcl_LinkVar(interp, "sqlite_static_bind_value",
|
||||
(char*)&sqlite_static_bind_value, TCL_LINK_STRING);
|
||||
Tcl_LinkVar(interp, "sqlite_static_bind_nbyte",
|
||||
(char*)&sqlite_static_bind_nbyte, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_temp_directory",
|
||||
(char*)&sqlite3_temp_directory, TCL_LINK_STRING);
|
||||
Tcl_LinkVar(interp, "bitmask_size",
|
||||
|
|
|
@ -567,6 +567,7 @@ static int btree_integrity_check(
|
|||
int nRoot;
|
||||
int *aRoot;
|
||||
int i;
|
||||
int nErr;
|
||||
char *zResult;
|
||||
|
||||
if( argc<3 ){
|
||||
|
@ -581,7 +582,7 @@ static int btree_integrity_check(
|
|||
if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot);
|
||||
zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
|
||||
#else
|
||||
zResult = 0;
|
||||
#endif
|
||||
|
@ -598,7 +599,6 @@ static int btree_integrity_check(
|
|||
**
|
||||
** Print information about all cursors to standard output for debugging.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int btree_cursor_list(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
|
@ -616,7 +616,6 @@ static int btree_cursor_list(
|
|||
sqlite3BtreeCursorList(pBt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Usage: btree_cursor ID TABLENUM WRITEABLE
|
||||
|
@ -1053,6 +1052,7 @@ static int btree_data(
|
|||
rc = sqlite3BtreeData(pCur, 0, n, zBuf);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
free(zBuf);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zBuf[n] = 0;
|
||||
|
@ -1187,7 +1187,6 @@ static int btree_payload_size(
|
|||
** aResult[8] = Local payload size
|
||||
** aResult[9] = Parent page number
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int btree_cursor_info(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
|
@ -1225,7 +1224,6 @@ static int btree_cursor_info(
|
|||
Tcl_AppendResult(interp, &zBuf[1], 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The command is provided for the purpose of setting breakpoints.
|
||||
|
@ -1441,10 +1439,8 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
|||
{ "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
|
||||
{ "btree_from_db", (Tcl_CmdProc*)btree_from_db },
|
||||
{ "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size },
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
|
||||
{ "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
|
||||
|
|
|
@ -394,16 +394,16 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|||
int tokenType;
|
||||
int lastTokenParsed = -1;
|
||||
sqlite3 *db = pParse->db;
|
||||
extern void *sqlite3ParserAlloc(void*(*)(int));
|
||||
extern void *sqlite3ParserAlloc(void*(*)(size_t));
|
||||
extern void sqlite3ParserFree(void*, void(*)(void*));
|
||||
extern int sqlite3Parser(void*, int, Token, Parse*);
|
||||
extern void sqlite3Parser(void*, int, Token, Parse*);
|
||||
|
||||
if( db->activeVdbeCnt==0 ){
|
||||
db->u1.isInterrupted = 0;
|
||||
}
|
||||
pParse->rc = SQLITE_OK;
|
||||
i = 0;
|
||||
pEngine = sqlite3ParserAlloc((void*(*)(int))sqlite3MallocX);
|
||||
pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3MallocX);
|
||||
if( pEngine==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,8 @@ void sqlite3BeginTrigger(
|
|||
SrcList *pTableName,/* The name of the table/view the trigger applies to */
|
||||
int foreach, /* One of TK_ROW or TK_STATEMENT */
|
||||
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;
|
||||
Table *pTab;
|
||||
|
@ -115,7 +116,9 @@ void sqlite3BeginTrigger(
|
|||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){
|
||||
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
}
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
|
@ -439,7 +442,7 @@ void sqlite3DeleteTrigger(Trigger *pTrigger){
|
|||
** same job as this routine except it takes a pointer to the trigger
|
||||
** instead of the trigger name.
|
||||
**/
|
||||
void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
|
||||
void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
|
||||
Trigger *pTrigger = 0;
|
||||
int i;
|
||||
const char *zDb;
|
||||
|
@ -463,7 +466,9 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
|
|||
if( pTrigger ) break;
|
||||
}
|
||||
if( !pTrigger ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
|
||||
}
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
|
@ -663,12 +668,12 @@ static int codeTriggerProgram(
|
|||
pParse->trigStack->orconf = orconf;
|
||||
switch( pTriggerStep->op ){
|
||||
case TK_SELECT: {
|
||||
Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
|
||||
assert(ss);
|
||||
assert(ss->pSrc);
|
||||
sqlite3SelectResolve(pParse, ss, 0);
|
||||
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(ss);
|
||||
Select *ss = sqlite3SelectDup(pTriggerStep->pSelect);
|
||||
if( ss ){
|
||||
sqlite3SelectResolve(pParse, ss, 0);
|
||||
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(ss);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_UPDATE: {
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
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,
|
||||
|
||||
/* 10wwwwww */
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
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,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
|
||||
/* 110yyyyy */
|
||||
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,
|
||||
|
||||
/* 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
|
||||
** in the READ_UTF8 macro explains things best.
|
||||
*/
|
||||
static const int xtra_utf8_bits[4] = {
|
||||
0,
|
||||
12416, /* (0xC0 << 6) + (0x80) */
|
||||
925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
|
||||
63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
|
||||
static const int xtra_utf8_bits[] = {
|
||||
0,
|
||||
12416, /* (0xC0 << 6) + (0x80) */
|
||||
925824, /* (0xE0 << 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) { \
|
||||
|
@ -113,11 +126,14 @@ static const int xtra_utf8_bits[4] = {
|
|||
c = *(zIn)++; \
|
||||
xtra = xtra_utf8_bytes[c]; \
|
||||
switch( xtra ){ \
|
||||
case 255: c = (int)0xFFFD; break; \
|
||||
case 4: c = (int)0xFFFD; break; \
|
||||
case 3: c = (c<<6) + *(zIn)++; \
|
||||
case 2: c = (c<<6) + *(zIn)++; \
|
||||
case 1: c = (c<<6) + *(zIn)++; \
|
||||
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){
|
||||
|
@ -181,6 +197,7 @@ int sqlite3ReadUtf8(const unsigned char *z){
|
|||
int c2 = (*zIn++); \
|
||||
c2 += ((*zIn++)<<8); \
|
||||
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); \
|
||||
c2 += (*zIn++); \
|
||||
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 *zTerm; /* End of input */
|
||||
unsigned char *z; /* Output iterator */
|
||||
int c;
|
||||
unsigned int c;
|
||||
|
||||
assert( pMem->flags&MEM_Str );
|
||||
assert( pMem->enc!=desiredEnc );
|
||||
|
@ -475,7 +493,7 @@ char *sqlite3utf16to8(const void *z, int nByte){
|
|||
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
|
||||
*/
|
||||
int sqlite3utf16ByteLen(const void *zIn, int nChar){
|
||||
int c = 1;
|
||||
unsigned int c = 1;
|
||||
char const *z = zIn;
|
||||
int n = 0;
|
||||
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
|
||||
|
@ -556,11 +574,11 @@ void sqlite3utf16Substr(
|
|||
** characters in each encoding are inverses of each other.
|
||||
*/
|
||||
void sqlite3utfSelfTest(){
|
||||
int i;
|
||||
unsigned int i, t;
|
||||
unsigned char zBuf[20];
|
||||
unsigned char *z;
|
||||
int n;
|
||||
int c;
|
||||
unsigned int c;
|
||||
|
||||
for(i=0; i<0x00110000; i++){
|
||||
z = zBuf;
|
||||
|
@ -568,7 +586,10 @@ void sqlite3utfSelfTest(){
|
|||
n = z-zBuf;
|
||||
z = zBuf;
|
||||
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 );
|
||||
}
|
||||
for(i=0; i<0x00110000; i++){
|
||||
|
|
|
@ -1446,7 +1446,7 @@ int sqlite3ApiExit(sqlite3* db, int rc){
|
|||
sqlite3Error(db, SQLITE_NOMEM, 0);
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
return rc;
|
||||
return rc & (db ? db->errMask : 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -21,20 +21,6 @@
|
|||
#include "os.h"
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
@ -69,8 +55,6 @@ static int execExecSql(sqlite3 *db, const char *zSql){
|
|||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The non-standard VACUUM command is used to clean up the database,
|
||||
** 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 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 *pTemp;
|
||||
char *zSql = 0;
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
Db *pDb = 0; /* Database to detach at end of vacuum */
|
||||
Btree *pTemp; /* The temporary database we vacuum into */
|
||||
char *zSql = 0; /* SQL statements */
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
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. */
|
||||
saved_flags = db->flags;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
|
||||
|
||||
sqlite3OsTempFileName(zTemp);
|
||||
if( !db->autoCommit ){
|
||||
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
|
||||
(char*)0);
|
||||
rc = SQLITE_ERROR;
|
||||
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;
|
||||
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
|
||||
** 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,
|
||||
"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;
|
||||
rc = execExecSql(db,
|
||||
"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) "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
|
||||
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
|
||||
** 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 * FROM ' || quote(name) || ';'"
|
||||
"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;
|
||||
|
||||
|
@ -233,17 +181,19 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
|||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
|
||||
/* Copy the triggers from the main database to the temporary database.
|
||||
** This was deferred before in case the triggers interfered with copying
|
||||
** the data. It's possible the indices should be deferred until this
|
||||
** point also.
|
||||
/* Copy the triggers, views, and virtual tables from the main database
|
||||
** over to the temporary database. None of these objects has any
|
||||
** associated storage, so all we have to do is copy their entries
|
||||
** from the SQLITE_MASTER table.
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'CREATE TRIGGER vacuum_db.' || substr(sql, 16, 1000000) "
|
||||
"FROM sqlite_master WHERE type='trigger'"
|
||||
rc = execSql(db,
|
||||
"INSERT INTO vacuum_db.sqlite_master "
|
||||
" 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
|
||||
** transaction open on the vacuum database, but not on the main database.
|
||||
|
@ -309,21 +259,12 @@ end_of_vacuum:
|
|||
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);
|
||||
sqliteFree(zTemp);
|
||||
}
|
||||
sqlite3OsDelete(zTemp);
|
||||
strcat(zTemp, "-journal");
|
||||
sqlite3OsDelete(zTemp);
|
||||
sqliteFree( zSql );
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VACUUM */
|
||||
|
|
|
@ -454,6 +454,21 @@ int sqlite3VdbeExec(
|
|||
p->resOnStack = 0;
|
||||
db->busyHandler.nBusy = 0;
|
||||
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++){
|
||||
assert( pc>=0 && pc<p->nOp );
|
||||
assert( pTos<=&p->aStack[pc] );
|
||||
|
@ -1812,32 +1827,31 @@ case OP_IfNot: { /* no-push */
|
|||
|
||||
/* Opcode: IsNull P1 P2 *
|
||||
**
|
||||
** If any of the top abs(P1) values on the stack are NULL, then jump
|
||||
** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack
|
||||
** unchanged.
|
||||
** Check the top of the stack and jump to P2 if the top of the stack
|
||||
** is NULL. If P1 is positive, then pop P1 elements from the stack
|
||||
** 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 */
|
||||
int i, cnt;
|
||||
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;
|
||||
break;
|
||||
if( pTos->flags & MEM_Null ){
|
||||
pc = pOp->p2-1;
|
||||
if( pOp->p1<0 ){
|
||||
popStack(&pTos, -pOp->p1);
|
||||
}
|
||||
}
|
||||
if( pOp->p1>0 ) popStack(&pTos, cnt);
|
||||
if( pOp->p1>0 ){
|
||||
popStack(&pTos, pOp->p1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: NotNull P1 P2 *
|
||||
**
|
||||
** Jump to P2 if the top P1 values on the stack are all not NULL. Pop the
|
||||
** stack if P1 times if P1 is greater than zero. If P1 is less than
|
||||
** zero then leave the stack unchanged.
|
||||
** Jump to P2 if the top abs(P1) values on the stack are all not NULL.
|
||||
** Regardless of whether or not the jump is taken, pop the stack
|
||||
** 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 */
|
||||
int i, cnt;
|
||||
|
@ -2010,7 +2024,9 @@ case OP_Column: {
|
|||
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);
|
||||
|
||||
/* The KeyFetch() or DataFetch() above are fast and will get the entire
|
||||
|
@ -2501,6 +2517,8 @@ case OP_VerifyCookie: { /* no-push */
|
|||
}
|
||||
if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
|
||||
sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0);
|
||||
sqlite3ResetInternalSchema(db, pOp->p1);
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
|
@ -2907,7 +2925,7 @@ case OP_MoveGt: { /* no-push */
|
|||
**
|
||||
** 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
|
||||
** 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.
|
||||
**
|
||||
** The difference between this operation and Distinct is that
|
||||
|
@ -2980,7 +2998,7 @@ case OP_IsUnique: { /* no-push */
|
|||
R = pTos->i;
|
||||
assert( (pTos->flags & MEM_Dyn)==0 );
|
||||
pTos--;
|
||||
assert( i>=0 && i<=p->nCursor );
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
pCx = p->apCsr[i];
|
||||
assert( pCx!=0 );
|
||||
pCrsr = pCx->pCursor;
|
||||
|
@ -3081,6 +3099,9 @@ case OP_NotExists: { /* no-push */
|
|||
pC->rowidIsValid = res==0;
|
||||
pC->nullRow = 0;
|
||||
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 ){
|
||||
pc = pOp->p2 - 1;
|
||||
pC->rowidIsValid = 0;
|
||||
|
@ -3852,38 +3873,6 @@ case OP_IdxGE: { /* no-push */
|
|||
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 *
|
||||
**
|
||||
** Delete an entire database table or index whose root page in the database
|
||||
|
@ -3906,9 +3895,9 @@ case OP_IdxIsNull: { /* no-push */
|
|||
*/
|
||||
case OP_Destroy: {
|
||||
int iMoved;
|
||||
Vdbe *pVdbe;
|
||||
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 ){
|
||||
|
@ -4032,10 +4021,14 @@ case OP_CreateTable: {
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ParseSchema P1 * P3
|
||||
/* Opcode: ParseSchema P1 P2 P3
|
||||
**
|
||||
** 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,
|
||||
** then runs the new virtual machine. It is thus a reentrant opcode.
|
||||
|
@ -4047,13 +4040,16 @@ case OP_ParseSchema: { /* no-push */
|
|||
InitData initData;
|
||||
|
||||
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);
|
||||
initData.db = db;
|
||||
initData.iDb = pOp->p1;
|
||||
initData.pzErrMsg = &p->zErrMsg;
|
||||
zSql = sqlite3MPrintf(
|
||||
"SELECT name, rootpage, sql, %d FROM '%q'.%s WHERE %s",
|
||||
pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3);
|
||||
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
|
||||
db->aDb[iDb].zName, zMaster, pOp->p3);
|
||||
if( zSql==0 ) goto no_mem;
|
||||
sqlite3SafetyOff(db);
|
||||
assert( db->init.busy==0 );
|
||||
|
@ -4124,11 +4120,16 @@ case OP_DropTrigger: { /* no-push */
|
|||
|
||||
|
||||
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
/* Opcode: IntegrityCk * P2 *
|
||||
/* Opcode: IntegrityCk P1 P2 *
|
||||
**
|
||||
** Do an analysis of the currently open database. Push onto the
|
||||
** 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
|
||||
** values on the stack. This opcode pulls as many integers as it
|
||||
|
@ -4137,13 +4138,15 @@ case OP_DropTrigger: { /* no-push */
|
|||
** If P2 is not zero, the check is done on the auxiliary database
|
||||
** 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: {
|
||||
int nRoot;
|
||||
int *aRoot;
|
||||
int j;
|
||||
int nErr;
|
||||
char *z;
|
||||
Mem *pnErr;
|
||||
|
||||
for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){
|
||||
if( (pTos[-nRoot].flags & MEM_Int)==0 ) break;
|
||||
|
@ -4151,6 +4154,10 @@ case OP_IntegrityCk: {
|
|||
assert( nRoot>0 );
|
||||
aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) );
|
||||
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++){
|
||||
Mem *pMem = &pTos[-j];
|
||||
aRoot[j] = pMem->i;
|
||||
|
@ -4158,12 +4165,12 @@ case OP_IntegrityCk: {
|
|||
aRoot[j] = 0;
|
||||
popStack(&pTos, nRoot);
|
||||
pTos++;
|
||||
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
|
||||
if( z==0 || z[0]==0 ){
|
||||
if( z ) sqliteFree(z);
|
||||
pTos->z = "ok";
|
||||
pTos->n = 2;
|
||||
pTos->flags = MEM_Str | MEM_Static | MEM_Term;
|
||||
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot,
|
||||
pnErr->i, &nErr);
|
||||
pnErr->i -= nErr;
|
||||
if( nErr==0 ){
|
||||
assert( z==0 );
|
||||
pTos->flags = MEM_Null;
|
||||
}else{
|
||||
pTos->z = z;
|
||||
pTos->n = strlen(z);
|
||||
|
@ -4499,6 +4506,7 @@ case OP_AggFinal: { /* no-push */
|
|||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_VACUUM
|
||||
/* Opcode: Vacuum * * *
|
||||
**
|
||||
** Vacuum the entire database. This opcode will cause other virtual
|
||||
|
@ -4511,6 +4519,7 @@ case OP_Vacuum: { /* no-push */
|
|||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Opcode: Expire P1 * *
|
||||
**
|
||||
|
@ -4672,9 +4681,9 @@ case OP_VFilter: { /* no-push */
|
|||
assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int );
|
||||
nArg = pTos[-1].i;
|
||||
|
||||
/* Invoke the xFilter method if one is defined. */
|
||||
if( pModule->xFilter ){
|
||||
int res;
|
||||
/* Invoke the xFilter method */
|
||||
{
|
||||
int res = 0;
|
||||
int i;
|
||||
Mem **apArg = p->apArg;
|
||||
for(i = 0; i<nArg; i++){
|
||||
|
@ -4857,7 +4866,9 @@ case OP_VUpdate: { /* no-push */
|
|||
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) );
|
||||
|
|
|
@ -129,12 +129,16 @@ int sqlite3VdbeFinalize(Vdbe*);
|
|||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||
void sqlite3VdbeTrace(Vdbe*,FILE*);
|
||||
void sqlite3VdbeResetStepResult(Vdbe*);
|
||||
int sqlite3VdbeReset(Vdbe*);
|
||||
int sqliteVdbeSetVariables(Vdbe*,int,const char**);
|
||||
void sqlite3VdbeSetNumCols(Vdbe*,int);
|
||||
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
|
||||
void sqlite3VdbeCountChanges(Vdbe*);
|
||||
sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
|
||||
const char *sqlite3VdbeGetSql(Vdbe*);
|
||||
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
** 6000 lines long) it was split up into several smaller files and
|
||||
** this header information was factored out.
|
||||
*/
|
||||
#ifndef _VDBEINT_H_
|
||||
#define _VDBEINT_H_
|
||||
|
||||
/*
|
||||
** intToKey() and keyToInt() used to transform the rowid. But with
|
||||
|
@ -328,6 +330,8 @@ struct Vdbe {
|
|||
u8 inVtabMethod; /* See comments above */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
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
|
||||
int fetchId; /* Statement number used by sqlite3_fetch_statement */
|
||||
int lru; /* Counter used for LRU cache replacement */
|
||||
|
@ -401,3 +405,5 @@ void sqlite3VdbeFifoInit(Fifo*);
|
|||
int sqlite3VdbeFifoPush(Fifo*, i64);
|
||||
int sqlite3VdbeFifoPop(Fifo*, i64*);
|
||||
void sqlite3VdbeFifoClear(Fifo*);
|
||||
|
||||
#endif /* !defined(_VDBEINT_H_) */
|
||||
|
|
|
@ -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
|
||||
** 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){
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
static int sqlite3Step(Vdbe *p){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
|
@ -172,7 +176,8 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
|||
if( p->rc==SQLITE_OK ){
|
||||
p->rc = SQLITE_SCHEMA;
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
rc = SQLITE_ERROR;
|
||||
goto end_of_step;
|
||||
}
|
||||
db = p->db;
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
|
@ -254,8 +259,42 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
|||
|
||||
sqlite3Error(p->db, rc, 0);
|
||||
p->rc = sqlite3ApiExit(p->db, p->rc);
|
||||
end_of_step:
|
||||
assert( (rc&0xff)==rc );
|
||||
if( p->zSql && (rc&0xff)<SQLITE_ROW ){
|
||||
/* This behavior occurs if sqlite3_prepare_v2() was used to build
|
||||
** the prepared statement. Return error codes directly */
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Extract the user data from a sqlite3_context structure and return a
|
||||
|
@ -266,6 +305,27 @@ void *sqlite3_user_data(sqlite3_context *p){
|
|||
return p->pFunc->pUserData;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
** context is allocated on the first call. Subsequent calls return the
|
||||
|
@ -815,6 +875,7 @@ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
|
|||
rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
|
||||
sqlite3MallocAllow();
|
||||
}
|
||||
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,46 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
|
|||
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
|
||||
*/
|
||||
|
@ -812,21 +852,6 @@ void sqlite3VdbeMakeReady(
|
|||
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->pc = -1;
|
||||
p->rc = SQLITE_OK;
|
||||
|
@ -1145,7 +1170,9 @@ static int vdbeCommit(sqlite3 *db){
|
|||
** transaction files are deleted.
|
||||
*/
|
||||
rc = sqlite3OsDelete(zMaster);
|
||||
assert( rc==SQLITE_OK );
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
sqliteFree(zMaster);
|
||||
zMaster = 0;
|
||||
rc = sqlite3OsSyncDirectory(zMainFile);
|
||||
|
@ -1287,9 +1314,10 @@ int sqlite3VdbeHalt(Vdbe *p){
|
|||
|
||||
/* No commit or rollback needed if the program never started */
|
||||
if( p->pc>=0 ){
|
||||
|
||||
int mrc; /* Primary error code from p->rc */
|
||||
/* 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 ){
|
||||
/* This loop does static analysis of the query to see which of the
|
||||
** following three categories it falls into:
|
||||
|
@ -1421,6 +1449,14 @@ int sqlite3VdbeHalt(Vdbe *p){
|
|||
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.
|
||||
** Write any error messages into *pzErrMsg. Return the result code.
|
||||
|
@ -1433,18 +1469,20 @@ int sqlite3VdbeHalt(Vdbe *p){
|
|||
** VDBE_MAGIC_INIT.
|
||||
*/
|
||||
int sqlite3VdbeReset(Vdbe *p){
|
||||
sqlite3 *db;
|
||||
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
|
||||
sqlite3Error(p->db, SQLITE_MISUSE, 0);
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
db = p->db;
|
||||
|
||||
/* If the VM did not run to completion or if it encountered an
|
||||
** error, then it might not have been halted properly. So halt
|
||||
** it now.
|
||||
*/
|
||||
sqlite3SafetyOn(p->db);
|
||||
sqlite3SafetyOn(db);
|
||||
sqlite3VdbeHalt(p);
|
||||
sqlite3SafetyOff(p->db);
|
||||
sqlite3SafetyOff(db);
|
||||
|
||||
/* 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
|
||||
|
@ -1453,21 +1491,20 @@ int sqlite3VdbeReset(Vdbe *p){
|
|||
*/
|
||||
if( p->pc>=0 ){
|
||||
if( p->zErrMsg ){
|
||||
sqlite3* db = p->db;
|
||||
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX);
|
||||
db->errCode = p->rc;
|
||||
p->zErrMsg = 0;
|
||||
}else if( p->rc ){
|
||||
sqlite3Error(p->db, p->rc, 0);
|
||||
sqlite3Error(db, p->rc, 0);
|
||||
}else{
|
||||
sqlite3Error(p->db, SQLITE_OK, 0);
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
}
|
||||
}else if( p->rc && p->expired ){
|
||||
/* The expired flag was set on the VDBE before the first call
|
||||
** to sqlite3_step(). For consistency (since sqlite3_step() was
|
||||
** 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
|
||||
|
@ -1502,9 +1539,9 @@ int sqlite3VdbeReset(Vdbe *p){
|
|||
p->magic = VDBE_MAGIC_INIT;
|
||||
p->aborted = 0;
|
||||
if( p->rc==SQLITE_SCHEMA ){
|
||||
sqlite3ResetInternalSchema(p->db, 0);
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
return p->rc;
|
||||
return p->rc & db->errMask;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1515,6 +1552,7 @@ int sqlite3VdbeFinalize(Vdbe *p){
|
|||
int rc = SQLITE_OK;
|
||||
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
|
||||
rc = sqlite3VdbeReset(p);
|
||||
assert( (rc & p->db->errMask)==rc );
|
||||
}else if( p->magic!=VDBE_MAGIC_INIT ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
@ -1569,6 +1607,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
|||
sqliteFree(p->aStack);
|
||||
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
||||
sqliteFree(p->aColName);
|
||||
sqliteFree(p->zSql);
|
||||
p->magic = VDBE_MAGIC_DEAD;
|
||||
sqliteFree(p);
|
||||
}
|
||||
|
@ -1887,14 +1926,13 @@ int sqlite3VdbeRecordCompare(
|
|||
idx2 += GetVarint( aKey2+idx2, serial_type2 );
|
||||
if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break;
|
||||
|
||||
/* Assert that there is enough space left in each key for the blob of
|
||||
** 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.
|
||||
/* Extract the values to be compared.
|
||||
*/
|
||||
d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
|
||||
d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2);
|
||||
|
||||
/* Do the comparison
|
||||
*/
|
||||
rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0);
|
||||
if( mem1.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem1);
|
||||
if( mem2.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem2);
|
||||
|
|
|
@ -50,14 +50,6 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
|||
assert(rc==SQLITE_OK || rc==SQLITE_NOMEM);
|
||||
assert(rc==SQLITE_OK || 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;
|
||||
#endif
|
||||
}
|
||||
|
@ -127,22 +119,9 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
|||
** Make sure the given Mem is \u0000 terminated.
|
||||
*/
|
||||
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 ){
|
||||
return SQLITE_OK; /* Nothing to do */
|
||||
}
|
||||
|
||||
if( pMem->flags & (MEM_Static|MEM_Ephem) ){
|
||||
return sqlite3VdbeMemMakeWriteable(pMem);
|
||||
}else{
|
||||
|
@ -151,7 +130,11 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
|
|||
memcpy(z, pMem->z, pMem->n);
|
||||
z[pMem->n] = 0;
|
||||
z[pMem->n+1] = 0;
|
||||
pMem->xDel(pMem->z);
|
||||
if( pMem->xDel ){
|
||||
pMem->xDel(pMem->z);
|
||||
}else{
|
||||
sqliteFree(pMem->z);
|
||||
}
|
||||
pMem->xDel = 0;
|
||||
pMem->z = z;
|
||||
}
|
||||
|
@ -782,7 +765,9 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
}else if( !(pVal->flags&MEM_Blob) ){
|
||||
sqlite3VdbeMemNulTerminate(pVal);
|
||||
}else{
|
||||
assert( (pVal->flags&MEM_Blob)==0 );
|
||||
sqlite3VdbeMemStringify(pVal, enc);
|
||||
assert( 0==(1&(int)pVal->z) );
|
||||
}
|
||||
|
|
|
@ -40,6 +40,29 @@ int sqlite3_create_module(
|
|||
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
|
||||
|
@ -49,10 +72,7 @@ void sqlite3VtabClear(Table *p){
|
|||
sqlite3_vtab *pVtab = p->pVtab;
|
||||
if( pVtab ){
|
||||
assert( p->pMod && p->pMod->pModule );
|
||||
pVtab->nRef--;
|
||||
if( pVtab->nRef==0 ){
|
||||
pVtab->pModule->xDisconnect(pVtab);
|
||||
}
|
||||
sqlite3VtabUnlock(pVtab);
|
||||
p->pVtab = 0;
|
||||
}
|
||||
if( p->azModuleArg ){
|
||||
|
@ -139,7 +159,7 @@ void sqlite3VtabBeginParse(
|
|||
*/
|
||||
static void addArgumentToVtab(Parse *pParse){
|
||||
if( pParse->sArg.z && pParse->pNewTable ){
|
||||
const char *z = pParse->sArg.z;
|
||||
const char *z = (const char*)pParse->sArg.z;
|
||||
int n = pParse->sArg.n;
|
||||
addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n));
|
||||
}
|
||||
|
@ -210,7 +230,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
|||
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
|
||||
zWhere = sqlite3MPrintf("name='%q'", pTab->zName);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC);
|
||||
sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1);
|
||||
}
|
||||
|
||||
|
@ -266,14 +286,16 @@ static int vtabCallConstructor(
|
|||
sqlite3 *db,
|
||||
Table *pTab,
|
||||
Module *pMod,
|
||||
int (*xConstruct)(sqlite3*, void *, int, char **, sqlite3_vtab **),
|
||||
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
||||
char **pzErr
|
||||
){
|
||||
int rc;
|
||||
int rc2;
|
||||
char **azArg = pTab->azModuleArg;
|
||||
sqlite3_vtab *pVtab;
|
||||
const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
||||
int nArg = pTab->nModuleArg;
|
||||
char *zErr = sqlite3MPrintf("vtable constructor failed: %s", pTab->zName);
|
||||
char *zErr = 0;
|
||||
char *zModuleName = sqlite3MPrintf("%s", pTab->zName);
|
||||
|
||||
assert( !db->pVTab );
|
||||
assert( xConstruct );
|
||||
|
@ -281,17 +303,22 @@ static int vtabCallConstructor(
|
|||
db->pVTab = pTab;
|
||||
rc = sqlite3SafetyOff(db);
|
||||
assert( rc==SQLITE_OK );
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab);
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab, &zErr);
|
||||
rc2 = sqlite3SafetyOn(db);
|
||||
if( rc==SQLITE_OK && pTab->pVtab ){
|
||||
pTab->pVtab->pModule = pMod->pModule;
|
||||
pTab->pVtab->nRef = 1;
|
||||
pVtab = pTab->pVtab;
|
||||
if( rc==SQLITE_OK && pVtab ){
|
||||
pVtab->pModule = pMod->pModule;
|
||||
pVtab->nRef = 1;
|
||||
}
|
||||
|
||||
if( SQLITE_OK!=rc ){
|
||||
*pzErr = zErr;
|
||||
zErr = 0;
|
||||
} else if( db->pVTab ){
|
||||
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;
|
||||
|
@ -300,7 +327,7 @@ static int vtabCallConstructor(
|
|||
rc = rc2;
|
||||
}
|
||||
db->pVTab = 0;
|
||||
sqliteFree(zErr);
|
||||
sqliteFree(zModuleName);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -313,7 +340,6 @@ static int vtabCallConstructor(
|
|||
*/
|
||||
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
||||
Module *pMod;
|
||||
const char *zModule;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( !pTab || !pTab->isVirtual || pTab->pVtab ){
|
||||
|
@ -321,7 +347,6 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
|||
}
|
||||
|
||||
pMod = pTab->pMod;
|
||||
zModule = pTab->azModuleArg[0];
|
||||
if( !pMod ){
|
||||
const char *zModule = pTab->azModuleArg[0];
|
||||
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
|
||||
|
@ -359,7 +384,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
|
|||
|
||||
/* Add pVtab to the end of sqlite3.aVTrans */
|
||||
db->aVTrans[db->nVTrans++] = pVtab;
|
||||
pVtab->nRef++;
|
||||
sqlite3VtabLock(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -444,6 +469,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|||
sParse.pNewTable = 0;
|
||||
db->pVTab = 0;
|
||||
|
||||
assert( (rc&0xff)==rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -492,10 +518,7 @@ static void callFinaliser(sqlite3 *db, int offset){
|
|||
int (*x)(sqlite3_vtab *);
|
||||
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
|
||||
if( x ) x(pVtab);
|
||||
pVtab->nRef--;
|
||||
if( pVtab->nRef==0 ){
|
||||
pVtab->pModule->xDisconnect(pVtab);
|
||||
}
|
||||
sqlite3VtabUnlock(pVtab);
|
||||
}
|
||||
sqliteFree(db->aVTrans);
|
||||
db->nVTrans = 0;
|
||||
|
@ -623,6 +646,10 @@ FuncDef *sqlite3VtabOverloadFunction(
|
|||
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;
|
||||
|
@ -637,8 +664,15 @@ FuncDef *sqlite3VtabOverloadFunction(
|
|||
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 */
|
||||
if( pMod->xFindFunction(pVtab, nArg, pDef->zName, &xFunc, &pArg)==0 ){
|
||||
** 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -157,22 +157,31 @@ struct ExprMaskSet {
|
|||
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
|
||||
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
|
||||
#define WO_MATCH 64
|
||||
#define WO_ISNULL 128
|
||||
|
||||
/*
|
||||
** Value for flags returned by bestIndex()
|
||||
** Value for flags returned by bestIndex().
|
||||
**
|
||||
** The least significant byte is reserved as a mask for WO_ values above.
|
||||
** The WhereLevel.flags field is usually set to WO_IN|WO_EQ|WO_ISNULL.
|
||||
** But if the table is the right table of a left join, WhereLevel.flags
|
||||
** is set to WO_IN|WO_EQ. The WhereLevel.flags field can then be used as
|
||||
** the "op" parameter to findTerm when we are resolving equality constraints.
|
||||
** ISNULL constraints will then not be used on the right table of a left
|
||||
** join. Tickets #2177 and #2189.
|
||||
*/
|
||||
#define WHERE_ROWID_EQ 0x0001 /* rowid=EXPR or rowid IN (...) */
|
||||
#define WHERE_ROWID_RANGE 0x0002 /* rowid<EXPR and/or rowid>EXPR */
|
||||
#define WHERE_COLUMN_EQ 0x0010 /* x=EXPR or x IN (...) */
|
||||
#define WHERE_COLUMN_RANGE 0x0020 /* x<EXPR and/or x>EXPR */
|
||||
#define WHERE_COLUMN_IN 0x0040 /* x IN (...) */
|
||||
#define WHERE_TOP_LIMIT 0x0100 /* x<EXPR or x<=EXPR constraint */
|
||||
#define WHERE_BTM_LIMIT 0x0200 /* x>EXPR or x>=EXPR constraint */
|
||||
#define WHERE_IDX_ONLY 0x0800 /* Use index only - omit table */
|
||||
#define WHERE_ORDERBY 0x1000 /* Output will appear in correct order */
|
||||
#define WHERE_REVERSE 0x2000 /* Scan in reverse order */
|
||||
#define WHERE_UNIQUE 0x4000 /* Selects no more than one row */
|
||||
#define WHERE_VIRTUALTABLE 0x8000 /* Use virtual-table processing */
|
||||
#define WHERE_ROWID_EQ 0x000100 /* rowid=EXPR or rowid IN (...) */
|
||||
#define WHERE_ROWID_RANGE 0x000200 /* rowid<EXPR and/or rowid>EXPR */
|
||||
#define WHERE_COLUMN_EQ 0x001000 /* x=EXPR or x IN (...) */
|
||||
#define WHERE_COLUMN_RANGE 0x002000 /* x<EXPR and/or x>EXPR */
|
||||
#define WHERE_COLUMN_IN 0x004000 /* x IN (...) */
|
||||
#define WHERE_TOP_LIMIT 0x010000 /* x<EXPR or x<=EXPR constraint */
|
||||
#define WHERE_BTM_LIMIT 0x020000 /* x>EXPR or x>=EXPR constraint */
|
||||
#define WHERE_IDX_ONLY 0x080000 /* Use index only - omit table */
|
||||
#define WHERE_ORDERBY 0x100000 /* Output will appear in correct order */
|
||||
#define WHERE_REVERSE 0x200000 /* Scan in reverse order */
|
||||
#define WHERE_UNIQUE 0x400000 /* Selects no more than one row */
|
||||
#define WHERE_VIRTUALTABLE 0x800000 /* Use virtual-table processing */
|
||||
|
||||
/*
|
||||
** Initialize a preallocated WhereClause structure.
|
||||
|
@ -354,7 +363,7 @@ static int allowedOp(int op){
|
|||
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
|
||||
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
|
||||
assert( TK_GE==TK_EQ+4 );
|
||||
return op==TK_IN || (op>=TK_EQ && op<=TK_GE);
|
||||
return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -388,9 +397,12 @@ static int operatorMask(int op){
|
|||
assert( allowedOp(op) );
|
||||
if( op==TK_IN ){
|
||||
c = WO_IN;
|
||||
}else if( op==TK_ISNULL ){
|
||||
c = WO_ISNULL;
|
||||
}else{
|
||||
c = WO_EQ<<(op-TK_EQ);
|
||||
}
|
||||
assert( op!=TK_ISNULL || c==WO_ISNULL );
|
||||
assert( op!=TK_IN || c==WO_IN );
|
||||
assert( op!=TK_EQ || c==WO_EQ );
|
||||
assert( op!=TK_LT || c==WO_LT );
|
||||
|
@ -422,7 +434,7 @@ static WhereTerm *findTerm(
|
|||
&& pTerm->leftColumn==iColumn
|
||||
&& (pTerm->eOperator & op)!=0
|
||||
){
|
||||
if( iCur>=0 && pIdx ){
|
||||
if( iCur>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
|
||||
Expr *pX = pTerm->pExpr;
|
||||
CollSeq *pColl;
|
||||
char idxaff;
|
||||
|
@ -590,13 +602,17 @@ static void exprAnalyze(
|
|||
Bitmask prereqAll;
|
||||
int nPattern;
|
||||
int isComplete;
|
||||
int op;
|
||||
|
||||
if( sqlite3MallocFailed() ) return;
|
||||
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
|
||||
if( pExpr->op==TK_IN ){
|
||||
op = pExpr->op;
|
||||
if( op==TK_IN ){
|
||||
assert( pExpr->pRight==0 );
|
||||
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
|
||||
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
|
||||
}else if( op==TK_ISNULL ){
|
||||
pTerm->prereqRight = 0;
|
||||
}else{
|
||||
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
|
||||
}
|
||||
|
@ -608,13 +624,13 @@ static void exprAnalyze(
|
|||
pTerm->leftCursor = -1;
|
||||
pTerm->iParent = -1;
|
||||
pTerm->eOperator = 0;
|
||||
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
|
||||
if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
Expr *pRight = pExpr->pRight;
|
||||
if( pLeft->op==TK_COLUMN ){
|
||||
pTerm->leftCursor = pLeft->iTable;
|
||||
pTerm->leftColumn = pLeft->iColumn;
|
||||
pTerm->eOperator = operatorMask(pExpr->op);
|
||||
pTerm->eOperator = operatorMask(op);
|
||||
}
|
||||
if( pRight && pRight->op==TK_COLUMN ){
|
||||
WhereTerm *pNew;
|
||||
|
@ -622,6 +638,10 @@ static void exprAnalyze(
|
|||
if( pTerm->leftCursor>=0 ){
|
||||
int idxNew;
|
||||
pDup = sqlite3ExprDup(pExpr);
|
||||
if( sqlite3MallocFailed() ){
|
||||
sqliteFree(pDup);
|
||||
return;
|
||||
}
|
||||
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
if( idxNew==0 ) return;
|
||||
pNew = &pWC->a[idxNew];
|
||||
|
@ -715,16 +735,15 @@ static void exprAnalyze(
|
|||
if( ok ){
|
||||
ExprList *pList = 0;
|
||||
Expr *pNew, *pDup;
|
||||
Expr *pLeft = 0;
|
||||
for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
|
||||
if( (pOrTerm->flags & TERM_OR_OK)==0 ) continue;
|
||||
pDup = sqlite3ExprDup(pOrTerm->pExpr->pRight);
|
||||
pList = sqlite3ExprListAppend(pList, pDup, 0);
|
||||
pLeft = pOrTerm->pExpr->pLeft;
|
||||
}
|
||||
pDup = sqlite3Expr(TK_COLUMN, 0, 0, 0);
|
||||
if( pDup ){
|
||||
pDup->iTable = iCursor;
|
||||
pDup->iColumn = iColumn;
|
||||
}
|
||||
assert( pLeft!=0 );
|
||||
pDup = sqlite3ExprDup(pLeft);
|
||||
pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
|
||||
if( pNew ){
|
||||
int idxNew;
|
||||
|
@ -857,11 +876,19 @@ static int isSortingIndex(
|
|||
|
||||
/* Match terms of the ORDER BY clause against columns of
|
||||
** the index.
|
||||
**
|
||||
** Note that indices have pIdx->nColumn regular columns plus
|
||||
** one additional column containing the rowid. The rowid column
|
||||
** of the index is also allowed to match against the ORDER BY
|
||||
** clause.
|
||||
*/
|
||||
for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){
|
||||
for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<=pIdx->nColumn; i++){
|
||||
Expr *pExpr; /* The expression of the ORDER BY pTerm */
|
||||
CollSeq *pColl; /* The collating sequence of pExpr */
|
||||
int termSortOrder; /* Sort order for this term */
|
||||
int iColumn; /* The i-th column of the index. -1 for rowid */
|
||||
int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
|
||||
const char *zColl; /* Name of the collating sequence for i-th index term */
|
||||
|
||||
pExpr = pTerm->pExpr;
|
||||
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
|
||||
|
@ -870,9 +897,22 @@ static int isSortingIndex(
|
|||
return 0;
|
||||
}
|
||||
pColl = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
if( pExpr->iColumn!=pIdx->aiColumn[i] ||
|
||||
sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){
|
||||
if( !pColl ){
|
||||
pColl = db->pDfltColl;
|
||||
}
|
||||
if( i<pIdx->nColumn ){
|
||||
iColumn = pIdx->aiColumn[i];
|
||||
if( iColumn==pIdx->pTable->iPKey ){
|
||||
iColumn = -1;
|
||||
}
|
||||
iSortOrder = pIdx->aSortOrder[i];
|
||||
zColl = pIdx->azColl[i];
|
||||
}else{
|
||||
iColumn = -1;
|
||||
iSortOrder = 0;
|
||||
zColl = pColl->zName;
|
||||
}
|
||||
if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
|
||||
/* Term j of the ORDER BY clause does not match column i of the index */
|
||||
if( i<nEqCol ){
|
||||
/* If an index column that is constrained by == fails to match an
|
||||
|
@ -888,8 +928,8 @@ static int isSortingIndex(
|
|||
}
|
||||
assert( pIdx->aSortOrder!=0 );
|
||||
assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
|
||||
assert( pIdx->aSortOrder[i]==0 || pIdx->aSortOrder[i]==1 );
|
||||
termSortOrder = pIdx->aSortOrder[i] ^ pTerm->sortOrder;
|
||||
assert( iSortOrder==0 || iSortOrder==1 );
|
||||
termSortOrder = iSortOrder ^ pTerm->sortOrder;
|
||||
if( i>nEqCol ){
|
||||
if( termSortOrder!=sortOrder ){
|
||||
/* Indices can only be used if all ORDER BY terms past the
|
||||
|
@ -901,13 +941,25 @@ static int isSortingIndex(
|
|||
}
|
||||
j++;
|
||||
pTerm++;
|
||||
if( iColumn<0 ){
|
||||
/* If the indexed column is the primary key and everything matches
|
||||
** so far, then we are assured that the index can be used to sort
|
||||
** because the primary key is unique and so none of the other columns
|
||||
** will make any difference
|
||||
*/
|
||||
j = nTerm;
|
||||
}
|
||||
}
|
||||
|
||||
/* The index can be used for sorting if all terms of the ORDER BY clause
|
||||
** are covered.
|
||||
*/
|
||||
*pbRev = sortOrder!=0;
|
||||
if( j>=nTerm ){
|
||||
*pbRev = sortOrder!=0;
|
||||
/* All terms of the ORDER BY clause are covered by this index so
|
||||
** this index can be used for sorting. */
|
||||
return 1;
|
||||
}
|
||||
if( j==pIdx->nColumn && pIdx->onError!=OE_None ){
|
||||
/* All terms of this index match some prefix of the ORDER BY clause
|
||||
** and this index is UNIQUE, so this index can be used for sorting. */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -928,8 +980,7 @@ static int sortableByRowid(
|
|||
assert( pOrderBy!=0 );
|
||||
assert( pOrderBy->nExpr>0 );
|
||||
p = pOrderBy->a[0].pExpr;
|
||||
if( pOrderBy->nExpr==1 && p->op==TK_COLUMN && p->iTable==base
|
||||
&& p->iColumn==-1 ){
|
||||
if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1 ){
|
||||
*pbRev = pOrderBy->a[0].sortOrder;
|
||||
return 1;
|
||||
}
|
||||
|
@ -1232,6 +1283,7 @@ static double bestIndex(
|
|||
int rev; /* True to scan in reverse order */
|
||||
int flags; /* Flags associated with pProbe */
|
||||
int nEq; /* Number of == or IN constraints */
|
||||
int eqTermMask; /* Mask of valid equality operators */
|
||||
double cost; /* Cost of using pProbe */
|
||||
|
||||
TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
|
||||
|
@ -1323,6 +1375,17 @@ static double bestIndex(
|
|||
bestFlags = flags;
|
||||
}
|
||||
|
||||
/* If the pSrc table is the right table of a LEFT JOIN then we may not
|
||||
** use an index to satisfy IS NULL constraints on that table. This is
|
||||
** because columns might end up being NULL if the table does not match -
|
||||
** a circumstance which the index cannot help us discover. Ticket #2177.
|
||||
*/
|
||||
if( (pSrc->jointype & JT_LEFT)!=0 ){
|
||||
eqTermMask = WO_EQ|WO_IN;
|
||||
}else{
|
||||
eqTermMask = WO_EQ|WO_IN|WO_ISNULL;
|
||||
}
|
||||
|
||||
/* Look at each index.
|
||||
*/
|
||||
for(; pProbe; pProbe=pProbe->pNext){
|
||||
|
@ -1337,7 +1400,7 @@ static double bestIndex(
|
|||
flags = 0;
|
||||
for(i=0; i<pProbe->nColumn; i++){
|
||||
int j = pProbe->aiColumn[i];
|
||||
pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe);
|
||||
pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pProbe);
|
||||
if( pTerm==0 ) break;
|
||||
flags |= WHERE_COLUMN_EQ;
|
||||
if( pTerm->eOperator & WO_IN ){
|
||||
|
@ -1431,7 +1494,7 @@ static double bestIndex(
|
|||
*ppIndex = bestIdx;
|
||||
TRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
|
||||
bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq));
|
||||
*pFlags = bestFlags;
|
||||
*pFlags = bestFlags | eqTermMask;
|
||||
*pnEq = bestNEq;
|
||||
return lowestCost;
|
||||
}
|
||||
|
@ -1476,30 +1539,18 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
|||
}
|
||||
|
||||
/*
|
||||
** Generate code that builds a probe for an index. Details:
|
||||
**
|
||||
** * Check the top nColumn entries on the stack. If any
|
||||
** of those entries are NULL, jump immediately to brk,
|
||||
** which is the loop exit, since no index entry will match
|
||||
** if any part of the key is NULL. Pop (nColumn+nExtra)
|
||||
** elements from the stack.
|
||||
**
|
||||
** * Construct a probe entry from the top nColumn entries in
|
||||
** the stack with affinities appropriate for index pIdx.
|
||||
** Only nColumn elements are popped from the stack in this case
|
||||
** (by OP_MakeRecord).
|
||||
** Generate code that builds a probe for an index.
|
||||
**
|
||||
** There should be nColumn values on the stack. The index
|
||||
** to be probed is pIdx. Pop the values from the stack and
|
||||
** replace them all with a single record that is the index
|
||||
** problem.
|
||||
*/
|
||||
static void buildIndexProbe(
|
||||
Vdbe *v,
|
||||
int nColumn,
|
||||
int nExtra,
|
||||
int brk,
|
||||
Index *pIdx
|
||||
Vdbe *v, /* Generate code into this VM */
|
||||
int nColumn, /* The number of columns to check for NULL */
|
||||
Index *pIdx /* Index that we will be searching */
|
||||
){
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
}
|
||||
|
@ -1523,15 +1574,17 @@ static void codeEqualityTerm(
|
|||
WhereLevel *pLevel /* When level of the FROM clause we are working on */
|
||||
){
|
||||
Expr *pX = pTerm->pExpr;
|
||||
if( pX->op!=TK_IN ){
|
||||
assert( pX->op==TK_EQ );
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( pX->op==TK_EQ ){
|
||||
sqlite3ExprCode(pParse, pX->pRight);
|
||||
}else if( pX->op==TK_ISNULL ){
|
||||
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
}else{
|
||||
int iTab;
|
||||
int *aIn;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
|
||||
assert( pX->op==TK_IN );
|
||||
sqlite3CodeSubselect(pParse, pX);
|
||||
iTab = pX->iTable;
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
|
||||
|
@ -1603,17 +1656,20 @@ static void codeAllEqualityTerms(
|
|||
|
||||
/* Evaluate the equality constraints
|
||||
*/
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
assert( pIdx->nColumn>=nEq );
|
||||
for(j=0; j<nEq; j++){
|
||||
int k = pIdx->aiColumn[j];
|
||||
pTerm = findTerm(pWC, iCur, k, notReady, WO_EQ|WO_IN, pIdx);
|
||||
pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
|
||||
if( pTerm==0 ) break;
|
||||
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||
codeEqualityTerm(pParse, pTerm, brk, pLevel);
|
||||
if( (pTerm->eOperator & WO_ISNULL)==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, termsInMem ? -1 : -(j+1), brk);
|
||||
}
|
||||
if( termsInMem ){
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1);
|
||||
}
|
||||
}
|
||||
assert( j==nEq );
|
||||
|
||||
/* Make sure all the constraint values are on the top of the stack
|
||||
*/
|
||||
|
@ -1850,8 +1906,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
|
||||
int doNotReorder; /* True if this table should not be reordered */
|
||||
|
||||
doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
|
||||
|| (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0);
|
||||
doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
|
||||
if( once && doNotReorder ) break;
|
||||
m = getMask(&maskSet, pTabItem->iCursor);
|
||||
if( (m & notReady)==0 ){
|
||||
|
@ -1986,7 +2041,9 @@ WhereInfo *sqlite3WhereBegin(
|
|||
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,
|
||||
(char*)pKey, P3_KEYINFO_HANDOFF);
|
||||
}
|
||||
if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){
|
||||
if( (pLevel->flags & (WHERE_IDX_ONLY|WHERE_COLUMN_RANGE))!=0 ){
|
||||
/* Only call OP_SetNumColumns on the index if we might later use
|
||||
** OP_Column on the index. */
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
|
||||
}
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
|
@ -2025,7 +2082,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
** initialize a memory cell that records if this table matches any
|
||||
** row of the left table of the join.
|
||||
*/
|
||||
if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
|
||||
if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){
|
||||
if( !pParse->nMem ) pParse->nMem++;
|
||||
pLevel->iLeftJoin = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin);
|
||||
|
@ -2159,7 +2216,6 @@ WhereInfo *sqlite3WhereBegin(
|
|||
int btmEq=0; /* True if btm limit uses ==. False if strictly > */
|
||||
int topOp, btmOp; /* Operators for the top and bottom search bounds */
|
||||
int testOp;
|
||||
int nNotNull; /* Number of rows of index that must be non-NULL */
|
||||
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
|
||||
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
|
||||
|
||||
|
@ -2181,7 +2237,6 @@ WhereInfo *sqlite3WhereBegin(
|
|||
** operator and the top bound is a < or <= operator. For a descending
|
||||
** index the operators are reversed.
|
||||
*/
|
||||
nNotNull = nEq + topLimit;
|
||||
if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){
|
||||
topOp = WO_LT|WO_LE;
|
||||
btmOp = WO_GT|WO_GE;
|
||||
|
@ -2206,6 +2261,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
pX = pTerm->pExpr;
|
||||
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||
sqlite3ExprCode(pParse, pX->pRight);
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), brk);
|
||||
topEq = pTerm->eOperator & (WO_LE|WO_GE);
|
||||
disableTerm(pLevel, pTerm);
|
||||
testOp = OP_IdxGE;
|
||||
|
@ -2216,7 +2272,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
if( testOp!=OP_Noop ){
|
||||
int nCol = nEq + topLimit;
|
||||
pLevel->iMem = pParse->nMem++;
|
||||
buildIndexProbe(v, nCol, nEq, brk, pIdx);
|
||||
buildIndexProbe(v, nCol, pIdx);
|
||||
if( bRev ){
|
||||
int op = topEq ? OP_MoveLe : OP_MoveLt;
|
||||
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
|
||||
|
@ -2244,6 +2300,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
pX = pTerm->pExpr;
|
||||
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||
sqlite3ExprCode(pParse, pX->pRight);
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), brk);
|
||||
btmEq = pTerm->eOperator & (WO_LE|WO_GE);
|
||||
disableTerm(pLevel, pTerm);
|
||||
}else{
|
||||
|
@ -2251,7 +2308,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
}
|
||||
if( nEq>0 || btmLimit ){
|
||||
int nCol = nEq + btmLimit;
|
||||
buildIndexProbe(v, nCol, 0, brk, pIdx);
|
||||
buildIndexProbe(v, nCol, pIdx);
|
||||
if( bRev ){
|
||||
pLevel->iMem = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
||||
|
@ -2278,8 +2335,10 @@ WhereInfo *sqlite3WhereBegin(
|
|||
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont);
|
||||
if( topLimit | btmLimit ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, nEq);
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, 1, cont);
|
||||
}
|
||||
if( !omitTable ){
|
||||
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
|
||||
|
@ -2305,7 +2364,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
/* Generate a single key that will be used to both start and terminate
|
||||
** the search
|
||||
*/
|
||||
buildIndexProbe(v, nEq, 0, brk, pIdx);
|
||||
buildIndexProbe(v, nEq, pIdx);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
|
||||
|
||||
/* Generate code (1) to move to the first matching element of the table.
|
||||
|
@ -2326,8 +2385,6 @@ WhereInfo *sqlite3WhereBegin(
|
|||
sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC);
|
||||
pLevel->op = OP_Next;
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq, cont);
|
||||
if( !omitTable ){
|
||||
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue