aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2013-12-14 18:24:46 +0000
committerdrh <drh@noemail.net>2013-12-14 18:24:46 +0000
commitc8d985e09c2adc83a944889bd6e60e4e86864e3e (patch)
tree462d90e333961e2779b511e3ef74e0505699940a /src
parent65106c77bb5436a3a4ab16193cc9b98b9c09e228 (diff)
parent4a8ee3dfe2afb5f0478b1bcdf94202cdf98a469d (diff)
downloadsqlite-c8d985e09c2adc83a944889bd6e60e4e86864e3e.tar.gz
sqlite-c8d985e09c2adc83a944889bd6e60e4e86864e3e.zip
Merge in all recent preformance enhancements from trunk.
FossilOrigin-Name: 32477642d79615fb85680bdac812ad9655cf6902
Diffstat (limited to 'src')
-rw-r--r--src/backup.c8
-rw-r--r--src/btree.c105
-rw-r--r--src/build.c9
-rw-r--r--src/callback.c1
-rw-r--r--src/func.c4
-rw-r--r--src/main.c26
-rw-r--r--src/malloc.c7
-rw-r--r--src/os_unix.c18
-rw-r--r--src/os_win.c2
-rw-r--r--src/pager.c157
-rw-r--r--src/pager.h3
-rw-r--r--src/pcache1.c53
-rw-r--r--src/printf.c58
-rw-r--r--src/shell.c7
-rw-r--r--src/sqlite.h.in80
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/test1.c37
-rw-r--r--src/test6.c13
-rw-r--r--src/test_vfstrace.c5
-rw-r--r--src/util.c23
-rw-r--r--src/vdbe.c81
-rw-r--r--src/vdbeInt.h2
-rw-r--r--src/vdbeapi.c4
-rw-r--r--src/vdbeaux.c28
-rw-r--r--src/vdbemem.c59
-rw-r--r--src/vdbetrace.c1
-rw-r--r--src/where.c4
27 files changed, 451 insertions, 346 deletions
diff --git a/src/backup.c b/src/backup.c
index 1bac821f3..4a6bc7493 100644
--- a/src/backup.c
+++ b/src/backup.c
@@ -526,7 +526,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
/* Sync the database file to disk. */
if( rc==SQLITE_OK ){
- rc = sqlite3PagerSync(pDestPager);
+ rc = sqlite3PagerSync(pDestPager, 0);
}
}else{
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
@@ -601,10 +601,10 @@ int sqlite3_backup_finish(sqlite3_backup *p){
/* Set the error code of the destination database handle. */
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
- sqlite3Error(p->pDestDb, rc, 0);
-
- /* Exit the mutexes and free the backup context structure. */
if( p->pDestDb ){
+ sqlite3Error(p->pDestDb, rc, 0);
+
+ /* Exit the mutexes and free the backup context structure. */
sqlite3LeaveMutexAndCloseZombie(p->pDestDb);
}
sqlite3BtreeLeave(p->pSrc);
diff --git a/src/btree.c b/src/btree.c
index 30fdf4256..20bed057e 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -1652,7 +1652,7 @@ static int getAndInitPage(
rc = SQLITE_CORRUPT_BKPT;
}else{
rc = btreeGetPage(pBt, pgno, ppPage, bReadonly);
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
rc = btreeInitPage(*ppPage);
if( rc!=SQLITE_OK ){
releasePage(*ppPage);
@@ -1673,10 +1673,11 @@ static void releasePage(MemPage *pPage){
if( pPage ){
assert( pPage->aData );
assert( pPage->pBt );
+ assert( pPage->pDbPage!=0 );
assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- sqlite3PagerUnref(pPage->pDbPage);
+ sqlite3PagerUnrefNotNull(pPage->pDbPage);
}
}
@@ -4192,10 +4193,10 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
/*
** Return a pointer to payload information from the entry that the
** pCur cursor is pointing to. The pointer is to the beginning of
-** the key if skipKey==0 and it points to the beginning of data if
-** skipKey==1. The number of bytes of available key/data is written
-** into *pAmt. If *pAmt==0, then the value returned will not be
-** a valid pointer.
+** the key if index btrees (pPage->intKey==0) and is the data for
+** table btrees (pPage->intKey==1). The number of bytes of available
+** key/data is written into *pAmt. If *pAmt==0, then the value
+** returned will not be a valid pointer.
**
** This routine is an optimization. It is common for the entire key
** and data to fit on the local page and for there to be no overflow
@@ -4208,41 +4209,21 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
** page of the database. The data might change or move the next time
** any btree routine is called.
*/
-static const unsigned char *fetchPayload(
+static const void *fetchPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
- u32 *pAmt, /* Write the number of available bytes here */
- int skipKey /* read beginning at data if this is true */
+ u32 *pAmt /* Write the number of available bytes here */
){
- unsigned char *aPayload;
- MemPage *pPage;
- u32 nKey;
- u32 nLocal;
-
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
assert( pCur->eState==CURSOR_VALID );
+ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorHoldsMutex(pCur) );
- pPage = pCur->apPage[pCur->iPage];
- assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
+ assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
if( pCur->info.nSize==0 ){
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
&pCur->info);
}
- aPayload = pCur->info.pCell;
- aPayload += pCur->info.nHeader;
- if( pPage->intKey ){
- nKey = 0;
- }else{
- nKey = (int)pCur->info.nKey;
- }
- if( skipKey ){
- aPayload += nKey;
- nLocal = pCur->info.nLocal - nKey;
- }else{
- nLocal = pCur->info.nLocal;
- assert( nLocal<=nKey );
- }
- *pAmt = nLocal;
- return aPayload;
+ *pAmt = pCur->info.nLocal;
+ return (void*)(pCur->info.pCell + pCur->info.nHeader);
}
@@ -4261,22 +4242,10 @@ static const unsigned char *fetchPayload(
** in the common case where no overflow pages are used.
*/
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){
- const void *p = 0;
- assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
- assert( cursorHoldsMutex(pCur) );
- if( ALWAYS(pCur->eState==CURSOR_VALID) ){
- p = (const void*)fetchPayload(pCur, pAmt, 0);
- }
- return p;
+ return fetchPayload(pCur, pAmt);
}
const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
- const void *p = 0;
- assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
- assert( cursorHoldsMutex(pCur) );
- if( ALWAYS(pCur->eState==CURSOR_VALID) ){
- p = (const void*)fetchPayload(pCur, pAmt, 1);
- }
- return p;
+ return fetchPayload(pCur, pAmt);
}
@@ -4395,8 +4364,6 @@ static void moveToParent(BtCursor *pCur){
static int moveToRoot(BtCursor *pCur){
MemPage *pRoot;
int rc = SQLITE_OK;
- Btree *p = pCur->pBtree;
- BtShared *pBt = p->pBt;
assert( cursorHoldsMutex(pCur) );
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
@@ -4411,16 +4378,12 @@ static int moveToRoot(BtCursor *pCur){
}
if( pCur->iPage>=0 ){
- int i;
- for(i=1; i<=pCur->iPage; i++){
- releasePage(pCur->apPage[i]);
- }
- pCur->iPage = 0;
+ while( pCur->iPage ) releasePage(pCur->apPage[pCur->iPage--]);
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}else{
- rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0],
+ rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
@@ -4453,14 +4416,16 @@ static int moveToRoot(BtCursor *pCur){
pCur->atLast = 0;
pCur->validNKey = 0;
- if( pRoot->nCell==0 && !pRoot->leaf ){
+ if( pRoot->nCell>0 ){
+ pCur->eState = CURSOR_VALID;
+ }else if( !pRoot->leaf ){
Pgno subpage;
if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT;
subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
pCur->eState = CURSOR_VALID;
rc = moveToChild(pCur, subpage);
}else{
- pCur->eState = ((pRoot->nCell>0)?CURSOR_VALID:CURSOR_INVALID);
+ pCur->eState = CURSOR_INVALID;
}
return rc;
}
@@ -4716,9 +4681,7 @@ int sqlite3BtreeMovetoUnpacked(
** 2 bytes of the cell.
*/
nCell = pCell[0];
- if( nCell<=pPage->max1bytePayload
- /* && (pCell+nCell)<pPage->aDataEnd */
- ){
+ if( nCell<=pPage->max1bytePayload ){
/* This branch runs if the record-size field of the cell is a
** single byte varint and the record fits entirely on the main
** b-tree page. */
@@ -4726,7 +4689,6 @@ int sqlite3BtreeMovetoUnpacked(
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
}else if( !(pCell[1] & 0x80)
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
- /* && (pCell+nCell+2)<=pPage->aDataEnd */
){
/* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
@@ -5550,7 +5512,7 @@ static int fillInCell(
nHeader += 4;
}
if( pPage->hasData ){
- nHeader += putVarint(&pCell[nHeader], nData+nZero);
+ nHeader += putVarint32(&pCell[nHeader], nData+nZero);
}else{
nData = nZero = 0;
}
@@ -5678,7 +5640,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
u32 pc; /* Offset to cell content of cell being deleted */
u8 *data; /* pPage->aData */
u8 *ptr; /* Used to move bytes around within data[] */
- u8 *endPtr; /* End of loop */
int rc; /* The return code */
int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */
@@ -5703,13 +5664,8 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
*pRC = rc;
return;
}
- endPtr = &pPage->aCellIdx[2*pPage->nCell - 2];
- assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */
- while( ptr<endPtr ){
- *(u16*)ptr = *(u16*)&ptr[2];
- ptr += 2;
- }
pPage->nCell--;
+ memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
put2byte(&data[hdr+3], pPage->nCell);
pPage->nFree += 2;
}
@@ -5746,9 +5702,6 @@ static void insertCell(
int ins; /* Index in data[] where new cell pointer is inserted */
int cellOffset; /* Address of first cell pointer in data[] */
u8 *data; /* The content of the whole page */
- u8 *ptr; /* Used for moving information around in data[] */
- u8 *endPtr; /* End of the loop */
-
int nSkip = (iChild ? 4 : 0);
if( *pRC ) return;
@@ -5799,13 +5752,7 @@ static void insertCell(
if( iChild ){
put4byte(&data[idx], iChild);
}
- ptr = &data[end];
- endPtr = &data[ins];
- assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */
- while( ptr>endPtr ){
- *(u16*)ptr = *(u16*)&ptr[-2];
- ptr -= 2;
- }
+ memmove(&data[ins+2], &data[ins], end-ins);
put2byte(&data[ins], idx);
put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -7767,7 +7714,7 @@ static void checkAppendMsg(
sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1);
}
if( zMsg1 ){
- sqlite3StrAccumAppend(&pCheck->errMsg, zMsg1, -1);
+ sqlite3StrAccumAppendAll(&pCheck->errMsg, zMsg1);
}
sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
va_end(ap);
diff --git a/src/build.c b/src/build.c
index fd512358b..c83ce57cf 100644
--- a/src/build.c
+++ b/src/build.c
@@ -3989,9 +3989,9 @@ void sqlite3UniqueConstraint(
for(j=0; j<pIdx->nKeyCol; j++){
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
- sqlite3StrAccumAppend(&errMsg, pTab->zName, -1);
+ sqlite3StrAccumAppendAll(&errMsg, pTab->zName);
sqlite3StrAccumAppend(&errMsg, ".", 1);
- sqlite3StrAccumAppend(&errMsg, zCol, -1);
+ sqlite3StrAccumAppendAll(&errMsg, zCol);
}
zErr = sqlite3StrAccumFinish(&errMsg);
sqlite3HaltConstraint(pParse,
@@ -4183,8 +4183,9 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
assert( sqlite3KeyInfoIsWriteable(pKey) );
for(i=0; i<nCol; i++){
char *zColl = pIdx->azColl[i];
- if( NEVER(zColl==0) ) zColl = "BINARY";
- pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl);
+ assert( zColl!=0 );
+ pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
+ sqlite3LocateCollSeq(pParse, zColl);
pKey->aSortOrder[i] = pIdx->aSortOrder[i];
}
if( pParse->nErr ){
diff --git a/src/callback.c b/src/callback.c
index 66fa49089..260fe806b 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -357,7 +357,6 @@ FuncDef *sqlite3FindFunction(
assert( nArg>=(-2) );
assert( nArg>=(-1) || createFlag==0 );
- assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
/* First search for a match amongst the application-defined functions.
diff --git a/src/func.c b/src/func.c
index 46c606ac0..951af97b3 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1511,11 +1511,11 @@ static void groupConcatStep(
zSep = ",";
nSep = 1;
}
- sqlite3StrAccumAppend(pAccum, zSep, nSep);
+ if( nSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
}
zVal = (char*)sqlite3_value_text(argv[0]);
nVal = sqlite3_value_bytes(argv[0]);
- sqlite3StrAccumAppend(pAccum, zVal, nVal);
+ if( nVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal);
}
}
static void groupConcatFinalize(sqlite3_context *context){
diff --git a/src/main.c b/src/main.c
index 7c8f1739f..c62aa3648 100644
--- a/src/main.c
+++ b/src/main.c
@@ -588,7 +588,8 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
db->lookaside.bEnabled = 1;
db->lookaside.bMalloced = pBuf==0 ?1:0;
}else{
- db->lookaside.pEnd = 0;
+ db->lookaside.pStart = db;
+ db->lookaside.pEnd = db;
db->lookaside.bEnabled = 0;
db->lookaside.bMalloced = 0;
}
@@ -986,9 +987,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
#endif
sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
- if( db->pErr ){
- sqlite3ValueFree(db->pErr);
- }
+ sqlite3ValueFree(db->pErr);
sqlite3CloseExtensions(db);
db->magic = SQLITE_MAGIC_ERROR;
@@ -1086,6 +1085,7 @@ const char *sqlite3ErrName(int rc){
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break;
+ case SQLITE_READONLY_DBMOVED: zName = "SQLITE_READONLY_DBMOVED"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break;
@@ -1370,6 +1370,7 @@ int sqlite3CreateFunc(
){
FuncDef *p;
int nName;
+ int extraFlags;
assert( sqlite3_mutex_held(db->mutex) );
if( zFunctionName==0 ||
@@ -1380,6 +1381,10 @@ int sqlite3CreateFunc(
(255<(nName = sqlite3Strlen30( zFunctionName))) ){
return SQLITE_MISUSE_BKPT;
}
+
+ assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
+ extraFlags = enc & SQLITE_DETERMINISTIC;
+ enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
#ifndef SQLITE_OMIT_UTF16
/* If SQLITE_UTF16 is specified as the encoding type, transform this
@@ -1393,10 +1398,10 @@ int sqlite3CreateFunc(
enc = SQLITE_UTF16NATIVE;
}else if( enc==SQLITE_ANY ){
int rc;
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
pUserData, xFunc, xStep, xFinal, pDestructor);
if( rc==SQLITE_OK ){
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
pUserData, xFunc, xStep, xFinal, pDestructor);
}
if( rc!=SQLITE_OK ){
@@ -1439,7 +1444,8 @@ int sqlite3CreateFunc(
pDestructor->nRef++;
}
p->pDestructor = pDestructor;
- p->funcFlags &= SQLITE_FUNC_ENCMASK;
+ p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
+ testcase( p->funcFlags & SQLITE_DETERMINISTIC );
p->xFunc = xFunc;
p->xStep = xStep;
p->xFinalize = xFinal;
@@ -1890,6 +1896,7 @@ const char *sqlite3_errmsg(sqlite3 *db){
if( db->mallocFailed ){
z = sqlite3ErrStr(SQLITE_NOMEM);
}else{
+ testcase( db->pErr==0 );
z = (char*)sqlite3_value_text(db->pErr);
assert( !db->mallocFailed );
if( z==0 ){
@@ -1931,8 +1938,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
}else{
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
- sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
- SQLITE_UTF8, SQLITE_STATIC);
+ sqlite3Error(db, db->errCode, sqlite3ErrStr(db->errCode));
z = sqlite3_value_text16(db->pErr);
}
/* A malloc() may have failed within the call to sqlite3_value_text16()
@@ -2646,8 +2652,6 @@ static int openDatabase(
}
#endif
- sqlite3Error(db, rc, 0);
-
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
** mode. Doing nothing at all also makes NORMAL the default.
diff --git a/src/malloc.c b/src/malloc.c
index 799f0485d..9c11d0776 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -433,7 +433,7 @@ void sqlite3ScratchFree(void *p){
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, void *p){
- return p && p>=db->lookaside.pStart && p<db->lookaside.pEnd;
+ return p>=db->lookaside.pStart && p<db->lookaside.pEnd;
}
#else
#define isLookaside(A,B) 0
@@ -449,8 +449,9 @@ int sqlite3MallocSize(void *p){
return sqlite3GlobalConfig.m.xSize(p);
}
int sqlite3DbMallocSize(sqlite3 *db, void *p){
- assert( db==0 || sqlite3_mutex_held(db->mutex) );
- if( db && isLookaside(db, p) ){
+ assert( db!=0 );
+ assert( sqlite3_mutex_held(db->mutex) );
+ if( isLookaside(db, p) ){
return db->lookaside.sz;
}else{
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
diff --git a/src/os_unix.c b/src/os_unix.c
index ab657dc7b..485b32fd9 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -1315,6 +1315,15 @@ static int findInodeInfo(
return SQLITE_OK;
}
+/*
+** Return TRUE if pFile has been renamed or unlinked since it was first opened.
+*/
+static int fileHasMoved(unixFile *pFile){
+ struct stat buf;
+ return pFile->pInode!=0 &&
+ (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
+}
+
/*
** Check a unixFile that is a database. Verify the following:
@@ -1349,10 +1358,7 @@ static void verifyDbFile(unixFile *pFile){
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
- if( pFile->pInode!=0
- && ((rc = osStat(pFile->zPath, &buf))!=0
- || buf.st_ino!=pFile->pInode->fileId.ino)
- ){
+ if( fileHasMoved(pFile) ){
sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
@@ -3801,6 +3807,10 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
+ case SQLITE_FCNTL_HAS_MOVED: {
+ *(int*)pArg = fileHasMoved(pFile);
+ return SQLITE_OK;
+ }
#if SQLITE_MAX_MMAP_SIZE>0
case SQLITE_FCNTL_MMAP_SIZE: {
i64 newLimit = *(i64*)pArg;
diff --git a/src/os_win.c b/src/os_win.c
index 22052a3fe..faa60569c 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -3119,7 +3119,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
return SQLITE_OK;
}
case SQLITE_FCNTL_VFSNAME: {
- *(char**)pArg = sqlite3_mprintf("win32");
+ *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
diff --git a/src/pager.c b/src/pager.c
index d675b8582..954ba7f1e 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -1024,15 +1024,12 @@ static char *print_pager_state(Pager *p){
static int subjRequiresPage(PgHdr *pPg){
Pager *pPager = pPg->pPager;
PagerSavepoint *p;
- Pgno pgno;
+ Pgno pgno = pPg->pgno;
int i;
- if( pPager->nSavepoint ){
- pgno = pPg->pgno;
- for(i=0; i<pPager->nSavepoint; i++){
- p = &pPager->aSavepoint[i];
- if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
- return 1;
- }
+ for(i=0; i<pPager->nSavepoint; i++){
+ p = &pPager->aSavepoint[i];
+ if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
+ return 1;
}
}
return 0;
@@ -1041,8 +1038,8 @@ static int subjRequiresPage(PgHdr *pPg){
/*
** Return true if the page is already in the journal file.
*/
-static int pageInJournal(PgHdr *pPg){
- return sqlite3BitvecTest(pPg->pPager->pInJournal, pPg->pgno);
+static int pageInJournal(Pager *pPager, PgHdr *pPg){
+ return sqlite3BitvecTest(pPager->pInJournal, pPg->pgno);
}
/*
@@ -1249,6 +1246,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
|| len>=nMaster
+ || len==0
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
|| memcmp(aMagic, aJournalMagic, 8)
@@ -1989,7 +1987,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
PgHdr *p = pager_lookup(pPager, 1);
if( p ){
p->pageHash = 0;
- sqlite3PagerUnref(p);
+ sqlite3PagerUnrefNotNull(p);
}
}
#endif
@@ -2018,6 +2016,11 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
rc = pager_truncate(pPager, pPager->dbSize);
}
+ if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){
+ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0);
+ if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
+ }
+
if( !pPager->exclusiveMode
&& (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
){
@@ -2831,7 +2834,7 @@ end_playback:
if( rc==SQLITE_OK
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
){
- rc = sqlite3PagerSync(pPager);
+ rc = sqlite3PagerSync(pPager, 0);
}
if( rc==SQLITE_OK ){
rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
@@ -2977,7 +2980,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
if( rc==SQLITE_OK ){
pPager->xReiniter(pPg);
}
- sqlite3PagerUnref(pPg);
+ sqlite3PagerUnrefNotNull(pPg);
}
}
@@ -4332,7 +4335,7 @@ static int subjournalPage(PgHdr *pPg){
assert( isOpen(pPager->jfd) || pagerUseWal(pPager) );
assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 );
assert( pagerUseWal(pPager)
- || pageInJournal(pPg)
+ || pageInJournal(pPager, pPg)
|| pPg->pgno>pPager->dbOrigSize
);
rc = openSubJournal(pPager);
@@ -4797,6 +4800,30 @@ int sqlite3PagerOpen(
}
+/* Verify that the database file has not be deleted or renamed out from
+** under the pager. Return SQLITE_OK if the database is still were it ought
+** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
+** code from sqlite3OsAccess()) if the database has gone missing.
+*/
+static int databaseIsUnmoved(Pager *pPager){
+ int bHasMoved = 0;
+ int rc;
+
+ if( pPager->tempFile ) return SQLITE_OK;
+ if( pPager->dbSize==0 ) return SQLITE_OK;
+ assert( pPager->zFilename && pPager->zFilename[0] );
+ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
+ if( rc==SQLITE_NOTFOUND ){
+ /* If the HAS_MOVED file-control is unimplemented, assume that the file
+ ** has not been moved. That is the historical behavior of SQLite: prior to
+ ** version 3.8.3, it never checked */
+ rc = SQLITE_OK;
+ }else if( rc==SQLITE_OK && bHasMoved ){
+ rc = SQLITE_READONLY_DBMOVED;
+ }
+ return rc;
+}
+
/*
** This function is called after transitioning from PAGER_UNLOCK to
@@ -5268,7 +5295,7 @@ int sqlite3PagerAcquire(
if( rc!=SQLITE_OK ) goto pager_acquire_err;
}
- if( iFrame==0 && bMmapOk ){
+ if( bMmapOk && iFrame==0 ){
void *pData = 0;
rc = sqlite3OsFetch(pPager->fd,
@@ -5409,16 +5436,19 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
** are released, a rollback occurs and the lock on the database is
** removed.
*/
-void sqlite3PagerUnref(DbPage *pPg){
- if( pPg ){
- Pager *pPager = pPg->pPager;
- if( pPg->flags & PGHDR_MMAP ){
- pagerReleaseMapPage(pPg);
- }else{
- sqlite3PcacheRelease(pPg);
- }
- pagerUnlockIfUnused(pPager);
+void sqlite3PagerUnrefNotNull(DbPage *pPg){
+ Pager *pPager;
+ assert( pPg!=0 );
+ pPager = pPg->pPager;
+ if( pPg->flags & PGHDR_MMAP ){
+ pagerReleaseMapPage(pPg);
+ }else{
+ sqlite3PcacheRelease(pPg);
}
+ pagerUnlockIfUnused(pPager);
+}
+void sqlite3PagerUnref(DbPage *pPg){
+ if( pPg ) sqlite3PagerUnrefNotNull(pPg);
}
/*
@@ -5473,13 +5503,19 @@ static int pager_open_journal(Pager *pPager){
(SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
(SQLITE_OPEN_MAIN_JOURNAL)
);
- #ifdef SQLITE_ENABLE_ATOMIC_WRITE
- rc = sqlite3JournalOpen(
- pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
- );
- #else
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
- #endif
+
+ /* Verify that the database still has the same name as it did when
+ ** it was originally opened. */
+ rc = databaseIsUnmoved(pPager);
+ if( rc==SQLITE_OK ){
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ rc = sqlite3JournalOpen(
+ pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
+ );
+#else
+ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
+#endif
+ }
}
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
}
@@ -5600,9 +5636,9 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
** of any open savepoints as appropriate.
*/
static int pager_write(PgHdr *pPg){
- void *pData = pPg->pData;
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
+ int inJournal;
/* This routine is not called unless a write-transaction has already
** been started. The journal file may or may not be open at this point.
@@ -5613,14 +5649,8 @@ static int pager_write(PgHdr *pPg){
|| pPager->eState==PAGER_WRITER_DBMOD
);
assert( assert_pager_state(pPager) );
-
- /* If an error has been previously detected, report the same error
- ** again. This should not happen, but the check provides robustness. */
- if( NEVER(pPager->errCode) ) return pPager->errCode;
-
- /* Higher-level routines never call this function if database is not
- ** writable. But check anyway, just for robustness. */
- if( NEVER(pPager->readOnly) ) return SQLITE_PERM;
+ assert( pPager->errCode==0 );
+ assert( pPager->readOnly==0 );
CHECK_PAGE(pPg);
@@ -5644,7 +5674,8 @@ static int pager_write(PgHdr *pPg){
** to the journal then we can return right away.
*/
sqlite3PcacheMakeDirty(pPg);
- if( pageInJournal(pPg) && !subjRequiresPage(pPg) ){
+ inJournal = pageInJournal(pPager, pPg);
+ if( inJournal && (pPager->nSavepoint==0 || !subjRequiresPage(pPg)) ){
assert( !pagerUseWal(pPager) );
}else{
@@ -5652,7 +5683,7 @@ static int pager_write(PgHdr *pPg){
** EXCLUSIVE lock on the main database file. Write the current page to
** the transaction journal if it is not there already.
*/
- if( !pageInJournal(pPg) && !pagerUseWal(pPager) ){
+ if( !inJournal && !pagerUseWal(pPager) ){
assert( pagerUseWal(pPager)==0 );
if( pPg->pgno<=pPager->dbOrigSize && isOpen(pPager->jfd) ){
u32 cksum;
@@ -5665,7 +5696,7 @@ static int pager_write(PgHdr *pPg){
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
assert( pPager->journalHdr<=pPager->journalOff );
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
+ CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
cksum = pager_cksum(pPager, (u8*)pData2);
/* Even if an IO or diskfull error occurs while journalling the
@@ -5717,7 +5748,7 @@ static int pager_write(PgHdr *pPg){
** the statement journal format differs from the standard journal format
** in that it omits the checksums and the header.
*/
- if( subjRequiresPage(pPg) ){
+ if( pPager->nSavepoint>0 && subjRequiresPage(pPg) ){
rc = subjournalPage(pPg);
}
}
@@ -5749,19 +5780,19 @@ int sqlite3PagerWrite(DbPage *pDbPage){
PgHdr *pPg = pDbPage;
Pager *pPager = pPg->pPager;
- Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
assert( (pPg->flags & PGHDR_MMAP)==0 );
assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( pPager->eState!=PAGER_ERROR );
assert( assert_pager_state(pPager) );
- if( nPagePerSector>1 ){
+ if( pPager->sectorSize > (u32)pPager->pageSize ){
Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */
int nPage = 0; /* Number of pages starting at pg1 to journal */
int ii; /* Loop counter */
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
+ Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
** a journal header to be written between the pages journaled by
@@ -5800,14 +5831,14 @@ int sqlite3PagerWrite(DbPage *pDbPage){
if( pPage->flags&PGHDR_NEED_SYNC ){
needSync = 1;
}
- sqlite3PagerUnref(pPage);
+ sqlite3PagerUnrefNotNull(pPage);
}
}
}else if( (pPage = pager_lookup(pPager, pg))!=0 ){
if( pPage->flags&PGHDR_NEED_SYNC ){
needSync = 1;
}
- sqlite3PagerUnref(pPage);
+ sqlite3PagerUnrefNotNull(pPage);
}
}
@@ -5823,7 +5854,7 @@ int sqlite3PagerWrite(DbPage *pDbPage){
PgHdr *pPage = pager_lookup(pPager, pg1+ii);
if( pPage ){
pPage->flags |= PGHDR_NEED_SYNC;
- sqlite3PagerUnref(pPage);
+ sqlite3PagerUnrefNotNull(pPage);
}
}
}
@@ -5976,17 +6007,17 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
** If successful, or if called on a pager for which it is a no-op, this
** function returns SQLITE_OK. Otherwise, an IO error code is returned.
*/
-int sqlite3PagerSync(Pager *pPager){
+int sqlite3PagerSync(Pager *pPager, const char *zMaster){
int rc = SQLITE_OK;
- if( !pPager->noSync ){
+
+ if( isOpen(pPager->fd) ){
+ void *pArg = (void*)zMaster;
+ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
+ if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
+ }
+ if( rc==SQLITE_OK && !pPager->noSync ){
assert( !MEMDB );
rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
- }else if( isOpen(pPager->fd) ){
- assert( !MEMDB );
- rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, 0);
- if( rc==SQLITE_NOTFOUND ){
- rc = SQLITE_OK;
- }
}
return rc;
}
@@ -6185,7 +6216,7 @@ int sqlite3PagerCommitPhaseOne(
/* Finally, sync the database file. */
if( !noSync ){
- rc = sqlite3PagerSync(pPager);
+ rc = sqlite3PagerSync(pPager, zMaster);
}
IOTRACE(("DBSYNC %p\n", pPager))
}
@@ -6314,7 +6345,9 @@ int sqlite3PagerRollback(Pager *pPager){
assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
- || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR );
+ || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR
+ || rc==SQLITE_CANTOPEN
+ );
/* If an error occurs during a ROLLBACK, we can no longer trust the pager
** cache. So call pager_error() on the way out to make any error persistent.
@@ -6717,7 +6750,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
needSyncPgno = pPg->pgno;
assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
- pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
+ pageInJournal(pPager, pPg) || pPg->pgno>pPager->dbOrigSize );
assert( pPg->flags&PGHDR_DIRTY );
}
@@ -6751,7 +6784,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
if( MEMDB ){
assert( pPgOld );
sqlite3PcacheMove(pPgOld, origPgno);
- sqlite3PagerUnref(pPgOld);
+ sqlite3PagerUnrefNotNull(pPgOld);
}
if( needSyncPgno ){
@@ -6780,7 +6813,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
}
pPgHdr->flags |= PGHDR_NEED_SYNC;
sqlite3PcacheMakeDirty(pPgHdr);
- sqlite3PagerUnref(pPgHdr);
+ sqlite3PagerUnrefNotNull(pPgHdr);
}
return SQLITE_OK;
diff --git a/src/pager.h b/src/pager.h
index 7851d2834..c9ca8553b 100644
--- a/src/pager.h
+++ b/src/pager.h
@@ -136,6 +136,7 @@ int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
void sqlite3PagerRef(DbPage*);
void sqlite3PagerUnref(DbPage*);
+void sqlite3PagerUnrefNotNull(DbPage*);
/* Operations on page references. */
int sqlite3PagerWrite(DbPage*);
@@ -150,7 +151,7 @@ void sqlite3PagerPagecount(Pager*, int*);
int sqlite3PagerBegin(Pager*, int exFlag, int);
int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
int sqlite3PagerExclusiveLock(Pager*);
-int sqlite3PagerSync(Pager *pPager);
+int sqlite3PagerSync(Pager *pPager, const char *zMaster);
int sqlite3PagerCommitPhaseTwo(Pager*);
int sqlite3PagerRollback(Pager*);
int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
diff --git a/src/pcache1.c b/src/pcache1.c
index df9d87753..f173e23fe 100644
--- a/src/pcache1.c
+++ b/src/pcache1.c
@@ -96,6 +96,7 @@ struct PCache1 {
struct PgHdr1 {
sqlite3_pcache_page page;
unsigned int iKey; /* Key value (page number) */
+ u8 isPinned; /* Page in use, not on the LRU list */
PgHdr1 *pNext; /* Next in hash table chain */
PCache1 *pCache; /* Cache that currently owns this page */
PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
@@ -424,34 +425,32 @@ static int pcache1ResizeHash(PCache1 *p){
** LRU list, then this function is a no-op.
**
** The PGroup mutex must be held when this function is called.
-**
-** If pPage is NULL then this routine is a no-op.
*/
static void pcache1PinPage(PgHdr1 *pPage){
PCache1 *pCache;
PGroup *pGroup;
- if( pPage==0 ) return;
+ assert( pPage!=0 );
+ assert( pPage->isPinned==0 );
pCache = pPage->pCache;
pGroup = pCache->pGroup;
+ assert( pPage->pLruNext || pPage==pGroup->pLruTail );
+ assert( pPage->pLruPrev || pPage==pGroup->pLruHead );
assert( sqlite3_mutex_held(pGroup->mutex) );
- if( pPage->pLruNext || pPage==pGroup->pLruTail ){
- if( pPage->pLruPrev ){
- pPage->pLruPrev->pLruNext = pPage->pLruNext;
- }
- if( pPage->pLruNext ){
- pPage->pLruNext->pLruPrev = pPage->pLruPrev;
- }
- if( pGroup->pLruHead==pPage ){
- pGroup->pLruHead = pPage->pLruNext;
- }
- if( pGroup->pLruTail==pPage ){
- pGroup->pLruTail = pPage->pLruPrev;
- }
- pPage->pLruNext = 0;
- pPage->pLruPrev = 0;
- pPage->pCache->nRecyclable--;
+ if( pPage->pLruPrev ){
+ pPage->pLruPrev->pLruNext = pPage->pLruNext;
+ }else{
+ pGroup->pLruHead = pPage->pLruNext;
+ }
+ if( pPage->pLruNext ){
+ pPage->pLruNext->pLruPrev = pPage->pLruPrev;
+ }else{
+ pGroup->pLruTail = pPage->pLruPrev;
}
+ pPage->pLruNext = 0;
+ pPage->pLruPrev = 0;
+ pPage->isPinned = 1;
+ pCache->nRecyclable--;
}
@@ -483,6 +482,7 @@ static void pcache1EnforceMaxPage(PGroup *pGroup){
while( pGroup->nCurrentPage>pGroup->nMaxPage && pGroup->pLruTail ){
PgHdr1 *p = pGroup->pLruTail;
assert( p->pCache->pGroup==pGroup );
+ assert( p->isPinned==0 );
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
@@ -510,7 +510,7 @@ static void pcache1TruncateUnsafe(
if( pPage->iKey>=iLimit ){
pCache->nPage--;
*pp = pPage->pNext;
- pcache1PinPage(pPage);
+ if( !pPage->isPinned ) pcache1PinPage(pPage);
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
@@ -733,8 +733,11 @@ static sqlite3_pcache_page *pcache1Fetch(
}
/* Step 2: Abort if no existing page is found and createFlag is 0 */
- if( pPage || createFlag==0 ){
- pcache1PinPage(pPage);
+ if( pPage ){
+ if( !pPage->isPinned ) pcache1PinPage(pPage);
+ goto fetch_out;
+ }
+ if( createFlag==0 ){
goto fetch_out;
}
@@ -775,6 +778,7 @@ static sqlite3_pcache_page *pcache1Fetch(
)){
PCache1 *pOther;
pPage = pGroup->pLruTail;
+ assert( pPage->isPinned==0 );
pcache1RemoveFromHash(pPage);
pcache1PinPage(pPage);
pOther = pPage->pCache;
@@ -811,6 +815,7 @@ static sqlite3_pcache_page *pcache1Fetch(
pPage->pCache = pCache;
pPage->pLruPrev = 0;
pPage->pLruNext = 0;
+ pPage->isPinned = 1;
*(void **)pPage->page.pExtra = 0;
pCache->apHash[h] = pPage;
}
@@ -846,6 +851,7 @@ static void pcache1Unpin(
*/
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
+ assert( pPage->isPinned==1 );
if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
pcache1RemoveFromHash(pPage);
@@ -861,6 +867,7 @@ static void pcache1Unpin(
pGroup->pLruHead = pPage;
}
pCache->nRecyclable++;
+ pPage->isPinned = 0;
}
pcache1LeaveMutex(pCache->pGroup);
@@ -987,6 +994,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
nFree += sqlite3MemSize(p);
#endif
+ assert( p->isPinned==0 );
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
@@ -1011,6 +1019,7 @@ void sqlite3PcacheStats(
PgHdr1 *p;
int nRecyclable = 0;
for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
+ assert( p->isPinned==0 );
nRecyclable++;
}
*pnCurrent = pcache1.grp.nCurrentPage;
diff --git a/src/printf.c b/src/printf.c
index f9e5c6406..3279a54f2 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -149,6 +149,14 @@ void sqlite3AppendSpace(StrAccum *pAccum, int N){
}
/*
+** Set the StrAccum object to an error mode.
+*/
+void setStrAccumError(StrAccum *p, u8 eError){
+ p->accError = eError;
+ p->nAlloc = 0;
+}
+
+/*
** On machines with a small stack size, you can redefine the
** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired.
*/
@@ -359,7 +367,7 @@ void sqlite3VXPrintf(
nOut = precision + 10;
zOut = zExtra = sqlite3Malloc( nOut );
if( zOut==0 ){
- pAccum->accError = STRACCUM_NOMEM;
+ setStrAccumError(pAccum, STRACCUM_NOMEM);
return;
}
}
@@ -471,7 +479,7 @@ void sqlite3VXPrintf(
if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){
bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 );
if( bufpt==0 ){
- pAccum->accError = STRACCUM_NOMEM;
+ setStrAccumError(pAccum, STRACCUM_NOMEM);
return;
}
}
@@ -606,7 +614,7 @@ void sqlite3VXPrintf(
if( n>etBUFSIZE ){
bufpt = zExtra = sqlite3Malloc( n );
if( bufpt==0 ){
- pAccum->accError = STRACCUM_NOMEM;
+ setStrAccumError(pAccum, STRACCUM_NOMEM);
return;
}
}else{
@@ -629,7 +637,7 @@ void sqlite3VXPrintf(
}
case etTOKEN: {
Token *pToken = va_arg(ap, Token*);
- if( pToken ){
+ if( pToken && pToken->n ){
sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
}
length = width = 0;
@@ -641,10 +649,10 @@ void sqlite3VXPrintf(
struct SrcList_item *pItem = &pSrc->a[k];
assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase ){
- sqlite3StrAccumAppend(pAccum, pItem->zDatabase, -1);
+ sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase);
sqlite3StrAccumAppend(pAccum, ".", 1);
}
- sqlite3StrAccumAppend(pAccum, pItem->zName, -1);
+ sqlite3StrAccumAppendAll(pAccum, pItem->zName);
length = width = 0;
break;
}
@@ -675,7 +683,7 @@ void sqlite3VXPrintf(
sqlite3AppendSpace(pAccum, nspace);
}
}
- sqlite3_free(zExtra);
+ if( zExtra ) sqlite3_free(zExtra);
}/* End for loop over the format string */
} /* End of function */
@@ -683,22 +691,20 @@ void sqlite3VXPrintf(
** Append N bytes of text from z to the StrAccum object.
*/
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
- assert( z!=0 || N==0 );
- if( p->accError ){
- testcase(p->accError==STRACCUM_TOOBIG);
- testcase(p->accError==STRACCUM_NOMEM);
- return;
- }
- assert( p->zText!=0 || p->nChar==0 );
- if( N<=0 ){
- if( N==0 || z[0]==0 ) return;
- N = sqlite3Strlen30(z);
- }
+ assert( z!=0 );
+ assert( p->zText!=0 || p->nChar==0 || p->accError );
+ assert( N>=0 );
+ assert( p->accError==0 || p->nAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
char *zNew;
+ if( p->accError ){
+ testcase(p->accError==STRACCUM_TOOBIG);
+ testcase(p->accError==STRACCUM_NOMEM);
+ return;
+ }
if( !p->useMalloc ){
- p->accError = STRACCUM_TOOBIG;
N = p->nAlloc - p->nChar - 1;
+ setStrAccumError(p, STRACCUM_TOOBIG);
if( N<=0 ){
return;
}
@@ -708,7 +714,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
szNew += N + 1;
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
- p->accError = STRACCUM_TOOBIG;
+ setStrAccumError(p, STRACCUM_TOOBIG);
return;
}else{
p->nAlloc = (int)szNew;
@@ -722,8 +728,8 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
}else{
- p->accError = STRACCUM_NOMEM;
sqlite3StrAccumReset(p);
+ setStrAccumError(p, STRACCUM_NOMEM);
return;
}
}
@@ -734,6 +740,14 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
}
/*
+** Append the complete text of zero-terminated string z[] to the p string.
+*/
+void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
+ sqlite3StrAccumAppend(p, z, sqlite3Strlen30(z));
+}
+
+
+/*
** Finish off a string by making sure it is zero-terminated.
** Return a pointer to the resulting string. Return a NULL
** pointer if any kind of error was encountered.
@@ -750,7 +764,7 @@ char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
memcpy(p->zText, p->zBase, p->nChar+1);
}else{
- p->accError = STRACCUM_NOMEM;
+ setStrAccumError(p, STRACCUM_NOMEM);
}
}
}
diff --git a/src/shell.c b/src/shell.c
index 480ec5b45..7826fdf20 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1836,7 +1836,7 @@ static void csv_append_char(CSVReader *p, int c){
** + Report syntax errors on stderr
*/
static char *csv_read_one_field(CSVReader *p){
- int c, pc;
+ int c, pc, ppc;
int cSep = p->cSeparator;
p->n = 0;
c = fgetc(p->in);
@@ -1847,7 +1847,7 @@ static char *csv_read_one_field(CSVReader *p){
if( c=='"' ){
int startLine = p->nLine;
int cQuote = c;
- pc = 0;
+ pc = ppc = 0;
while( 1 ){
c = fgetc(p->in);
if( c=='\n' ) p->nLine++;
@@ -1859,7 +1859,7 @@ static char *csv_read_one_field(CSVReader *p){
}
if( (c==cSep && pc==cQuote)
|| (c=='\n' && pc==cQuote)
- || (c=='\n' && pc=='\r' && p->n>=2 && p->z[p->n-2]==cQuote)
+ || (c=='\n' && pc=='\r' && ppc==cQuote)
|| (c==EOF && pc==cQuote)
){
do{ p->n--; }while( p->z[p->n]!=cQuote );
@@ -1877,6 +1877,7 @@ static char *csv_read_one_field(CSVReader *p){
break;
}
csv_append_char(p, c);
+ ppc = pc;
pc = c;
}
}else{
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index f67c42a8c..abb690419 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -486,6 +486,7 @@ int sqlite3_exec(
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
+#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
@@ -553,7 +554,8 @@ int sqlite3_exec(
** after reboot following a crash or power loss, the only bytes in a
** file that were written at the application level might have changed
** and that adjacent bytes, even bytes within the same sector are
-** guaranteed to be unchanged.
+** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+** flag indicate that a file cannot be deleted when open.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -784,15 +786,29 @@ struct sqlite3_io_methods {
** additional information.
**
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
-** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
-** SQLite and sent to all VFSes in place of a call to the xSync method
-** when the database connection has [PRAGMA synchronous] set to OFF.)^
-** Some specialized VFSes need this signal in order to operate correctly
-** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most
-** VFSes do not need this signal and should silently ignore this opcode.
-** Applications should not call [sqlite3_file_control()] with this
-** opcode as doing so may disrupt the operation of the specialized VFSes
-** that do require it.
+** No longer in use.
+**
+** <li>[[SQLITE_FCNTL_SYNC]]
+** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and
+** sent to the VFS immediately before the xSync method is invoked on a
+** database file descriptor. Or, if the xSync method is not invoked
+** because the user has configured SQLite with
+** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
+** of the xSync method. In most cases, the pointer argument passed with
+** this file-control is NULL. However, if the database file is being synced
+** as part of a multi-database commit, the argument points to a nul-terminated
+** string containing the transactions master-journal file name. VFSes that
+** do not need this signal should silently ignore this opcode. Applications
+** should not call [sqlite3_file_control()] with this opcode as doing so may
+** disrupt the operation of the specialized VFSes that do require it.
+**
+** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]]
+** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite
+** and sent to the VFS after a transaction has been committed immediately
+** but before the database is unlocked. VFSes that do not need this signal
+** should silently ignore this opcode. Applications should not call
+** [sqlite3_file_control()] with this opcode as doing so may disrupt the
+** operation of the specialized VFSes that do require it.
**
** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]]
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
@@ -916,6 +932,12 @@ struct sqlite3_io_methods {
** SQLite stack may generate instances of this file control if
** the [SQLITE_USE_FCNTL_TRACE] compile-time option is enabled.
**
+** <li>[[SQLITE_FCNTL_HAS_MOVED]]
+** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a
+** pointer to an integer and it writes a boolean into that integer depending
+** on whether or not the file has been renamed, moved, or deleted since it
+** was first opened.
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -936,6 +958,9 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_TEMPFILENAME 16
#define SQLITE_FCNTL_MMAP_SIZE 18
#define SQLITE_FCNTL_TRACE 19
+#define SQLITE_FCNTL_HAS_MOVED 20
+#define SQLITE_FCNTL_SYNC 21
+#define SQLITE_FCNTL_COMMIT_PHASETWO 22
/*
** CAPI3REF: Mutex Handle
@@ -3952,15 +3977,24 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
**
** ^The fourth parameter, eTextRep, specifies what
** [SQLITE_UTF8 | text encoding] this SQL function prefers for
-** its parameters. Every SQL function implementation must be able to work
-** with UTF-8, UTF-16le, or UTF-16be. But some implementations may be
-** more efficient with one encoding than another. ^An application may
-** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
-** times with the same function but with different values of eTextRep.
+** its parameters. The application should set this parameter to
+** [SQLITE_UTF16LE] if the function implementation invokes
+** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the
+** implementation invokes [sqlite3_value_text16be()] on an input, or
+** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8]
+** otherwise. ^The same SQL function may be registered multiple times using
+** different preferred text encodings, with different implementations for
+** each encoding.
** ^When multiple implementations of the same function are available, SQLite
** will pick the one that involves the least amount of data conversion.
-** If there is only a single implementation which does not care what text
-** encoding is used, then the fourth argument should be [SQLITE_ANY].
+**
+** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC]
+** to signal that the function will always return the same result given
+** the same inputs within a single SQL statement. Most SQL functions are
+** deterministic. The built-in [random()] SQL function is an example of a
+** function that is not deterministic. The SQLite query planner is able to
+** perform additional optimizations on deterministic functions, so use
+** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
@@ -4046,10 +4080,20 @@ int sqlite3_create_function_v2(
#define SQLITE_UTF16LE 2
#define SQLITE_UTF16BE 3
#define SQLITE_UTF16 4 /* Use native byte order */
-#define SQLITE_ANY 5 /* sqlite3_create_function only */
+#define SQLITE_ANY 5 /* Deprecated */
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
/*
+** CAPI3REF: Function Flags
+**
+** These constants may be ORed together with the
+** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
+** to [sqlite3_create_function()], [sqlite3_create_function16()], or
+** [sqlite3_create_function_v2()].
+*/
+#define SQLITE_DETERMINISTIC 0x800
+
+/*
** CAPI3REF: Deprecated Functions
** DEPRECATED
**
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 0c4159e62..98dc451a4 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3169,6 +3169,7 @@ const void *sqlite3ValueText(sqlite3_value*, u8);
int sqlite3ValueBytes(sqlite3_value*, u8);
void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
+void sqlite3ValueSetNull(sqlite3_value*);
void sqlite3ValueFree(sqlite3_value*);
sqlite3_value *sqlite3ValueNew(sqlite3 *);
char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
@@ -3234,6 +3235,7 @@ int sqlite3OpenTempDatabase(Parse *);
void sqlite3StrAccumInit(StrAccum*, char*, int, int);
void sqlite3StrAccumAppend(StrAccum*,const char*,int);
+void sqlite3StrAccumAppendAll(StrAccum*,const char*);
void sqlite3AppendSpace(StrAccum*,int);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumReset(StrAccum*);
diff --git a/src/test1.c b/src/test1.c
index e0c16e13a..a96b29866 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -942,9 +942,21 @@ static void ptrChngFunction(
sqlite3_result_int(context, p1!=p2);
}
+/*
+** This SQL function returns a different answer each time it is called, even if
+** the arguments are the same.
+*/
+static void nondeterministicFunction(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ static int cnt = 0;
+ sqlite3_result_int(context, cnt++);
+}
/*
-** Usage: sqlite_test_create_function DB
+** Usage: sqlite3_create_function DB
**
** Call the sqlite3_create_function API on the given database in order
** to create a function named "x_coalesce". This function does the same thing
@@ -973,16 +985,16 @@ static int test_create_function(
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
- rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0,
+ rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0,
t1_ifnullFunc, 0, 0);
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0,
- hex8Func, 0, 0);
+ rc = sqlite3_create_function(db, "hex8", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+ 0, hex8Func, 0, 0);
}
#ifndef SQLITE_OMIT_UTF16
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0,
- hex16Func, 0, 0);
+ rc = sqlite3_create_function(db, "hex16", 1, SQLITE_UTF16 | SQLITE_DETERMINISTIC,
+ 0, hex16Func, 0, 0);
}
#endif
if( rc==SQLITE_OK ){
@@ -994,6 +1006,19 @@ static int test_create_function(
ptrChngFunction, 0, 0);
}
+ /* Functions counter1() and counter2() have the same implementation - they
+ ** both return an ascending integer with each call. But counter1() is marked
+ ** as non-deterministic and counter2() is marked as deterministic.
+ */
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "counter1", -1, SQLITE_UTF8,
+ 0, nondeterministicFunction, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC,
+ 0, nondeterministicFunction, 0, 0);
+ }
+
#ifndef SQLITE_OMIT_UTF16
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
** because it is not tested anywhere else. */
diff --git a/src/test6.c b/src/test6.c
index 6ea03b0f1..306482dcd 100644
--- a/src/test6.c
+++ b/src/test6.c
@@ -173,9 +173,6 @@ static void *crash_realloc(void *p, int n){
static int writeDbFile(CrashFile *p, u8 *z, i64 iAmt, i64 iOff){
int rc = SQLITE_OK;
int iSkip = 0;
- if( iOff==PENDING_BYTE && (p->flags&SQLITE_OPEN_MAIN_DB) ){
- iSkip = 512;
- }
if( (iAmt-iSkip)>0 ){
rc = sqlite3OsWrite(p->pRealFile, &z[iSkip], (int)(iAmt-iSkip), iOff+iSkip);
}
@@ -409,13 +406,17 @@ static int cfRead(
sqlite_int64 iOfst
){
CrashFile *pCrash = (CrashFile *)pFile;
+ int nCopy = (int)MIN((i64)iAmt, (pCrash->iSize - iOfst));
+
+ if( nCopy>0 ){
+ memcpy(zBuf, &pCrash->zData[iOfst], nCopy);
+ }
/* Check the file-size to see if this is a short-read */
- if( pCrash->iSize<(iOfst+iAmt) ){
+ if( nCopy<iAmt ){
return SQLITE_IOERR_SHORT_READ;
}
- memcpy(zBuf, &pCrash->zData[iOfst], iAmt);
return SQLITE_OK;
}
@@ -632,14 +633,12 @@ static int cfOpen(
** UPDATE: It also contains an assert() verifying that each call
** to the xRead() method reads less than 128KB of data.
*/
- const int isDb = (flags&SQLITE_OPEN_MAIN_DB);
i64 iOff;
memset(pWrapper->zData, 0, pWrapper->nData);
for(iOff=0; iOff<pWrapper->iSize; iOff += 512){
int nRead = (int)(pWrapper->iSize - iOff);
if( nRead>512 ) nRead = 512;
- if( isDb && iOff==PENDING_BYTE ) continue;
rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], nRead, iOff);
}
}else{
diff --git a/src/test_vfstrace.c b/src/test_vfstrace.c
index 0aacc01fe..c1792f116 100644
--- a/src/test_vfstrace.c
+++ b/src/test_vfstrace.c
@@ -258,6 +258,11 @@ static void vfstrace_print_errcode(
case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
+ case SQLITE_IOERR_SHMMAP: zVal = "SQLITE_IOERR_SHMMAP"; break;
+ case SQLITE_IOERR_SEEK: zVal = "SQLITE_IOERR_SEEK"; break;
+ case SQLITE_IOERR_GETTEMPPATH: zVal = "SQLITE_IOERR_GETTEMPPATH"; break;
+ case SQLITE_IOERR_CONVPATH: zVal = "SQLITE_IOERR_CONVPATH"; break;
+ case SQLITE_READONLY_DBMOVED: zVal = "SQLITE_READONLY_DBMOVED"; break;
case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
diff --git a/src/util.c b/src/util.c
index 9fa2a0fbd..362a5d897 100644
--- a/src/util.c
+++ b/src/util.c
@@ -115,18 +115,17 @@ int sqlite3Strlen30(const char *z){
** to NULL.
*/
void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
- if( db && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
- db->errCode = err_code;
- if( zFormat ){
- char *z;
- va_list ap;
- va_start(ap, zFormat);
- z = sqlite3VMPrintf(db, zFormat, ap);
- va_end(ap);
- sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC);
- }else{
- sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
- }
+ assert( db!=0 );
+ db->errCode = err_code;
+ if( zFormat && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
+ char *z;
+ va_list ap;
+ va_start(ap, zFormat);
+ z = sqlite3VMPrintf(db, zFormat, ap);
+ va_end(ap);
+ sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC);
+ }else if( db->pErr ){
+ sqlite3ValueSetNull(db->pErr);
}
}
diff --git a/src/vdbe.c b/src/vdbe.c
index 908e5bcb3..e35e324fa 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2506,7 +2506,7 @@ case OP_Column: {
pDest->enc = encoding;
op_column_out:
- rc = sqlite3VdbeMemMakeWriteable(pDest);
+ Deephemeralize(pDest);
op_column_error:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
@@ -2570,7 +2570,8 @@ case OP_MakeRecord: {
int nField; /* Number of fields in the record */
char *zAffinity; /* The affinity string for the record */
int file_format; /* File format to use for encoding */
- int i; /* Space used in zNewRecord[] */
+ int i; /* Space used in zNewRecord[] header */
+ int j; /* Space used in zNewRecord[] content */
int len; /* Length of a field */
/* Assuming the record contains N fields, the record format looks
@@ -2604,36 +2605,51 @@ case OP_MakeRecord: {
pOut = &aMem[pOp->p3];
memAboutToChange(p, pOut);
+ /* Apply the requested affinity to all inputs
+ */
+ assert( pData0<=pLast );
+ if( zAffinity ){
+ pRec = pData0;
+ do{
+ applyAffinity(pRec, *(zAffinity++), encoding);
+ }while( (++pRec)<=pLast );
+ }
+
/* Loop through the elements that will make up the record to figure
** out how much space is required for the new record.
*/
- for(pRec=pData0; pRec<=pLast; pRec++){
+ pRec = pLast;
+ do{
assert( memIsValid(pRec) );
- if( zAffinity ){
- applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
- }
- if( pRec->flags&MEM_Zero && pRec->n>0 ){
- sqlite3VdbeMemExpandBlob(pRec);
- }
serial_type = sqlite3VdbeSerialType(pRec, file_format);
len = sqlite3VdbeSerialTypeLen(serial_type);
- nData += len;
- nHdr += sqlite3VarintLen(serial_type);
if( pRec->flags & MEM_Zero ){
- /* Only pure zero-filled BLOBs can be input to this Opcode.
- ** We do not allow blobs with a prefix and a zero-filled tail. */
- nZero += pRec->u.nZero;
- }else if( len ){
- nZero = 0;
+ if( nData ){
+ sqlite3VdbeMemExpandBlob(pRec);
+ }else{
+ nZero += pRec->u.nZero;
+ len -= pRec->u.nZero;
+ }
}
- }
+ nData += len;
+ testcase( serial_type==127 );
+ testcase( serial_type==128 );
+ nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
+ }while( (--pRec)>=pData0 );
/* Add the initial header varint and total the size */
- nHdr += nVarint = sqlite3VarintLen(nHdr);
- if( nVarint<sqlite3VarintLen(nHdr) ){
- nHdr++;
+ testcase( nHdr==126 );
+ testcase( nHdr==127 );
+ if( nHdr<=126 ){
+ /* The common case */
+ nHdr += 1;
+ }else{
+ /* Rare case of a really large header */
+ nVarint = sqlite3VarintLen(nHdr);
+ nHdr += nVarint;
+ if( nVarint<sqlite3VarintLen(nHdr) ) nHdr++;
}
- nByte = nHdr+nData-nZero;
+ nByte = nHdr+nData;
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
@@ -2650,14 +2666,16 @@ case OP_MakeRecord: {
/* Write the record */
i = putVarint32(zNewRecord, nHdr);
- for(pRec=pData0; pRec<=pLast; pRec++){
+ j = nHdr;
+ assert( pData0<=pLast );
+ pRec = pData0;
+ do{
serial_type = sqlite3VdbeSerialType(pRec, file_format);
- i += putVarint32(&zNewRecord[i], serial_type); /* serial type */
- }
- for(pRec=pData0; pRec<=pLast; pRec++){ /* serial data */
- i += sqlite3VdbeSerialPut(&zNewRecord[i], (int)(nByte-i), pRec,file_format);
- }
- assert( i==nByte );
+ i += putVarint32(&zNewRecord[i], serial_type); /* serial type */
+ j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */
+ }while( (++pRec)<=pLast );
+ assert( i==nHdr );
+ assert( j==nByte );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pOut->n = (int)nByte;
@@ -2686,6 +2704,7 @@ case OP_Count: { /* out2-prerelease */
pCrsr = p->apCsr[pOp->p1]->pCursor;
assert( pCrsr );
+ nEntry = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3BtreeCount(pCrsr, &nEntry);
pOut->u.i = nEntry;
break;
@@ -3706,7 +3725,6 @@ case OP_Found: { /* jump, in3 */
if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++;
#endif
- alreadyExists = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p4type==P4_INT32 );
pC = p->apCsr[pOp->p1];
@@ -3714,6 +3732,7 @@ case OP_Found: { /* jump, in3 */
pIn3 = &aMem[pOp->p3];
assert( pC->pCursor!=0 );
assert( pC->isTable==0 );
+ pFree = 0; /* Not needed. Only used to suppress a compiler warning. */
if( pOp->p4.i>0 ){
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
@@ -4697,6 +4716,7 @@ case OP_IdxRowid: { /* out2-prerelease */
assert( pC->deferredMoveto==0 );
assert( pC->isTable==0 );
if( !pC->nullRow ){
+ rowid = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
@@ -4760,6 +4780,7 @@ case OP_IdxGE: { /* jump */
#ifdef SQLITE_DEBUG
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
#endif
+ res = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res);
if( pOp->opcode==OP_IdxLT ){
res = -res;
@@ -4820,6 +4841,7 @@ case OP_Destroy: { /* out2-prerelease */
iDb = pOp->p3;
assert( iCnt==1 );
assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 );
+ iMoved = 0; /* Not needed. Only to silence a warning. */
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
pOut->flags = MEM_Int;
pOut->u.i = iMoved;
@@ -5392,7 +5414,6 @@ case OP_FkIfZero: { /* jump */
** an integer.
*/
case OP_MemMax: { /* in2 */
- Mem *pIn1;
VdbeFrame *pFrame;
if( p->pFrame ){
for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index cf1041887..0f89c3a24 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -408,7 +408,7 @@ void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
u32 sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialType(Mem*, int);
-u32 sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
+u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 976a4125e..080eee3fe 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -486,7 +486,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
v->doingRerun = 1;
assert( v->expired==0 );
}
- if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
+ if( rc2!=SQLITE_OK ){
/* This case occurs after failing to recompile an sql statement.
** The error message from the SQL compiler has already been loaded
** into the database handle. This block copies the error message
@@ -496,6 +496,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
** sqlite3_errmsg() and sqlite3_errcode().
*/
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
+ assert( zErr!=0 || db->mallocFailed );
sqlite3DbFree(db, v->zErrMsg);
if( !db->mallocFailed ){
v->zErrMsg = sqlite3DbStrDup(db, zErr);
@@ -1332,6 +1333,7 @@ static UnpackedRecord *vdbeUnpackRecord(
pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo, 0, 0, &dummy);
if( pRet ){
+ memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
}
return pRet;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index c1a22b207..5fc7a3198 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -2421,6 +2421,7 @@ int sqlite3VdbeTransferError(Vdbe *p){
if( p->zErrMsg ){
u8 mallocFailed = db->mallocFailed;
sqlite3BeginBenignMalloc();
+ if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db);
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
sqlite3EndBenignMalloc();
db->mallocFailed = mallocFailed;
@@ -2489,8 +2490,7 @@ int sqlite3VdbeReset(Vdbe *p){
** to sqlite3_step(). For consistency (since sqlite3_step() was
** called), set the database error in this case as well.
*/
- sqlite3Error(db, p->rc, 0);
- sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
+ sqlite3Error(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
@@ -2828,21 +2828,15 @@ static u64 floatSwap(u64 in){
** buf. It is assumed that the caller has allocated sufficient space.
** Return the number of bytes written.
**
-** nBuf is the amount of space left in buf[]. nBuf must always be
-** large enough to hold the entire field. Except, if the field is
-** a blob with a zero-filled tail, then buf[] might be just the right
-** size to hold everything except for the zero-filled tail. If buf[]
-** is only big enough to hold the non-zero prefix, then only write that
-** prefix into buf[]. But if buf[] is large enough to hold both the
-** prefix and the tail then write the prefix and set the tail to all
-** zeros.
+** nBuf is the amount of space left in buf[]. The caller is responsible
+** for allocating enough space to buf[] to hold the entire field, exclusive
+** of the pMem->u.nZero bytes for a MEM_Zero value.
**
** Return the number of bytes actually written into buf[]. The number
** of bytes in the zero-filled tail is included in the return value only
** if those bytes were zeroed in buf[].
*/
-u32 sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
- u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
+u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
u32 len;
/* Integer and Real */
@@ -2857,7 +2851,6 @@ u32 sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
v = pMem->u.i;
}
len = i = sqlite3VdbeSerialTypeLen(serial_type);
- assert( len<=(u32)nBuf );
while( i-- ){
buf[i] = (u8)(v&0xFF);
v >>= 8;
@@ -2869,17 +2862,8 @@ u32 sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
if( serial_type>=12 ){
assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
== (int)sqlite3VdbeSerialTypeLen(serial_type) );
- assert( pMem->n<=nBuf );
len = pMem->n;
memcpy(buf, pMem->z, len);
- if( pMem->flags & MEM_Zero ){
- len += pMem->u.nZero;
- assert( nBuf>=0 );
- if( len > (u32)nBuf ){
- len = (u32)nBuf;
- }
- memset(&buf[pMem->n], 0, len-pMem->n);
- }
return len;
}
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 51f20d4cc..3beccd92d 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -59,18 +59,14 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
/*
** Make sure pMem->z points to a writable allocation of at least
-** n bytes.
+** min(n,32) bytes.
**
-** If the third argument passed to this function is true, then memory
-** cell pMem must contain a string or blob. In this case the content is
-** preserved. Otherwise, if the third parameter to this function is false,
-** any current string or blob value may be discarded.
-**
-** This function sets the MEM_Dyn flag and clears any xDel callback.
-** It also clears MEM_Ephem and MEM_Static. If the preserve flag is
-** not set, Mem.n is zeroed.
+** If the bPreserve argument is true, then copy of the content of
+** pMem->z into the new allocation. pMem must be either a string or
+** blob if bPreserve is true. If bPreserve is false, any prior content
+** in pMem->z is discarded.
*/
-int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
+int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( 1 >=
((pMem->zMalloc && pMem->zMalloc==pMem->z) ? 1 : 0) +
(((pMem->flags&MEM_Dyn)&&pMem->xDel) ? 1 : 0) +
@@ -79,37 +75,39 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
);
assert( (pMem->flags&MEM_RowSet)==0 );
- /* If the preserve flag is set to true, then the memory cell must already
+ /* If the bPreserve flag is set to true, then the memory cell must already
** contain a valid string or blob value. */
- assert( preserve==0 || pMem->flags&(MEM_Blob|MEM_Str) );
+ assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) );
+ testcase( bPreserve && pMem->z==0 );
- if( n<32 ) n = 32;
- if( sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
- if( preserve && pMem->z==pMem->zMalloc ){
+ if( pMem->zMalloc==0 || sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
+ if( n<32 ) n = 32;
+ if( bPreserve && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
- preserve = 0;
+ bPreserve = 0;
}else{
sqlite3DbFree(pMem->db, pMem->zMalloc);
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
}
+ if( pMem->zMalloc==0 ){
+ sqlite3VdbeMemRelease(pMem);
+ pMem->flags = MEM_Null;
+ return SQLITE_NOMEM;
+ }
}
- if( pMem->z && preserve && pMem->zMalloc && pMem->z!=pMem->zMalloc ){
+ if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
- if( pMem->flags&MEM_Dyn && pMem->xDel ){
+ if( (pMem->flags&MEM_Dyn)!=0 && pMem->xDel ){
assert( pMem->xDel!=SQLITE_DYNAMIC );
pMem->xDel((void *)(pMem->z));
}
pMem->z = pMem->zMalloc;
- if( pMem->z==0 ){
- pMem->flags = MEM_Null;
- }else{
- pMem->flags &= ~(MEM_Ephem|MEM_Static);
- }
+ pMem->flags &= ~(MEM_Ephem|MEM_Static);
pMem->xDel = 0;
- return (pMem->z ? SQLITE_OK : SQLITE_NOMEM);
+ return SQLITE_OK;
}
/*
@@ -295,10 +293,12 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
*/
void sqlite3VdbeMemRelease(Mem *p){
VdbeMemRelease(p);
- sqlite3DbFree(p->db, p->zMalloc);
+ if( p->zMalloc ){
+ sqlite3DbFree(p->db, p->zMalloc);
+ p->zMalloc = 0;
+ }
p->z = 0;
- p->zMalloc = 0;
- p->xDel = 0;
+ assert( p->xDel==0 ); /* Zeroed by VdbeMemRelease() above */
}
/*
@@ -482,6 +482,9 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
MemSetTypeFlag(pMem, MEM_Null);
pMem->type = SQLITE_NULL;
}
+void sqlite3ValueSetNull(sqlite3_value *p){
+ sqlite3VdbeMemSetNull((Mem*)p);
+}
/*
** Delete any previous value and set the value to be a BLOB of length
@@ -1219,7 +1222,7 @@ static void recordFunc(
}else{
aRet[0] = nSerial+1;
sqlite3PutVarint(&aRet[1], iSerial);
- sqlite3VdbeSerialPut(&aRet[1+nSerial], nVal, argv[0], file_format);
+ sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
sqlite3DbFree(db, aRet);
}
diff --git a/src/vdbetrace.c b/src/vdbetrace.c
index 0a767261f..a7ff0a685 100644
--- a/src/vdbetrace.c
+++ b/src/vdbetrace.c
@@ -92,6 +92,7 @@ char *sqlite3VdbeExpandSql(
const char *zStart = zRawSql;
while( *(zRawSql++)!='\n' && *zRawSql );
sqlite3StrAccumAppend(&out, "-- ", 3);
+ assert( (zRawSql - zStart) > 0 );
sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
}
}else{
diff --git a/src/where.c b/src/where.c
index 7d3ec48da..afe664aa0 100644
--- a/src/where.c
+++ b/src/where.c
@@ -2568,7 +2568,7 @@ static void explainAppendTerm(
const char *zOp /* Name of the operator */
){
if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5);
- sqlite3StrAccumAppend(pStr, zColumn, -1);
+ sqlite3StrAccumAppendAll(pStr, zColumn);
sqlite3StrAccumAppend(pStr, zOp, 1);
sqlite3StrAccumAppend(pStr, "?", 1);
}
@@ -2614,7 +2614,7 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){
}else{
if( i ) sqlite3StrAccumAppend(&txt, " AND ", 5);
sqlite3StrAccumAppend(&txt, "ANY(", 4);
- sqlite3StrAccumAppend(&txt, z, -1);
+ sqlite3StrAccumAppendAll(&txt, z);
sqlite3StrAccumAppend(&txt, ")", 1);
}
}