** This function is used when parsing the "prefix=" FTS4 parameter.
*/
static int fts3GobbleInt(const char **pp, int *pnOut){
+ const int MAX_NPREFIX = 10000000;
const char *p; /* Iterator pointer */
int nInt = 0; /* Output value */
for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
nInt = nInt * 10 + (p[0] - '0');
+ if( nInt>MAX_NPREFIX ){
+ nInt = 0;
+ break;
+ }
}
if( p==*pp ) return SQLITE_ERROR;
*pnOut = nInt;
aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex);
*apIndex = aIndex;
- *pnIndex = nIndex;
if( !aIndex ){
return SQLITE_NOMEM;
}
const char *p = zParam;
int i;
for(i=1; i<nIndex; i++){
- int nPrefix;
+ int nPrefix = 0;
if( fts3GobbleInt(&p, &nPrefix) ) return SQLITE_ERROR;
- aIndex[i].nPrefix = nPrefix;
+ assert( nPrefix>=0 );
+ if( nPrefix==0 ){
+ nIndex--;
+ i--;
+ }else{
+ aIndex[i].nPrefix = nPrefix;
+ }
p++;
}
}
+ *pnIndex = nIndex;
return SQLITE_OK;
}
const char **aCol; /* Array of column names */
sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */
- int nIndex; /* Size of aIndex[] array */
+ int nIndex = 0; /* Size of aIndex[] array */
struct Fts3Index *aIndex = 0; /* Array of indexes for this table */
/* The results of parsing supported FTS4 key=value options: */
**
** The right-hand input doclist is overwritten by this function.
*/
-static void fts3DoclistPhraseMerge(
+static int fts3DoclistPhraseMerge(
int bDescDoclist, /* True if arguments are desc */
int nDist, /* Distance from left to right (1=adjacent) */
char *aLeft, int nLeft, /* Left doclist */
- char *aRight, int *pnRight /* IN/OUT: Right/output doclist */
+ char **paRight, int *pnRight /* IN/OUT: Right/output doclist */
){
sqlite3_int64 i1 = 0;
sqlite3_int64 i2 = 0;
sqlite3_int64 iPrev = 0;
+ char *aRight = *paRight;
char *pEnd1 = &aLeft[nLeft];
char *pEnd2 = &aRight[*pnRight];
char *p1 = aLeft;
char *p2 = aRight;
char *p;
int bFirstOut = 0;
- char *aOut = aRight;
+ char *aOut;
assert( nDist>0 );
-
+ if( bDescDoclist ){
+ aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX);
+ if( aOut==0 ) return SQLITE_NOMEM;
+ }else{
+ aOut = aRight;
+ }
p = aOut;
+
fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1);
fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2);
}
*pnRight = (int)(p - aOut);
+ if( bDescDoclist ){
+ sqlite3_free(aRight);
+ *paRight = aOut;
+ }
+
+ return SQLITE_OK;
}
/*
){
if( pTS->aaOutput[0]==0 ){
/* If this is the first term selected, copy the doclist to the output
- ** buffer using memcpy(). */
- pTS->aaOutput[0] = sqlite3_malloc(nDoclist);
+ ** buffer using memcpy().
+ **
+ ** Add FTS3_VARINT_MAX bytes of unused space to the end of the
+ ** allocation. This is so as to ensure that the buffer is big enough
+ ** to hold the current doclist AND'd with any other doclist. If the
+ ** doclists are stored in order=ASC order, this padding would not be
+ ** required (since the size of [doclistA AND doclistB] is always less
+ ** than or equal to the size of [doclistA] in that case). But this is
+ ** not true for order=DESC. For example, a doclist containing (1, -1)
+ ** may be smaller than (-1), as in the first example the -1 may be stored
+ ** as a single-byte delta, whereas in the second it must be stored as a
+ ** FTS3_VARINT_MAX byte varint.
+ **
+ ** Similar padding is added in the fts3DoclistOrMerge() function.
+ */
+ pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1);
pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
** row by docid.
*/
if( eSearch==FTS3_FULLSCAN_SEARCH ){
- zSql = sqlite3_mprintf(
- "SELECT %s ORDER BY rowid %s",
- p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
- );
+ if( pDocidGe || pDocidLe ){
+ zSql = sqlite3_mprintf(
+ "SELECT %s WHERE rowid BETWEEN %lld AND %lld ORDER BY rowid %s",
+ p->zReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid,
+ (pCsr->bDesc ? "DESC" : "ASC")
+ );
+ }else{
+ zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s",
+ p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
+ );
+ }
if( zSql ){
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
sqlite3_free(zSql);
** This function assumes that pList points to a buffer allocated using
** sqlite3_malloc(). This function takes responsibility for eventually
** freeing the buffer.
+**
+** SQLITE_OK is returned if successful, or SQLITE_NOMEM if an error occurs.
*/
-static void fts3EvalPhraseMergeToken(
+static int fts3EvalPhraseMergeToken(
Fts3Table *pTab, /* FTS Table pointer */
Fts3Phrase *p, /* Phrase to merge pList/nList into */
int iToken, /* Token pList/nList corresponds to */
char *pList, /* Pointer to doclist */
int nList /* Number of bytes in pList */
){
+ int rc = SQLITE_OK;
assert( iToken!=p->iDoclistToken );
if( pList==0 ){
nDiff = p->iDoclistToken - iToken;
}
- fts3DoclistPhraseMerge(pTab->bDescIdx, nDiff, pLeft, nLeft, pRight,&nRight);
+ rc = fts3DoclistPhraseMerge(
+ pTab->bDescIdx, nDiff, pLeft, nLeft, &pRight, &nRight
+ );
sqlite3_free(pLeft);
p->doclist.aAll = pRight;
p->doclist.nAll = nRight;
}
if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken;
+ return rc;
}
/*
char *pThis = 0;
rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis);
if( rc==SQLITE_OK ){
- fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis);
+ rc = fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis);
}
}
assert( pToken->pSegcsr==0 );
char *pList = 0;
rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList);
assert( rc==SQLITE_OK || pList==0 );
+ if( rc==SQLITE_OK ){
+ rc = fts3EvalPhraseMergeToken(
+ pTab, pTC->pPhrase, pTC->iToken,pList,nList
+ );
+ }
if( rc==SQLITE_OK ){
int nCount;
- fts3EvalPhraseMergeToken(pTab, pTC->pPhrase, pTC->iToken,pList,nList);
nCount = fts3DoclistCountDocids(
pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll
);
if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
int rc = SQLITE_OK;
int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
- int iMul; /* +1 if csr dir matches index dir, else -1 */
int bOr = 0;
u8 bEof = 0;
u8 bTreeEof = 0;
** required. They are required if (a) this is not the first fragment,
** or (b) this fragment does not begin at position 0 of its column.
*/
- if( rc==SQLITE_OK && (iPos>0 || iFragment>0) ){
- rc = fts3StringAppend(pOut, zEllipsis, -1);
+ if( rc==SQLITE_OK ){
+ if( iPos>0 || iFragment>0 ){
+ rc = fts3StringAppend(pOut, zEllipsis, -1);
+ }else if( iBegin ){
+ rc = fts3StringAppend(pOut, zDoc, iBegin);
+ }
}
if( rc!=SQLITE_OK || iCurrent<iPos ) continue;
}
*/
for(iRead=0; iRead<pTab->nColumn; iRead++){
SnippetFragment sF = {0, 0, 0, 0};
- int iS;
+ int iS = 0;
if( iCol>=0 && iRead!=iCol ) continue;
/* Find the best snippet of nFToken tokens in column iRead. */
if( argc==2 ){
void *pOld;
int n = sqlite3_value_bytes(argv[1]);
- if( n!=sizeof(pPtr) ){
+ if( zName==0 || n!=sizeof(pPtr) ){
sqlite3_result_error(context, "argument type mismatch", -1);
return;
}
return;
}
}else{
- pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
+ if( zName ){
+ pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
+ }
if( !pPtr ){
char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
sqlite3_result_error(context, zErr, -1);
zEnd = &zCopy[strlen(zCopy)];
z = (char *)sqlite3Fts3NextToken(zCopy, &n);
+ if( z==0 ){
+ assert( n==0 );
+ z = zCopy;
+ }
z[n] = '\0';
sqlite3Fts3Dequote(z);
** an array of pending terms by term. This occurs as part of flushing
** the contents of the pending-terms hash table to the database.
*/
-static int fts3CompareElemByTerm(const void *lhs, const void *rhs){
+static int SQLITE_CDECL fts3CompareElemByTerm(
+ const void *lhs,
+ const void *rhs
+){
char *z1 = fts3HashKey(*(Fts3HashElem **)lhs);
char *z2 = fts3HashKey(*(Fts3HashElem **)rhs);
int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs);
sqlite3_column_int64(pStmt,5));
printf(" root %9s\n", rtag);
if( iLEnd>iStart ){
- sqlite3_int64 iLower, iPrev, iX;
+ sqlite3_int64 iLower, iPrev = 0, iX;
if( iLEnd+1<=iEnd ){
sqlite3_bind_int64(pStmt2, 1, iLEnd+1);
sqlite3_bind_int64(pStmt2, 2, iEnd);
const unsigned char *aData, /* Content to print */
int nData /* Number of bytes of content */
){
- sqlite3_int64 iChild;
+ sqlite3_int64 iChild = 0;
sqlite3_int64 iPrefix;
sqlite3_int64 nTerm;
sqlite3_int64 n;
pWord->zCost[8] = 0;
}
+/* Circumvent compiler warnings about the use of strcpy() by supplying
+** our own implementation.
+*/
+#if defined(__OpenBSD__)
+static void amatchStrcpy(char *dest, const char *src){
+ while( (*(dest++) = *(src++))!=0 ){}
+}
+static void amatchStrcat(char *dest, const char *src){
+ while( *dest ) dest++;
+ amatchStrcpy(dest, src);
+}
+#else
+# define amatchStrcpy strcpy
+# define amatchStrcat strcat
+#endif
+
+
/*
** Add a new amatch_word object to the queue.
**
assert( pOther==0 ); (void)pOther;
pWord->sWord.zKey = pWord->zWord;
pWord->sWord.pWord = pWord;
- strcpy(pWord->zWord, pCur->zBuf);
+ amatchStrcpy(pWord->zWord, pCur->zBuf);
pOther = amatchAvlInsert(&pCur->pWord, &pWord->sWord);
assert( pOther==0 ); (void)pOther;
#ifdef AMATCH_TRACE_1
#endif
}
+
/*
** Advance a cursor to its next row of output
*/
zBuf = sqlite3_realloc(zBuf, nBuf);
if( zBuf==0 ) return SQLITE_NOMEM;
}
- strcpy(zBuf, pWord->zWord+2);
+ amatchStrcpy(zBuf, pWord->zWord+2);
zNext[0] = 0;
zNextIn[0] = pCur->zInput[pWord->nMatch];
if( zNextIn[0] ){
if( zNextIn[0] && zNextIn[0]!='*' ){
sqlite3_reset(p->pVCheck);
- strcat(zBuf, zNextIn);
+ amatchStrcat(zBuf, zNextIn);
sqlite3_bind_text(p->pVCheck, 1, zBuf, nWord+nNextIn, SQLITE_STATIC);
rc = sqlite3_step(p->pVCheck);
if( rc==SQLITE_ROW ){
}
while( 1 ){
- strcpy(zBuf+nWord, zNext);
+ amatchStrcpy(zBuf+nWord, zNext);
sqlite3_reset(p->pVCheck);
sqlite3_bind_text(p->pVCheck, 1, zBuf, -1, SQLITE_TRANSIENT);
rc = sqlite3_step(p->pVCheck);
if( rc!=SQLITE_ROW ) break;
zW = (const char*)sqlite3_column_text(p->pVCheck, 0);
- strcpy(zBuf+nWord, zNext);
+ amatchStrcpy(zBuf+nWord, zNext);
if( strncmp(zW, zBuf, nWord)!=0 ) break;
if( (zNextIn[0]=='*' && zNextIn[1]==0)
|| (zNextIn[0]==0 && zW[nWord]==0)
unsigned int nIn;
unsigned long int nOut;
unsigned char x[8];
+ int rc;
int i, j;
pIn = sqlite3_value_blob(argv[0]);
for(i=0; i<4 && x[i]==0; i++){}
for(j=0; i<=4; i++, j++) pOut[j] = x[i];
pOut[j-1] |= 0x80;
- compress(&pOut[j], &nOut, pIn, nIn);
- sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free);
+ rc = compress(&pOut[j], &nOut, pIn, nIn);
+ if( rc==Z_OK ){
+ sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free);
+ }else{
+ sqlite3_free(pOut);
+ }
}
/*
rc = uncompress(pOut, &nOut, &pIn[i], nIn-i);
if( rc==Z_OK ){
sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
+ }else{
+ sqlite3_free(pOut);
}
}
*/
if( pDflt ){
sqlite3_value *pVal = 0;
- if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
+ int rc;
+ rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal);
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ if( rc!=SQLITE_OK ){
db->mallocFailed = 1;
return;
}
case SQLITE_NULL:
/* No key specified. Use the key from the main database */
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
- if( nKey>0 || sqlite3BtreeGetReserve(db->aDb[0].pBt)>0 ){
+ if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
}
break;
** guaranteed that the shared-mutex is held by this thread, handle
** p->pSrc may not actually be the owner. */
int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
- int nDestReserve = sqlite3BtreeGetReserve(p->pDest);
+ int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest);
#endif
int rc = SQLITE_OK;
i64 iOff;
** Exit the recursive mutex on a Btree.
*/
void sqlite3BtreeLeave(Btree *p){
+ assert( sqlite3_mutex_held(p->db->mutex) );
if( p->sharable ){
assert( p->wantToLock>0 );
p->wantToLock--;
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
Index *pIdx = (Index *)sqliteHashData(p);
if( pIdx->tnum==(int)iRoot ){
+ if( iTab ){
+ /* Two or more indexes share the same root page. There must
+ ** be imposter tables. So just return true. The assert is not
+ ** useful in that case. */
+ return 1;
+ }
iTab = pIdx->pTable->tnum;
}
}
static int saveCursorPosition(BtCursor *pCur){
int rc;
- assert( CURSOR_VALID==pCur->eState );
+ assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
+ if( pCur->eState==CURSOR_SKIPNEXT ){
+ pCur->eState = CURSOR_VALID;
+ }else{
+ pCur->skipNext = 0;
+ }
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
){
do{
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){
- if( p->eState==CURSOR_VALID ){
+ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
*/
static int btreeRestoreCursorPosition(BtCursor *pCur){
int rc;
+ int skipNext;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState>=CURSOR_REQUIRESEEK );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skipNext;
}
pCur->eState = CURSOR_INVALID;
- rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skipNext);
+ rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
if( rc==SQLITE_OK ){
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
+ pCur->skipNext |= skipNext;
if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
pCur->eState = CURSOR_SKIPNEXT;
}
*pDifferentRow = 1;
return rc;
}
- if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
+ if( pCur->eState!=CURSOR_VALID ){
*pDifferentRow = 1;
}else{
+ assert( pCur->skipNext==0 );
*pDifferentRow = 0;
}
return SQLITE_OK;
*/
if( isTempDb==0 && (isMemdb==0 || (vfsFlags&SQLITE_OPEN_URI)!=0) ){
if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){
+ int nFilename = sqlite3Strlen30(zFilename)+1;
int nFullPathname = pVfs->mxPathname+1;
- char *zFullPathname = sqlite3Malloc(nFullPathname);
+ char *zFullPathname = sqlite3Malloc(MAX(nFullPathname,nFilename));
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
+
p->sharable = 1;
if( !zFullPathname ){
sqlite3_free(p);
return SQLITE_NOMEM;
}
if( isMemdb ){
- memcpy(zFullPathname, zFilename, sqlite3Strlen30(zFilename)+1);
+ memcpy(zFullPathname, zFilename, nFilename);
}else{
rc = sqlite3OsFullPathname(pVfs, zFilename,
nFullPathname, zFullPathname);
** the right size. This is to guard against size changes that result
** when compiling on a different architecture.
*/
- assert( sizeof(i64)==8 || sizeof(i64)==4 );
- assert( sizeof(u64)==8 || sizeof(u64)==4 );
+ assert( sizeof(i64)==8 );
+ assert( sizeof(u64)==8 );
assert( sizeof(u32)==4 );
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
BtShared *pBt = p->pBt;
assert( nReserve>=-1 && nReserve<=255 );
sqlite3BtreeEnter(p);
+#if SQLITE_HAS_CODEC
+ if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve;
+#endif
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
sqlite3BtreeLeave(p);
return SQLITE_READONLY;
return p->pBt->pageSize;
}
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG)
/*
** This function is similar to sqlite3BtreeGetReserve(), except that it
** may only be called if it is guaranteed that the b-tree mutex is already
** database handle that owns *p, causing undefined behavior.
*/
int sqlite3BtreeGetReserveNoMutex(Btree *p){
+ int n;
assert( sqlite3_mutex_held(p->pBt->mutex) );
- return p->pBt->pageSize - p->pBt->usableSize;
+ n = p->pBt->pageSize - p->pBt->usableSize;
+ return n;
}
-#endif /* SQLITE_HAS_CODEC || SQLITE_DEBUG */
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
/*
** Return the number of bytes of space at the end of every page that
** are intentually left unused. This is the "reserved" space that is
** sometimes used by extensions.
+**
+** If SQLITE_HAS_MUTEX is defined then the number returned is the
+** greater of the current reserved space and the maximum requested
+** reserve space.
*/
-int sqlite3BtreeGetReserve(Btree *p){
+int sqlite3BtreeGetOptimalReserve(Btree *p){
int n;
sqlite3BtreeEnter(p);
- n = p->pBt->pageSize - p->pBt->usableSize;
+ n = sqlite3BtreeGetReserveNoMutex(p);
+#ifdef SQLITE_HAS_CODEC
+ if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve;
+#endif
sqlite3BtreeLeave(p);
return n;
}
+
/*
** Set the maximum page count for a database if mxPage is positive.
** No changes are made if mxPage is 0 or negative.
sqlite3BtreeLeave(p);
return b;
}
-#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
/*
** Change the 'auto-vacuum' property of the database. If the 'autoVacuum'
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
- if( p->eState==CURSOR_VALID ){
+ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
rc = saveCursorPosition(p);
if( rc!=SQLITE_OK ){
(void)sqlite3BtreeTripAllCursors(pBtree, rc, 0);
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->iPage>=0 );
+ assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
getCellInfo(pCur);
*pSize = pCur->info.nPayload;
return SQLITE_OK;
}
-#if 0
+#if SQLITE_DEBUG
/*
** Page pParent is an internal (non-leaf) tree page. This function
** asserts that page number iChild is the left-child if the iIdx'th
** the page.
*/
static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
+ if( CORRUPT_DB ) return; /* The conditions tested below might not be true
+ ** in a corrupt database */
assert( iIdx<=pParent->nCell );
if( iIdx==pParent->nCell ){
assert( get4byte(&pParent->aData[pParent->hdrOffset+8])==iChild );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
-
- /* UPDATE: It is actually possible for the condition tested by the assert
- ** below to be untrue if the database file is corrupt. This can occur if
- ** one cursor has modified page pParent while a reference to it is held
- ** by a second cursor. Which can only happen if a single page is linked
- ** into more than one b-tree structure in a corrupt database. */
-#if 0
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
pCur->apPage[pCur->iPage]->pgno
);
-#endif
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
releasePage(pCur->apPage[pCur->iPage]);
** pSpace buffer passed to the latter call to balance_nonroot().
*/
u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize);
- rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, pCur->hints);
+ rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1,
+ pCur->hints&BTREE_BULKLOAD);
if( pFree ){
/* If pFree is not NULL, it points to the pSpace buffer used
** by a previous call to balance_nonroot(). Its contents are
/* The next iteration of the do-loop balances the parent page. */
releasePage(pPage);
pCur->iPage--;
+ assert( pCur->iPage>=0 );
}
}while( rc==SQLITE_OK );
if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
-
rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
+ if( pPage->bBusy ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto cleardatabasepage_out;
+ }
+ pPage->bBusy = 1;
hdr = pPage->hdrOffset;
for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i);
}
cleardatabasepage_out:
+ pPage->bBusy = 0;
releasePage(pPage);
return rc;
}
}
/*
-** set the mask of hint flags for cursor pCsr. Currently the only valid
-** values are 0 and BTREE_BULKLOAD.
+** set the mask of hint flags for cursor pCsr.
*/
void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
- assert( mask==BTREE_BULKLOAD || mask==0 );
+ assert( mask==BTREE_BULKLOAD || mask==BTREE_SEEK_EQ || mask==0 );
pCsr->hints = mask;
}
+#ifdef SQLITE_DEBUG
+/*
+** Return true if the cursor has a hint specified. This routine is
+** only used from within assert() statements
+*/
+int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){
+ return (pCsr->hints & mask)!=0;
+}
+#endif
+
/*
** Return true if the given Btree is read-only.
*/
int sqlite3BtreeMaxPageCount(Btree*,int);
u32 sqlite3BtreeLastPage(Btree*);
int sqlite3BtreeSecureDelete(Btree*,int);
-int sqlite3BtreeGetReserve(Btree*);
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG)
+int sqlite3BtreeGetOptimalReserve(Btree*);
int sqlite3BtreeGetReserveNoMutex(Btree *p);
-#endif
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int);
/*
** Values that may be OR'd together to form the second argument of an
** sqlite3BtreeCursorHints() call.
+**
+** The BTREE_BULKLOAD flag is set on index cursors when the index is going
+** to be filled with content that is already in sorted order.
+**
+** The BTREE_SEEK_EQ flag is set on cursors that will get OP_SeekGE or
+** OP_SeekLE opcodes for a range search, but where the range of entries
+** selected will all have the same key. In other words, the cursor will
+** be used only for equality key searches.
+**
*/
-#define BTREE_BULKLOAD 0x00000001
+#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */
+#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */
int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
void sqlite3BtreeClearCursor(BtCursor *);
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
+#ifdef SQLITE_DEBUG
+int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
+#endif
int sqlite3BtreeIsReadonly(Btree *pBt);
int sqlite3HeaderSizeBtree(void);
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
u8 max1bytePayload; /* min(maxLocal,127) */
+ u8 bBusy; /* Prevent endless loops on corrupt database files */
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
#endif
u8 inTransaction; /* Transaction state */
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
+#ifdef SQLITE_HAS_CODEC
+ u8 optimalReserve; /* Desired amount of reserved space per page */
+#endif
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
Table *p = 0;
int i;
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) || zName==0 ) return 0;
-#endif
-
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
#if SQLITE_USER_AUTHENTICATION
assert( pPk!=0 );
nPk = pPk->nKeyCol;
- /* Make sure every column of the PRIMARY KEY is NOT NULL */
- for(i=0; i<nPk; i++){
- pTab->aCol[pPk->aiColumn[i]].notNull = 1;
+ /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except,
+ ** do not enforce this for imposter tables.) */
+ if( !db->init.imposterTable ){
+ for(i=0; i<nPk; i++){
+ pTab->aCol[pPk->aiColumn[i]].notNull = 1;
+ }
+ pPk->uniqNotNull = 1;
}
- pPk->uniqNotNull = 1;
/* The root page of the PRIMARY KEY is the table root page */
pPk->tnum = pTab->tnum;
pIdx->onError = pIndex->onError;
}
}
+ pRet = pIdx;
goto exit_create_index;
}
}
pInClause->x.pSelect = pSelect;
pInClause->flags |= EP_xIsSelect;
- sqlite3ExprSetHeight(pParse, pInClause);
+ sqlite3ExprSetHeightAndFlags(pParse, pInClause);
return pInClause;
/* something went wrong. clean up anything allocated. */
Expr *sqlite3ExprAddCollateToken(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
- const Token *pCollName /* Name of collating sequence */
+ const Token *pCollName, /* Name of collating sequence */
+ int dequote /* True to dequote pCollName */
){
if( pCollName->n>0 ){
- Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
+ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote);
if( pNew ){
pNew->pLeft = pExpr;
pNew->flags |= EP_Collate|EP_Skip;
assert( zC!=0 );
s.z = zC;
s.n = sqlite3Strlen30(s.z);
- return sqlite3ExprAddCollateToken(pParse, pExpr, &s);
+ return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
}
/*
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
break;
}
- if( p->pTab!=0
- && (op==TK_AGG_COLUMN || op==TK_COLUMN
+ if( (op==TK_AGG_COLUMN || op==TK_COLUMN
|| op==TK_REGISTER || op==TK_TRIGGER)
+ && p->pTab!=0
){
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
** a TK_COLUMN but was previously evaluated and cached in a register */
break;
}
if( p->flags & EP_Collate ){
- if( ALWAYS(p->pLeft) && (p->pLeft->flags & EP_Collate)!=0 ){
+ if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){
p = p->pLeft;
}else{
- p = p->pRight;
+ Expr *pNext = p->pRight;
+ /* The Expr.x union is never used at the same time as Expr.pRight */
+ assert( p->x.pList==0 || p->pRight==0 );
+ /* p->flags holds EP_Collate and p->pLeft->flags does not. And
+ ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at
+ ** least one EP_Collate. Thus the following two ALWAYS. */
+ if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){
+ int i;
+ for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
+ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
+ pNext = p->x.pList->a[i].pExpr;
+ break;
+ }
+ }
+ }
+ p = pNext;
}
}else{
break;
** Expr.pSelect member has a height of 1. Any other expression
** has a height equal to the maximum height of any other
** referenced Expr plus one.
+**
+** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags,
+** if appropriate.
*/
static void exprSetHeight(Expr *p){
int nHeight = 0;
heightOfExpr(p->pRight, &nHeight);
if( ExprHasProperty(p, EP_xIsSelect) ){
heightOfSelect(p->x.pSelect, &nHeight);
- }else{
+ }else if( p->x.pList ){
heightOfExprList(p->x.pList, &nHeight);
+ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
}
p->nHeight = nHeight + 1;
}
** Set the Expr.nHeight variable using the exprSetHeight() function. If
** the height is greater than the maximum allowed expression depth,
** leave an error in pParse.
+**
+** Also propagate all EP_Propagate flags from the Expr.x.pList into
+** Expr.flags.
*/
-void sqlite3ExprSetHeight(Parse *pParse, Expr *p){
+void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
+ if( pParse->nErr ) return;
exprSetHeight(p);
sqlite3ExprCheckHeight(pParse, p->nHeight);
}
heightOfSelect(p, &nHeight);
return nHeight;
}
-#else
- #define exprSetHeight(y)
+#else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */
+/*
+** Propagate all EP_Propagate flags from the Expr.x.pList into
+** Expr.flags.
+*/
+void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
+ if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){
+ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
+ }
+}
+#define exprSetHeight(y)
#endif /* SQLITE_MAX_EXPR_DEPTH>0 */
/*
}else{
if( pRight ){
pRoot->pRight = pRight;
- pRoot->flags |= EP_Collate & pRight->flags;
+ pRoot->flags |= EP_Propagate & pRight->flags;
}
if( pLeft ){
pRoot->pLeft = pLeft;
- pRoot->flags |= EP_Collate & pLeft->flags;
+ pRoot->flags |= EP_Propagate & pLeft->flags;
}
exprSetHeight(pRoot);
}
}
pNew->x.pList = pList;
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
- sqlite3ExprSetHeight(pParse, pNew);
+ sqlite3ExprSetHeightAndFlags(pParse, pNew);
return pNew;
}
sqlite3DbFree(db, pList);
}
+/*
+** Return the bitwise-OR of all Expr.flags fields in the given
+** ExprList.
+*/
+u32 sqlite3ExprListFlags(const ExprList *pList){
+ int i;
+ u32 m = 0;
+ if( pList ){
+ for(i=0; i<pList->nExpr; i++){
+ m |= pList->a[i].pExpr->flags;
+ }
+ }
+ return m;
+}
+
/*
** These routines are Walker callbacks used to check expressions to
** see if they are "constant" for some definition of constant. The
** and either pWalker->eCode==4 or 5 or the function has the
** SQLITE_FUNC_CONST flag. */
case TK_FUNCTION:
- if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_Constant) ){
+ if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){
return WRC_Continue;
}else{
pWalker->eCode = 0;
int idxLru;
struct yColCache *p;
- assert( iReg>0 ); /* Register numbers are always positive */
+ /* Unless an error has occurred, register numbers are always positive. */
+ assert( iReg>0 || pParse->nErr || pParse->db->mallocFailed );
assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */
/* The SQLITE_ColumnCache flag disables the column cache. This is used
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
- VdbeOp *pOp = &context->pVdbe->aOp[context->iOp-1];
+ VdbeOp *pOp;
+ assert( context->pVdbe!=0 );
+ pOp = &context->pVdbe->aOp[context->iOp-1];
assert( pOp->opcode==OP_CollSeq );
assert( pOp->p4type==P4_COLLSEQ );
return pOp->p4.pColl;
}
}
}
+#ifdef SQLITE_SUBSTR_COMPATIBILITY
+ /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
+ ** as substr(X,1,N) - it returns the first N characters of X. This
+ ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
+ ** from 2009-02-02 for compatibility of applications that exploited the
+ ** old buggy behavior. */
+ if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
+#endif
if( argc==3 ){
p2 = sqlite3_value_int(argv[2]);
if( p2<0 ){
** then set aWc[0] through aWc[2] to the wildcard characters and
** return TRUE. If the function is not a LIKE-style function then
** return FALSE.
+**
+** *pIsNocase is set to true if uppercase and lowercase are equivalent for
+** the function (default for LIKE). If the function makes the distinction
+** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to
+** false.
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
- 96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
- 112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
+ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */
160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
- 224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
- 239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
+ 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */
#endif
};
** I/O active are written using this function. These messages
** are intended for debugging activity only.
*/
-/* not-private */ void (*sqlite3IoTrace)(const char*, ...) = 0;
+SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0;
#endif
/*
}
#endif
+ /* If the following assert() fails on some obscure processor/compiler
+ ** combination, the work-around is to set the correct pointer
+ ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */
+ assert( SQLITE_PTRSIZE==sizeof(char*) );
+
/* If SQLite is already completely initialized, then this call
** to sqlite3_initialize() should be a no-op. But the initialization
** must be complete. So isInit must not be set until the very end
*/
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */
case SQLITE_CONFIG_SINGLETHREAD: {
- /* Disable all mutexing */
- sqlite3GlobalConfig.bCoreMutex = 0;
- sqlite3GlobalConfig.bFullMutex = 0;
+ /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to
+ ** Single-thread. */
+ sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */
break;
}
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */
case SQLITE_CONFIG_MULTITHREAD: {
- /* Disable mutexing of database connections */
- /* Enable mutexing of core data structures */
- sqlite3GlobalConfig.bCoreMutex = 1;
- sqlite3GlobalConfig.bFullMutex = 0;
+ /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to
+ ** Multi-thread. */
+ sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */
break;
}
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */
case SQLITE_CONFIG_SERIALIZED: {
- /* Enable all mutexing */
- sqlite3GlobalConfig.bCoreMutex = 1;
- sqlite3GlobalConfig.bFullMutex = 1;
+ /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to
+ ** Serialized. */
+ sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */
break;
}
#endif
case SQLITE_CONFIG_HEAP: {
/* EVIDENCE-OF: R-19854-42126 There are three arguments to
** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the
- ** number of bytes in the memory buffer, and the minimum allocation size. */
+ ** number of bytes in the memory buffer, and the minimum allocation size.
+ */
sqlite3GlobalConfig.pHeap = va_arg(ap, void*);
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
sqlite3GlobalConfig.mnReq = va_arg(ap, int);
** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE
** compile-time option.
*/
- if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE;
+ if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){
+ mxMmap = SQLITE_MAX_MMAP_SIZE;
+ }
if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE;
if( szMmap>mxMmap) szMmap = mxMmap;
sqlite3GlobalConfig.mxMmap = mxMmap;
void *pArg
){
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE;
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
db->busyHandler.xFunc = xBusy;
if( !zFile ) return SQLITE_NOMEM;
iIn = 5;
-#ifndef SQLITE_ALLOW_URI_AUTHORITY
+#ifdef SQLITE_ALLOW_URI_AUTHORITY
+ if( strncmp(zUri+5, "///", 3)==0 ){
+ iIn = 7;
+ /* The following condition causes URIs with five leading / characters
+ ** like file://///host/path to be converted into UNCs like //host/path.
+ ** The correct URI for that UNC has only two or four leading / characters
+ ** file://host/path or file:////host/path. But 5 leading slashes is a
+ ** common error, we are told, so we handle it as a special case. */
+ if( strncmp(zUri+7, "///", 3)==0 ){ iIn++; }
+ }else if( strncmp(zUri+5, "//localhost/", 12)==0 ){
+ iIn = 16;
+ }
+#else
/* Discard the scheme and authority segments of the URI. */
if( zUri[5]=='/' && zUri[6]=='/' ){
iIn = 7;
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
| SQLITE_AutoIndex
#endif
+#if SQLITE_DEFAULT_CKPTFULLFSYNC
+ | SQLITE_CkptFullFSync
+#endif
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
opendb_out:
sqlite3_free(zOpen);
if( db ){
- assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
+ assert( db->mutex!=0 || isThreadsafe==0
+ || sqlite3GlobalConfig.bFullMutex==0 );
sqlite3_mutex_leave(db->mutex);
}
rc = sqlite3_errcode(db);
Table *pTab = 0;
Column *pCol = 0;
int iCol = 0;
-
char const *zDataType = 0;
char const *zCollSeq = 0;
int notnull = 0;
int primarykey = 0;
int autoinc = 0;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+
/* Ensure the database schema has been loaded */
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
sqlite3BtreeLeave(pBtree);
}
sqlite3_mutex_leave(db->mutex);
- return rc;
+ return rc;
}
/*
if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR;
break;
}
+
+ /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum);
+ **
+ ** This test control is used to create imposter tables. "db" is a pointer
+ ** to the database connection. dbName is the database name (ex: "main" or
+ ** "temp") which will receive the imposter. "onOff" turns imposter mode on
+ ** or off. "tnum" is the root page of the b-tree to which the imposter
+ ** table should connect.
+ **
+ ** Enable imposter mode only when the schema has already been parsed. Then
+ ** run a single CREATE TABLE statement to construct the imposter table in
+ ** the parsed schema. Then turn imposter mode back off again.
+ **
+ ** If onOff==0 and tnum>0 then reset the schema for all databases, causing
+ ** the schema to be reparsed the next time it is needed. This has the
+ ** effect of erasing all imposter tables.
+ */
+ case SQLITE_TESTCTRL_IMPOSTER: {
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ sqlite3_mutex_enter(db->mutex);
+ db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
+ db->init.busy = db->init.imposterTable = va_arg(ap,int);
+ db->init.newTnum = va_arg(ap,int);
+ if( db->init.busy==0 && db->init.newTnum>0 ){
+ sqlite3ResetAllSchemasOfConnection(db);
+ }
+ sqlite3_mutex_leave(db->mutex);
+ break;
+ }
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
#define mem0 GLOBAL(struct Mem0Global, mem0)
+/*
+** Return the memory allocator mutex. sqlite3_status() needs it.
+*/
+sqlite3_mutex *sqlite3MallocMutex(void){
+ return mem0.mutex;
+}
+
/*
** This routine runs when the memory allocator sees that the
** total memory allocation is about to exceed the soft heap
void *pArg,
sqlite3_int64 iThreshold
){
- int nUsed;
+ sqlite3_int64 nUsed;
sqlite3_mutex_enter(mem0.mutex);
mem0.alarmCallback = xCallback;
mem0.alarmArg = pArg;
** Initialize the memory allocation subsystem.
*/
int sqlite3MallocInit(void){
+ int rc;
if( sqlite3GlobalConfig.m.xMalloc==0 ){
sqlite3MemSetDefault();
}
sqlite3GlobalConfig.szPage = 0;
sqlite3GlobalConfig.nPage = 0;
}
- return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
+ rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
+ if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
+ return rc;
}
/*
nFull = sqlite3GlobalConfig.m.xRoundup(n);
sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
if( mem0.alarmCallback!=0 ){
- int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
mem0.nearlyFull = 1;
sqlite3MallocAlarm(nFull);
#endif
if( p ){
nFull = sqlite3MallocSize(p);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull);
+ sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
}
*pp = p;
return nFull;
p = mem0.pScratchFree;
mem0.pScratchFree = mem0.pScratchFree->pNext;
mem0.nScratchFree--;
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3_mutex_leave(mem0.mutex);
p = sqlite3Malloc(n);
if( sqlite3GlobalConfig.bMemstat && p ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
sqlite3_mutex_leave(mem0.mutex);
}
sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
mem0.pScratchFree = pSlot;
mem0.nScratchFree++;
assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
/* Release memory back to the heap */
assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_SCRATCH) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, -iSize);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize);
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
}
int sqlite3DbMallocSize(sqlite3 *db, void *p){
if( db==0 ){
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return sqlite3MallocSize(p);
}else{
return db->lookaside.sz;
}else{
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
return sqlite3GlobalConfig.m.xSize(p);
}
}
}
sqlite3_uint64 sqlite3_msize(void *p){
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
}
void sqlite3_free(void *p){
if( p==0 ) return; /* IMP: R-49053-54554 */
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p));
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
}
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
int nOld, nNew, nDiff;
void *pNew;
assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
- assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(pOld, (u8)~MEMTYPE_HEAP) );
if( pOld==0 ){
return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */
}
}
if( pNew ){
nNew = sqlite3MallocSize(pNew);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
}
sqlite3_mutex_leave(mem0.mutex);
}else{
}
}else{
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
pNew = sqlite3_realloc64(p, n);
if( !pNew ){
break;
}
default: {
- assert( id-2 >= 0 );
- assert( id-2 < (int)(sizeof(aStatic)/sizeof(aStatic[0])) );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( id-2<0 || id-2>=ArraySize(aStatic) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
pNew = &aStatic[id-2];
pNew->id = id;
break;
static void debugMutexFree(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( p->cnt==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
- sqlite3_free(p);
+ if( p->id==SQLITE_MUTEX_RECURSIVE || p->id==SQLITE_MUTEX_FAST ){
+ sqlite3_free(p);
+ }else{
+#ifdef SQLITE_ENABLE_API_ARMOR
+ (void)SQLITE_MISUSE_BKPT;
+#endif
+ }
}
/*
*/
struct sqlite3_mutex {
pthread_mutex_t mutex; /* Mutex controlling the lock */
-#if SQLITE_MUTEX_NREF
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
int id; /* Mutex type */
+#endif
+#if SQLITE_MUTEX_NREF
volatile int nRef; /* Number of entrances */
volatile pthread_t owner; /* Thread that is within this mutex */
int trace; /* True to trace changes */
pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
-#endif
-#if SQLITE_MUTEX_NREF
- p->id = iType;
#endif
}
break;
case SQLITE_MUTEX_FAST: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
-#if SQLITE_MUTEX_NREF
- p->id = iType;
-#endif
pthread_mutex_init(&p->mutex, 0);
}
break;
}
#endif
p = &staticMutexes[iType-2];
-#if SQLITE_MUTEX_NREF
- p->id = iType;
-#endif
break;
}
}
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
+ if( p ) p->id = iType;
+#endif
return p;
}
*/
static void pthreadMutexFree(sqlite3_mutex *p){
assert( p->nRef==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
- pthread_mutex_destroy(&p->mutex);
- sqlite3_free(p);
+#if SQLITE_ENABLE_API_ARMOR
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE )
+#endif
+ {
+ pthread_mutex_destroy(&p->mutex);
+ sqlite3_free(p);
+ }
+#ifdef SQLITE_ENABLE_API_ARMOR
+ else{
+ (void)SQLITE_MISUSE_BKPT;
+ }
+#endif
}
/*
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
-#ifdef SQLITE_DEBUG
p->id = iType;
+#ifdef SQLITE_DEBUG
#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC
p->trace = 1;
#endif
return 0;
}
#endif
- assert( iType-2 >= 0 );
- assert( iType-2 < ArraySize(winMutex_staticMutexes) );
- assert( winMutex_isInit==1 );
p = &winMutex_staticMutexes[iType-2];
-#ifdef SQLITE_DEBUG
p->id = iType;
+#ifdef SQLITE_DEBUG
#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
p->trace = 1;
#endif
*/
static void winMutexFree(sqlite3_mutex *p){
assert( p );
-#ifdef SQLITE_DEBUG
assert( p->nRef==0 && p->owner==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){
+ DeleteCriticalSection(&p->mutex);
+ sqlite3_free(p);
+ }else{
+#ifdef SQLITE_ENABLE_API_ARMOR
+ (void)SQLITE_MISUSE_BKPT;
#endif
- assert( winMutex_isInit==1 );
- DeleteCriticalSection(&p->mutex);
- sqlite3_free(p);
+ }
}
/*
#endif /* SQLITE_OS_WINRT */
/*
-** This file mapping API is common to both Win32 and WinRT.
+** These file mapping APIs are common to both Win32 and WinRT.
*/
+
+WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T);
WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
#endif /* SQLITE_WIN32_FILEMAPPING_API */
SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
#endif /* defined(InterlockedCompareExchange) */
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ { "UuidCreate", (SYSCALL)UuidCreate, 0 },
+#else
+ { "UuidCreate", (SYSCALL)0, 0 },
+#endif
+
+#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent)
+
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 },
+#else
+ { "UuidCreateSequential", (SYSCALL)0, 0 },
+#endif
+
+#define osUuidCreateSequential \
+ ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent)
+
+#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0
+ { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 },
+#else
+ { "FlushViewOfFile", (SYSCALL)0, 0 },
+#endif
+
+#define osFlushViewOfFile \
+ ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
+
}; /* End of the overrideable system calls */
/*
/*
** Log a I/O error retry episode.
*/
-static void winLogIoerr(int nRetry){
+static void winLogIoerr(int nRetry, int lineno){
if( nRetry ){
- sqlite3_log(SQLITE_IOERR,
- "delayed %dms for lock/sharing conflict",
- winIoerrRetryDelay*nRetry*(nRetry+1)/2
+ sqlite3_log(SQLITE_NOTICE,
+ "delayed %dms for lock/sharing conflict at line %d",
+ winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno
);
}
}
assert( pFile->pShm==0 );
#endif
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
- OSTRACE(("CLOSE file=%p\n", pFile->h));
+ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
#if SQLITE_MAX_MMAP_SIZE>0
winUnmapfile(pFile);
pFile->h = NULL;
}
OpenCounter(-1);
- OSTRACE(("CLOSE file=%p, rc=%s\n", pFile->h, rc ? "ok" : "failed"));
+ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+ osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed"));
return rc ? SQLITE_OK
: winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
"winClose", pFile->zPath);
assert( amt>0 );
assert( offset>=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
- OSTRACE(("READ-MMAP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( winSeekFile(pFile, offset) ){
- OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_FULL;
}
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
DWORD lastErrno;
if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
pFile->lastErrno = lastErrno;
- OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
"winRead", pFile->zPath);
}
- winLogIoerr(nRetry);
+ winLogIoerr(nRetry, __LINE__);
if( nRead<(DWORD)amt ){
/* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[nRead], 0, amt-nRead);
- OSTRACE(("READ file=%p, rc=SQLITE_IOERR_SHORT_READ\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_IOERR_SHORT_READ;
}
- OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
- OSTRACE(("WRITE-MMAP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
if( rc ){
if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
|| ( pFile->lastErrno==ERROR_DISK_FULL )){
- OSTRACE(("WRITE file=%p, rc=SQLITE_FULL\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_FULL, pFile->lastErrno,
"winWrite1", pFile->zPath);
}
- OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
"winWrite2", pFile->zPath);
}else{
- winLogIoerr(nRetry);
+ winLogIoerr(nRetry, __LINE__);
}
- OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
assert( pFile );
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- OSTRACE(("TRUNCATE file=%p, size=%lld, lock=%d\n",
- pFile->h, nByte, pFile->locktype));
+ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n",
+ osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype));
/* If the user has configured a chunk-size for this file, truncate the
** file so that it consists of an integer number of chunks (i.e. the
}
#endif
- OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
+ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+ osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc)));
return rc;
}
*/
SimulateDiskfullError( return SQLITE_FULL );
- OSTRACE(("SYNC file=%p, flags=%x, lock=%d\n",
- pFile->h, flags, pFile->locktype));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n",
+ osGetCurrentProcessId(), pFile, pFile->h, flags,
+ pFile->locktype));
#ifndef SQLITE_TEST
UNUSED_PARAMETER(flags);
** no-op
*/
#ifdef SQLITE_NO_SYNC
- OSTRACE(("SYNC-NOP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
#else
+#if SQLITE_MAX_MMAP_SIZE>0
+ if( pFile->pMapRegion ){
+ if( osFlushViewOfFile(pFile->pMapRegion, 0) ){
+ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+ "rc=SQLITE_OK\n", osGetCurrentProcessId(),
+ pFile, pFile->pMapRegion));
+ }else{
+ pFile->lastErrno = osGetLastError();
+ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+ "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(),
+ pFile, pFile->pMapRegion));
+ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
+ "winSync1", pFile->zPath);
+ }
+ }
+#endif
rc = osFlushFileBuffers(pFile->h);
SimulateIOError( rc=FALSE );
if( rc ){
- OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
pFile->lastErrno = osGetLastError();
- OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
- "winSync", pFile->zPath);
+ "winSync2", pFile->zPath);
}
#endif
}
void volatile **pp /* OUT: Mapped memory */
){
winFile *pDbFd = (winFile*)fd;
- winShm *p = pDbFd->pShm;
+ winShm *pShm = pDbFd->pShm;
winShmNode *pShmNode;
int rc = SQLITE_OK;
- if( !p ){
+ if( !pShm ){
rc = winOpenSharedMemory(pDbFd);
if( rc!=SQLITE_OK ) return rc;
- p = pDbFd->pShm;
+ pShm = pDbFd->pShm;
}
- pShmNode = p->pShmNode;
+ pShmNode = pShm->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
}
}
#endif
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name,
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename);
}else{
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
}
sqlite3_free(zConverted);
OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
attr = sAttrData.dwFileAttributes;
}
}else{
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
sqlite3_free(zConverted);
return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess",
memcpy(&zBuf[n], &i, sizeof(i));
n += sizeof(i);
}
+#endif
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ if( sizeof(UUID)<=nBuf-n ){
+ UUID id;
+ memset(&id, 0, sizeof(UUID));
+ osUuidCreate(&id);
+ memcpy(zBuf, &id, sizeof(UUID));
+ n += sizeof(UUID);
+ }
+ if( sizeof(UUID)<=nBuf-n ){
+ UUID id;
+ memset(&id, 0, sizeof(UUID));
+ osUuidCreateSequential(&id);
+ memcpy(zBuf, &id, sizeof(UUID));
+ n += sizeof(UUID);
+ }
#endif
return n;
}
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==77 );
+ assert( ArraySize(aSyscall)==80 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
# define SQLITE_WIN32_VOLATILE volatile
#endif
+/*
+** For some Windows sub-platforms, the _beginthreadex() / _endthreadex()
+** functions are not available (e.g. those not using MSVC, Cygwin, etc).
+*/
+#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
+ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__)
+# define SQLITE_OS_WIN_THREADS 1
+#else
+# define SQLITE_OS_WIN_THREADS 0
+#endif
+
#endif /* _OS_WIN_H_ */
}
/*
-** Compute the number of pages of cache requested.
+** Compute the number of pages of cache requested. p->szCache is the
+** cache size requested by the "PRAGMA cache_size" statement.
+**
+**
*/
static int numberOfCachePages(PCache *p){
if( p->szCache>=0 ){
+ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
+ ** suggested cache size is set to N. */
return p->szCache;
}else{
+ /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then
+ ** the number of cache pages is adjusted to use approximately abs(N*1024)
+ ** bytes of memory. */
return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
}
}
static void *pcache1Alloc(int nByte){
void *p = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
- sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
if( nByte<=pcache1.szSlot ){
sqlite3_mutex_enter(pcache1.mutex);
p = (PgHdr1 *)pcache1.pFree;
pcache1.nFreeSlot--;
pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
assert( pcache1.nFreeSlot>=0 );
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
}
sqlite3_mutex_leave(pcache1.mutex);
}
if( p ){
int sz = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
sqlite3_mutex_leave(pcache1.mutex);
}
#endif
if( p>=pcache1.pStart && p<pcache1.pEnd ){
PgFreeslot *pSlot;
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
nFreed = sqlite3MallocSize(p);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
sqlite3_mutex_leave(pcache1.mutex);
#endif
sqlite3_free(p);
*/
int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }
+/*
+** Return the global mutex used by this PCACHE implementation. The
+** sqlite3_status() routine needs access to this mutex.
+*/
+sqlite3_mutex *sqlite3Pcache1Mutex(void){
+ return pcache1.mutex;
+}
+
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
#endif
/***************************************************************************
-** The next block of code, including the PragTyp_XXXX macro definitions and
-** the aPragmaName[] object is composed of generated code. DO NOT EDIT.
-**
-** To add new pragmas, edit the code in ../tool/mkpragmatab.tcl and rerun
-** that script. Then copy/paste the output in place of the following:
-*/
-#define PragTyp_HEADER_VALUE 0
-#define PragTyp_AUTO_VACUUM 1
-#define PragTyp_FLAG 2
-#define PragTyp_BUSY_TIMEOUT 3
-#define PragTyp_CACHE_SIZE 4
-#define PragTyp_CASE_SENSITIVE_LIKE 5
-#define PragTyp_COLLATION_LIST 6
-#define PragTyp_COMPILE_OPTIONS 7
-#define PragTyp_DATA_STORE_DIRECTORY 8
-#define PragTyp_DATABASE_LIST 9
-#define PragTyp_DEFAULT_CACHE_SIZE 10
-#define PragTyp_ENCODING 11
-#define PragTyp_FOREIGN_KEY_CHECK 12
-#define PragTyp_FOREIGN_KEY_LIST 13
-#define PragTyp_INCREMENTAL_VACUUM 14
-#define PragTyp_INDEX_INFO 15
-#define PragTyp_INDEX_LIST 16
-#define PragTyp_INTEGRITY_CHECK 17
-#define PragTyp_JOURNAL_MODE 18
-#define PragTyp_JOURNAL_SIZE_LIMIT 19
-#define PragTyp_LOCK_PROXY_FILE 20
-#define PragTyp_LOCKING_MODE 21
-#define PragTyp_PAGE_COUNT 22
-#define PragTyp_MMAP_SIZE 23
-#define PragTyp_PAGE_SIZE 24
-#define PragTyp_SECURE_DELETE 25
-#define PragTyp_SHRINK_MEMORY 26
-#define PragTyp_SOFT_HEAP_LIMIT 27
-#define PragTyp_STATS 28
-#define PragTyp_SYNCHRONOUS 29
-#define PragTyp_TABLE_INFO 30
-#define PragTyp_TEMP_STORE 31
-#define PragTyp_TEMP_STORE_DIRECTORY 32
-#define PragTyp_THREADS 33
-#define PragTyp_WAL_AUTOCHECKPOINT 34
-#define PragTyp_WAL_CHECKPOINT 35
-#define PragTyp_ACTIVATE_EXTENSIONS 36
-#define PragTyp_HEXKEY 37
-#define PragTyp_KEY 38
-#define PragTyp_REKEY 39
-#define PragTyp_LOCK_STATUS 40
-#define PragTyp_PARSER_TRACE 41
-#define PragFlag_NeedSchema 0x01
-#define PragFlag_ReadOnly 0x02
-static const struct sPragmaNames {
- const char *const zName; /* Name of pragma */
- u8 ePragTyp; /* PragTyp_XXX value */
- u8 mPragFlag; /* Zero or more PragFlag_XXX values */
- u32 iArg; /* Extra argument */
-} aPragmaNames[] = {
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
- { /* zName: */ "activate_extensions",
- /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "application_id",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_APPLICATION_ID },
-#endif
-#if !defined(SQLITE_OMIT_AUTOVACUUM)
- { /* zName: */ "auto_vacuum",
- /* ePragTyp: */ PragTyp_AUTO_VACUUM,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
- { /* zName: */ "automatic_index",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_AutoIndex },
-#endif
-#endif
- { /* zName: */ "busy_timeout",
- /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "cache_size",
- /* ePragTyp: */ PragTyp_CACHE_SIZE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "cache_spill",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CacheSpill },
-#endif
- { /* zName: */ "case_sensitive_like",
- /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "checkpoint_fullfsync",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CkptFullFSync },
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "collation_list",
- /* ePragTyp: */ PragTyp_COLLATION_LIST,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
- { /* zName: */ "compile_options",
- /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "count_changes",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CountRows },
-#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
- { /* zName: */ "data_store_directory",
- /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "data_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ PragFlag_ReadOnly,
- /* iArg: */ BTREE_DATA_VERSION },
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "database_list",
- /* ePragTyp: */ PragTyp_DATABASE_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
- { /* zName: */ "default_cache_size",
- /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "defer_foreign_keys",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_DeferFKs },
-#endif
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "empty_result_callbacks",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_NullCallback },
-#endif
-#if !defined(SQLITE_OMIT_UTF16)
- { /* zName: */ "encoding",
- /* ePragTyp: */ PragTyp_ENCODING,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "foreign_key_check",
- /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FOREIGN_KEY)
- { /* zName: */ "foreign_key_list",
- /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "foreign_keys",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ForeignKeys },
-#endif
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "freelist_count",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ PragFlag_ReadOnly,
- /* iArg: */ BTREE_FREE_PAGE_COUNT },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "full_column_names",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_FullColNames },
- { /* zName: */ "fullfsync",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_FullFSync },
-#endif
-#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "hexkey",
- /* ePragTyp: */ PragTyp_HEXKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "hexrekey",
- /* ePragTyp: */ PragTyp_HEXKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if !defined(SQLITE_OMIT_CHECK)
- { /* zName: */ "ignore_check_constraints",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_IgnoreChecks },
-#endif
-#endif
-#if !defined(SQLITE_OMIT_AUTOVACUUM)
- { /* zName: */ "incremental_vacuum",
- /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "index_info",
- /* ePragTyp: */ PragTyp_INDEX_INFO,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "index_list",
- /* ePragTyp: */ PragTyp_INDEX_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
- { /* zName: */ "integrity_check",
- /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "journal_mode",
- /* ePragTyp: */ PragTyp_JOURNAL_MODE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "journal_size_limit",
- /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "key",
- /* ePragTyp: */ PragTyp_KEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "legacy_file_format",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_LegacyFileFmt },
-#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
- { /* zName: */ "lock_proxy_file",
- /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- { /* zName: */ "lock_status",
- /* ePragTyp: */ PragTyp_LOCK_STATUS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "locking_mode",
- /* ePragTyp: */ PragTyp_LOCKING_MODE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "max_page_count",
- /* ePragTyp: */ PragTyp_PAGE_COUNT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "mmap_size",
- /* ePragTyp: */ PragTyp_MMAP_SIZE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "page_count",
- /* ePragTyp: */ PragTyp_PAGE_COUNT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "page_size",
- /* ePragTyp: */ PragTyp_PAGE_SIZE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if defined(SQLITE_DEBUG)
- { /* zName: */ "parser_trace",
- /* ePragTyp: */ PragTyp_PARSER_TRACE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "query_only",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_QueryOnly },
-#endif
-#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
- { /* zName: */ "quick_check",
- /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "read_uncommitted",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ReadUncommitted },
- { /* zName: */ "recursive_triggers",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_RecTriggers },
-#endif
-#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "rekey",
- /* ePragTyp: */ PragTyp_REKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "reverse_unordered_selects",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ReverseOrder },
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "schema_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_SCHEMA_VERSION },
-#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "secure_delete",
- /* ePragTyp: */ PragTyp_SECURE_DELETE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "short_column_names",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ShortColNames },
-#endif
- { /* zName: */ "shrink_memory",
- /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "soft_heap_limit",
- /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if defined(SQLITE_DEBUG)
- { /* zName: */ "sql_trace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_SqlTrace },
-#endif
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "stats",
- /* ePragTyp: */ PragTyp_STATS,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "synchronous",
- /* ePragTyp: */ PragTyp_SYNCHRONOUS,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "table_info",
- /* ePragTyp: */ PragTyp_TABLE_INFO,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "temp_store",
- /* ePragTyp: */ PragTyp_TEMP_STORE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "temp_store_directory",
- /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
- { /* zName: */ "threads",
- /* ePragTyp: */ PragTyp_THREADS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "user_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_USER_VERSION },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if defined(SQLITE_DEBUG)
- { /* zName: */ "vdbe_addoptrace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeAddopTrace },
- { /* zName: */ "vdbe_debug",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
- { /* zName: */ "vdbe_eqp",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeEQP },
- { /* zName: */ "vdbe_listing",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeListing },
- { /* zName: */ "vdbe_trace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeTrace },
-#endif
-#endif
-#if !defined(SQLITE_OMIT_WAL)
- { /* zName: */ "wal_autocheckpoint",
- /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "wal_checkpoint",
- /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
-#endif
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "writable_schema",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
-#endif
-};
-/* Number of pragmas: 58 on by default, 71 total. */
-/* End of the automatically generated pragma table.
-***************************************************************************/
+** The "pragma.h" include file is an automatically generated file that
+** that includes the PragType_XXXX macro definitions and the aPragmaName[]
+** object. This ensures that the aPragmaName[] table is arranged in
+** lexicographical order to facility a binary search of the pragma name.
+** Do not edit pragma.h directly. Edit and rerun the script in at
+** ../tool/mkpragmatab.tcl. */
+#include "pragma.h"
/*
** Interpret the given string as a safety level. Return 0 for OFF,
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
+ const struct sPragmaNames *pPragma;
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
/* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS
** connection. If it returns SQLITE_OK, then assume that the VFS
** handled the pragma and generate a no-op prepared statement.
+ **
+ ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed,
+ ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file
+ ** object corresponding to the database file to which the pragma
+ ** statement refers.
+ **
+ ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA
+ ** file control is an array of pointers to strings (char**) in which the
+ ** second element of the array is the name of the pragma and the third
+ ** element is the argument to the pragma or NULL if the pragma has no
+ ** argument.
*/
aFcntl[0] = 0;
aFcntl[1] = zLeft;
}
}
if( lwr>upr ) goto pragma_out;
+ pPragma = &aPragmaNames[mid];
/* Make sure the database schema is loaded if the pragma requires that */
- if( (aPragmaNames[mid].mPragFlag & PragFlag_NeedSchema)!=0 ){
+ if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
}
/* Jump to the appropriate pragma handler */
- switch( aPragmaNames[mid].ePragTyp ){
+ switch( pPragma->ePragTyp ){
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
case PragTyp_FLAG: {
if( zRight==0 ){
- returnSingleInt(pParse, aPragmaNames[mid].zName,
- (db->flags & aPragmaNames[mid].iArg)!=0 );
+ returnSingleInt(pParse, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
}else{
- int mask = aPragmaNames[mid].iArg; /* Mask of bits to set or clear. */
+ int mask = pPragma->iArg; /* Mask of bits to set or clear. */
if( db->autoCommit==0 ){
/* Foreign key support may not be enabled or disabled while not
** in auto-commit mode. */
pIdx = sqlite3FindIndex(db, zRight, zDb);
if( pIdx ){
int i;
+ int mx;
+ if( pPragma->iArg ){
+ /* PRAGMA index_xinfo (newer version with more rows and columns) */
+ mx = pIdx->nColumn;
+ pParse->nMem = 6;
+ }else{
+ /* PRAGMA index_info (legacy version) */
+ mx = pIdx->nKeyCol;
+ pParse->nMem = 3;
+ }
pTab = pIdx->pTable;
- sqlite3VdbeSetNumCols(v, 3);
- pParse->nMem = 3;
+ sqlite3VdbeSetNumCols(v, pParse->nMem);
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC);
- for(i=0; i<pIdx->nKeyCol; i++){
+ if( pPragma->iArg ){
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC);
+ }
+ for(i=0; i<mx; i++){
i16 cnum = pIdx->aiColumn[i];
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
- assert( pTab->nCol>cnum );
- sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
+ if( cnum<0 ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, 3);
+ }else{
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
+ }
+ if( pPragma->iArg ){
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6);
+ }
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem);
}
}
}
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
- sqlite3VdbeSetNumCols(v, 3);
- pParse->nMem = 3;
+ sqlite3VdbeSetNumCols(v, 5);
+ pParse->nMem = 5;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "origin", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "partial", SQLITE_STATIC);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
+ const char *azOrigin[] = { "c", "u", "pk" };
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, azOrigin[pIdx->idxType], 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->pPartIdxWhere!=0, 5);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
}
}
}
** applications for any purpose.
*/
case PragTyp_HEADER_VALUE: {
- int iCookie = aPragmaNames[mid].iArg; /* Which cookie to read or write */
+ int iCookie = pPragma->iArg; /* Which cookie to read or write */
sqlite3VdbeUsesBtree(v, iDb);
- if( zRight && (aPragmaNames[mid].mPragFlag & PragFlag_ReadOnly)==0 ){
+ if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
/*
** PRAGMA shrink_memory
**
- ** This pragma attempts to free as much memory as possible from the
- ** current database connection.
+ ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database
+ ** connection on which it is invoked to free up as much memory as it
+ ** can, by calling sqlite3_db_release_memory().
*/
case PragTyp_SHRINK_MEMORY: {
sqlite3_db_release_memory(db);
** disables the timeout.
*/
/*case PragTyp_BUSY_TIMEOUT*/ default: {
- assert( aPragmaNames[mid].ePragTyp==PragTyp_BUSY_TIMEOUT );
+ assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT );
if( zRight ){
sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
}
** PRAGMA soft_heap_limit
** PRAGMA soft_heap_limit = N
**
- ** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted,
- ** use -1.
+ ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the
+ ** sqlite3_soft_heap_limit64() interface with the argument N, if N is
+ ** specified and is a non-negative integer.
+ ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always
+ ** returns the same integer that would be returned by the
+ ** sqlite3_soft_heap_limit64(-1) C-language function.
*/
case PragTyp_SOFT_HEAP_LIMIT: {
sqlite3_int64 N;
--- /dev/null
+/* DO NOT EDIT!
+** This file is automatically generated by the script at
+** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit
+** that script and rerun it.
+*/
+#define PragTyp_HEADER_VALUE 0
+#define PragTyp_AUTO_VACUUM 1
+#define PragTyp_FLAG 2
+#define PragTyp_BUSY_TIMEOUT 3
+#define PragTyp_CACHE_SIZE 4
+#define PragTyp_CASE_SENSITIVE_LIKE 5
+#define PragTyp_COLLATION_LIST 6
+#define PragTyp_COMPILE_OPTIONS 7
+#define PragTyp_DATA_STORE_DIRECTORY 8
+#define PragTyp_DATABASE_LIST 9
+#define PragTyp_DEFAULT_CACHE_SIZE 10
+#define PragTyp_ENCODING 11
+#define PragTyp_FOREIGN_KEY_CHECK 12
+#define PragTyp_FOREIGN_KEY_LIST 13
+#define PragTyp_INCREMENTAL_VACUUM 14
+#define PragTyp_INDEX_INFO 15
+#define PragTyp_INDEX_LIST 16
+#define PragTyp_INTEGRITY_CHECK 17
+#define PragTyp_JOURNAL_MODE 18
+#define PragTyp_JOURNAL_SIZE_LIMIT 19
+#define PragTyp_LOCK_PROXY_FILE 20
+#define PragTyp_LOCKING_MODE 21
+#define PragTyp_PAGE_COUNT 22
+#define PragTyp_MMAP_SIZE 23
+#define PragTyp_PAGE_SIZE 24
+#define PragTyp_SECURE_DELETE 25
+#define PragTyp_SHRINK_MEMORY 26
+#define PragTyp_SOFT_HEAP_LIMIT 27
+#define PragTyp_STATS 28
+#define PragTyp_SYNCHRONOUS 29
+#define PragTyp_TABLE_INFO 30
+#define PragTyp_TEMP_STORE 31
+#define PragTyp_TEMP_STORE_DIRECTORY 32
+#define PragTyp_THREADS 33
+#define PragTyp_WAL_AUTOCHECKPOINT 34
+#define PragTyp_WAL_CHECKPOINT 35
+#define PragTyp_ACTIVATE_EXTENSIONS 36
+#define PragTyp_HEXKEY 37
+#define PragTyp_KEY 38
+#define PragTyp_REKEY 39
+#define PragTyp_LOCK_STATUS 40
+#define PragTyp_PARSER_TRACE 41
+#define PragFlag_NeedSchema 0x01
+#define PragFlag_ReadOnly 0x02
+static const struct sPragmaNames {
+ const char *const zName; /* Name of pragma */
+ u8 ePragTyp; /* PragTyp_XXX value */
+ u8 mPragFlag; /* Zero or more PragFlag_XXX values */
+ u32 iArg; /* Extra argument */
+} aPragmaNames[] = {
+#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
+ { /* zName: */ "activate_extensions",
+ /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
+ { /* zName: */ "application_id",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ BTREE_APPLICATION_ID },
+#endif
+#if !defined(SQLITE_OMIT_AUTOVACUUM)
+ { /* zName: */ "auto_vacuum",
+ /* ePragTyp: */ PragTyp_AUTO_VACUUM,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
+ { /* zName: */ "automatic_index",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_AutoIndex },
+#endif
+#endif
+ { /* zName: */ "busy_timeout",
+ /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
+ { /* zName: */ "cache_size",
+ /* ePragTyp: */ PragTyp_CACHE_SIZE,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "cache_spill",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_CacheSpill },
+#endif
+ { /* zName: */ "case_sensitive_like",
+ /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "checkpoint_fullfsync",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_CkptFullFSync },
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
+ { /* zName: */ "collation_list",
+ /* ePragTyp: */ PragTyp_COLLATION_LIST,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
+ { /* zName: */ "compile_options",
+ /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "count_changes",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_CountRows },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
+ { /* zName: */ "data_store_directory",
+ /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
+ { /* zName: */ "data_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlag: */ PragFlag_ReadOnly,
+ /* iArg: */ BTREE_DATA_VERSION },
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
+ { /* zName: */ "database_list",
+ /* ePragTyp: */ PragTyp_DATABASE_LIST,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
+ { /* zName: */ "default_cache_size",
+ /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
+ { /* zName: */ "defer_foreign_keys",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_DeferFKs },
+#endif
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "empty_result_callbacks",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_NullCallback },
+#endif
+#if !defined(SQLITE_OMIT_UTF16)
+ { /* zName: */ "encoding",
+ /* ePragTyp: */ PragTyp_ENCODING,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
+ { /* zName: */ "foreign_key_check",
+ /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FOREIGN_KEY)
+ { /* zName: */ "foreign_key_list",
+ /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
+ { /* zName: */ "foreign_keys",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_ForeignKeys },
+#endif
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
+ { /* zName: */ "freelist_count",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlag: */ PragFlag_ReadOnly,
+ /* iArg: */ BTREE_FREE_PAGE_COUNT },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "full_column_names",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_FullColNames },
+ { /* zName: */ "fullfsync",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_FullFSync },
+#endif
+#if defined(SQLITE_HAS_CODEC)
+ { /* zName: */ "hexkey",
+ /* ePragTyp: */ PragTyp_HEXKEY,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+ { /* zName: */ "hexrekey",
+ /* ePragTyp: */ PragTyp_HEXKEY,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+#if !defined(SQLITE_OMIT_CHECK)
+ { /* zName: */ "ignore_check_constraints",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_IgnoreChecks },
+#endif
+#endif
+#if !defined(SQLITE_OMIT_AUTOVACUUM)
+ { /* zName: */ "incremental_vacuum",
+ /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
+ { /* zName: */ "index_info",
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+ { /* zName: */ "index_list",
+ /* ePragTyp: */ PragTyp_INDEX_LIST,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+ { /* zName: */ "index_xinfo",
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 1 },
+#endif
+#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
+ { /* zName: */ "integrity_check",
+ /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
+ { /* zName: */ "journal_mode",
+ /* ePragTyp: */ PragTyp_JOURNAL_MODE,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+ { /* zName: */ "journal_size_limit",
+ /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if defined(SQLITE_HAS_CODEC)
+ { /* zName: */ "key",
+ /* ePragTyp: */ PragTyp_KEY,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "legacy_file_format",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_LegacyFileFmt },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
+ { /* zName: */ "lock_proxy_file",
+ /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
+ { /* zName: */ "lock_status",
+ /* ePragTyp: */ PragTyp_LOCK_STATUS,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
+ { /* zName: */ "locking_mode",
+ /* ePragTyp: */ PragTyp_LOCKING_MODE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+ { /* zName: */ "max_page_count",
+ /* ePragTyp: */ PragTyp_PAGE_COUNT,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+ { /* zName: */ "mmap_size",
+ /* ePragTyp: */ PragTyp_MMAP_SIZE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+ { /* zName: */ "page_count",
+ /* ePragTyp: */ PragTyp_PAGE_COUNT,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+ { /* zName: */ "page_size",
+ /* ePragTyp: */ PragTyp_PAGE_SIZE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if defined(SQLITE_DEBUG)
+ { /* zName: */ "parser_trace",
+ /* ePragTyp: */ PragTyp_PARSER_TRACE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "query_only",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_QueryOnly },
+#endif
+#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
+ { /* zName: */ "quick_check",
+ /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "read_uncommitted",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_ReadUncommitted },
+ { /* zName: */ "recursive_triggers",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_RecTriggers },
+#endif
+#if defined(SQLITE_HAS_CODEC)
+ { /* zName: */ "rekey",
+ /* ePragTyp: */ PragTyp_REKEY,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "reverse_unordered_selects",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_ReverseOrder },
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
+ { /* zName: */ "schema_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ BTREE_SCHEMA_VERSION },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
+ { /* zName: */ "secure_delete",
+ /* ePragTyp: */ PragTyp_SECURE_DELETE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "short_column_names",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_ShortColNames },
+#endif
+ { /* zName: */ "shrink_memory",
+ /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+ { /* zName: */ "soft_heap_limit",
+ /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+#if defined(SQLITE_DEBUG)
+ { /* zName: */ "sql_trace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_SqlTrace },
+#endif
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
+ { /* zName: */ "stats",
+ /* ePragTyp: */ PragTyp_STATS,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
+ { /* zName: */ "synchronous",
+ /* ePragTyp: */ PragTyp_SYNCHRONOUS,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
+ { /* zName: */ "table_info",
+ /* ePragTyp: */ PragTyp_TABLE_INFO,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
+ { /* zName: */ "temp_store",
+ /* ePragTyp: */ PragTyp_TEMP_STORE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+ { /* zName: */ "temp_store_directory",
+ /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#endif
+ { /* zName: */ "threads",
+ /* ePragTyp: */ PragTyp_THREADS,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
+ { /* zName: */ "user_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlag: */ 0,
+ /* iArg: */ BTREE_USER_VERSION },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+#if defined(SQLITE_DEBUG)
+ { /* zName: */ "vdbe_addoptrace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_VdbeAddopTrace },
+ { /* zName: */ "vdbe_debug",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
+ { /* zName: */ "vdbe_eqp",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_VdbeEQP },
+ { /* zName: */ "vdbe_listing",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_VdbeListing },
+ { /* zName: */ "vdbe_trace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_VdbeTrace },
+#endif
+#endif
+#if !defined(SQLITE_OMIT_WAL)
+ { /* zName: */ "wal_autocheckpoint",
+ /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
+ /* ePragFlag: */ 0,
+ /* iArg: */ 0 },
+ { /* zName: */ "wal_checkpoint",
+ /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ { /* zName: */ "writable_schema",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlag: */ 0,
+ /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
+#endif
+};
+/* Number of pragmas: 59 on by default, 72 total. */
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( ap==0 ){
- (void)SQLITE_MISUSE_BKPT;
- sqlite3StrAccumReset(pAccum);
- return;
- }
-#endif
bufpt = 0;
if( bFlags ){
if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
}
if( width<0 ){
flag_leftjustify = 1;
- width = -width;
+ width = width >= -2147483647 ? -width : 0;
}
c = *++fmt;
}else{
+ unsigned wx = 0;
while( c>='0' && c<='9' ){
- width = width*10 + c - '0';
+ wx = wx*10 + c - '0';
c = *++fmt;
}
+ testcase( wx>0x7fffffff );
+ width = wx & 0x7fffffff;
}
+
/* Get the precision */
if( c=='.' ){
precision = 0;
}else{
precision = va_arg(ap,int);
}
- if( precision<0 ) precision = -precision;
c = *++fmt;
+ if( precision<0 ){
+ precision = precision >= -2147483647 ? -precision : -1;
+ }
}else{
+ unsigned px = 0;
while( c>='0' && c<='9' ){
- precision = precision*10 + c - '0';
+ px = px*10 + c - '0';
c = *++fmt;
}
+ testcase( px>0x7fffffff );
+ precision = px & 0x7fffffff;
}
}else{
precision = -1;
else prefix = 0;
}
if( xtype==etGENERIC && precision>0 ) precision--;
- for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
+ testcase( precision>0xfff );
+ for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){}
if( xtype==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
}else{
e2 = exp;
}
- if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){
- bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 );
+ if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){
+ bufpt = zExtra
+ = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 );
if( bufpt==0 ){
setStrAccumError(pAccum, STRACCUM_NOMEM);
return;
*/
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew;
- assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
+ assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
testcase(p->accError==STRACCUM_TOOBIG);
testcase(p->accError==STRACCUM_NOMEM);
** Append N copies of character c to the given string buffer.
*/
void sqlite3AppendChar(StrAccum *p, int N, char c){
- if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
+ testcase( p->nChar + (i64)N > 0x7fffffff );
+ if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
+ return;
+ }
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
#ifdef SQLITE_ENABLE_API_ARMOR
if( zBuf==0 || zFormat==0 ) {
(void)SQLITE_MISUSE_BKPT;
- if( zBuf && n>0 ) zBuf[0] = 0;
+ if( zBuf ) zBuf[0] = 0;
return zBuf;
}
#endif
testcase( pNC->ncFlags & NC_PartIdx );
testcase( pNC->ncFlags & NC_IsCheck );
if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){
- /* Silently ignore database qualifiers inside CHECK constraints and partial
- ** indices. Do not raise errors because that might break legacy and
- ** because it does not hurt anything to just ignore the database name. */
+ /* Silently ignore database qualifiers inside CHECK constraints and
+ ** partial indices. Do not raise errors because that might break
+ ** legacy and because it does not hurt anything to just ignore the
+ ** database name. */
zDb = 0;
}else{
for(i=0; i<db->nDb; i++){
if( pMatch ){
pExpr->iTable = pMatch->iCursor;
pExpr->pTab = pMatch->pTab;
- assert( (pMatch->jointype & JT_RIGHT)==0 ); /* RIGHT JOIN not (yet) supported */
+ /* RIGHT JOIN not (yet) supported */
+ assert( (pMatch->jointype & JT_RIGHT)==0 );
if( (pMatch->jointype & JT_LEFT)!=0 ){
ExprSetProperty(pExpr, EP_CanBeNull);
}
pExpr->affinity = SQLITE_AFF_INTEGER;
break;
}
-#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */
+#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
+ && !defined(SQLITE_OMIT_SUBQUERY) */
/* A lone identifier is the name of a column.
*/
if( n==2 ){
pExpr->iTable = exprProbability(pList->a[1].pExpr);
if( pExpr->iTable<0 ){
- sqlite3ErrorMsg(pParse, "second argument to likelihood() must be a "
- "constant between 0.0 and 1.0");
+ sqlite3ErrorMsg(pParse,
+ "second argument to likelihood() must be a "
+ "constant between 0.0 and 1.0");
pNC->nErr++;
}
}else{
- /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to
- ** likelihood(X, 0.0625).
- ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for
- ** likelihood(X,0.0625).
- ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for
- ** likelihood(X,0.9375).
- ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to
- ** likelihood(X,0.9375). */
+ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is
+ ** equivalent to likelihood(X, 0.0625).
+ ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is
+ ** short-hand for likelihood(X,0.0625).
+ ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand
+ ** for likelihood(X,0.9375).
+ ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent
+ ** to likelihood(X,0.9375). */
/* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120;
}
return WRC_Prune;
}
#endif
- if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant);
+ if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){
+ ExprSetProperty(pExpr,EP_ConstFunc);
+ }
}
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
return 1;
}
- resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr, zType,0);
+ resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,
+ zType,0);
}
}
return 0;
sqlite3ResolveExprNames(&sNC, p->pOffset) ){
return WRC_Abort;
}
+
+ /* If the SF_Converted flags is set, then this Select object was
+ ** was created by the convertCompoundSelectToSubquery() function.
+ ** In this case the ORDER BY clause (p->pOrderBy) should be resolved
+ ** as if it were part of the sub-query, not the parent. This block
+ ** moves the pOrderBy down to the sub-query. It will be moved back
+ ** after the names have been resolved. */
+ if( p->selFlags & SF_Converted ){
+ Select *pSub = p->pSrc->a[0].pSelect;
+ assert( p->pSrc->nSrc==1 && isCompound==0 && p->pOrderBy );
+ assert( pSub->pPrior && pSub->pOrderBy==0 );
+ pSub->pOrderBy = p->pOrderBy;
+ p->pOrderBy = 0;
+ }
/* Recursively resolve names in all subqueries
*/
sNC.pNext = 0;
sNC.ncFlags |= NC_AllowAgg;
+ /* If this is a converted compound query, move the ORDER BY clause from
+ ** the sub-query back to the parent query. At this point each term
+ ** within the ORDER BY clause has been transformed to an integer value.
+ ** These integers will be replaced by copies of the corresponding result
+ ** set expressions by the call to resolveOrderGroupBy() below. */
+ if( p->selFlags & SF_Converted ){
+ Select *pSub = p->pSrc->a[0].pSelect;
+ p->pOrderBy = pSub->pOrderBy;
+ pSub->pOrderBy = 0;
+ }
+
/* Process the ORDER BY clause for singleton SELECT statements.
** The ORDER BY clause for compounds SELECT statements is handled
** below, after all of the result-sets for all of the elements of
}
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
if( pSelect->iLimit ){
- int addr1, addr2;
+ int addr;
int iLimit;
if( pSelect->iOffset ){
iLimit = pSelect->iOffset+1;
}else{
iLimit = pSelect->iLimit;
}
- addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
- addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
- sqlite3VdbeJumpHere(v, addr1);
+ addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
- sqlite3VdbeJumpHere(v, addr2);
+ sqlite3VdbeJumpHere(v, addr);
}
}
** the output for us.
*/
if( pSort==0 && p->iLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
}
}
sqlite3ExprCode(pParse, p->pLimit, iLimit);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v);
VdbeComment((v, "LIMIT counter"));
- sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
}
if( p->pOffset ){
p->iOffset = iOffset = ++pParse->nMem;
selectInnerLoop(pParse, p, p->pEList, iCurrent,
0, 0, pDest, addrCont, addrBreak);
if( regLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
VdbeCoverage(v);
}
sqlite3VdbeResolveLabel(v, addrCont);
p->iLimit = pPrior->iLimit;
p->iOffset = pPrior->iOffset;
if( p->iLimit ){
- addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeCoverage(v);
+ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
VdbeComment((v, "Jump ahead if LIMIT reached"));
}
explainSetInteger(iSub2, pParse->iNextSelectId);
/* Jump to the end of the loop if the LIMIT is reached.
*/
if( p->iLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
}
/* Generate the subroutine return
**
** (1) The subquery and the outer query do not both use aggregates.
**
-** (2) The subquery is not an aggregate or the outer query is not a join.
+** (2) The subquery is not an aggregate or (2a) the outer query is not a join
+** and (2b) the outer query does not use subqueries other than the one
+** FROM-clause subquery that is a candidate for flattening. (2b is
+** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
**
** (3) The subquery is not the right operand of a left outer join
** (Originally ticket #306. Strengthened by ticket #3300)
iParent = pSubitem->iCursor;
pSub = pSubitem->pSelect;
assert( pSub!=0 );
- if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */
- if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */
+ if( subqueryIsAgg ){
+ if( isAgg ) return 0; /* Restriction (1) */
+ if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */
+ if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
+ || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
+ || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
+ ){
+ return 0; /* Restriction (2b) */
+ }
+ }
+
pSubSrc = pSub->pSrc;
assert( pSubSrc );
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
p->pPrior = 0;
p->pNext = 0;
p->selFlags &= ~SF_Compound;
+ assert( (p->selFlags & SF_Converted)==0 );
+ p->selFlags |= SF_Converted;
assert( pNew->pPrior!=0 );
pNew->pPrior->pNext = pNew;
pNew->pLimit = 0;
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
pEList = pLeft->pEList;
if( pCte->pCols ){
- if( pEList->nExpr!=pCte->pCols->nExpr ){
+ if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){
sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns",
pCte->zName, pEList->nExpr, pCte->pCols->nExpr
);
/* A sub-query in the FROM clause of a SELECT */
assert( pSel!=0 );
assert( pFrom->pTab==0 );
- sqlite3WalkSelect(pWalker, pSel);
+ if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
pTab->nRef = 1;
}
isAgg = (p->selFlags & SF_Aggregate)!=0;
assert( pEList!=0 );
+#if SELECTTRACE_ENABLED
+ if( sqlite3SelectTrace & 0x100 ){
+ SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+
/* Begin generating code.
*/
void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
int n = 0;
pView = sqlite3TreeViewPush(pView, moreToFollow);
- sqlite3TreeViewLine(pView, "SELECT%s%s",
+ sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p)",
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
- ((p->selFlags & SF_Aggregate) ? " agg_flag" : "")
+ ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p
);
if( p->pSrc && p->pSrc->nSrc ) n++;
if( p->pWhere ) n++;
/*
-** Add the ability to override 'extern'
+** Provide the ability to override linkage features of the interface.
*/
#ifndef SQLITE_EXTERN
# define SQLITE_EXTERN extern
#endif
+#ifndef SQLITE_API
+# define SQLITE_API
+#endif
+#ifndef SQLITE_CDECL
+# define SQLITE_CDECL
+#endif
+#ifndef SQLITE_STDCALL
+# define SQLITE_STDCALL
+#endif
/*
** These no-op macros are used in front of interfaces to mark those
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
** interface.
**
+** <ul>
+** <li>[[SQLITE_FCNTL_LOCKSTATE]]
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
** into an integer that the pArg argument points to. This capability
-** is used during testing and only needs to be supported when SQLITE_TEST
-** is defined.
-** <ul>
+** is used during testing and is only available when the SQLITE_TEST
+** compile-time option is used.
+**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
** file control returns [SQLITE_OK], then the parser assumes that the
** VFS has handled the PRAGMA itself and the parser generates a no-op
-** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns
+** prepared statement if result string is NULL, or that returns a copy
+** of the result string if the string is non-NULL.
+** ^If the [SQLITE_FCNTL_PRAGMA] file control returns
** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means
** that the VFS encountered an error while handling the [PRAGMA] and the
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
+** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
+** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
+** be advantageous to block on the next WAL lock if the lock is not immediately
+** available. The WAL subsystem issues this signal during rare
+** circumstances in order to fix a problem with priority inversion.
+** Applications should <em>not</em> use this file-control.
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
-#define SQLITE_GET_LOCKPROXYFILE 2
-#define SQLITE_SET_LOCKPROXYFILE 3
-#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
+#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3
+#define SQLITE_FCNTL_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7
#define SQLITE_FCNTL_SYNC 21
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
+#define SQLITE_FCNTL_WAL_BLOCK 24
+
+/* deprecated names */
+#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
+#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
+#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
+
/*
** CAPI3REF: Mutex Handle
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
** <li> [sqlite3_soft_heap_limit64()]
-** <li> [sqlite3_status()]
+** <li> [sqlite3_status64()]
** </ul>)^
** ^Memory allocation statistics are enabled by default unless SQLite is
** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory
** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro
** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
** that specifies the maximum size of the created heap.
-** </dl>
**
** [[SQLITE_CONFIG_PCACHE_HDRSZ]]
** <dt>SQLITE_CONFIG_PCACHE_HDRSZ
**
** These routines are work-alikes of the "printf()" family of functions
** from the standard C library.
+** These routines understand most of the common K&R formatting options,
+** plus some additional non-standard formats, detailed below.
+** Note that some of the more obscure formatting options from recent
+** C-library standards are omitted from this implementation.
**
** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
** results into memory obtained from [sqlite3_malloc()].
** These routines all implement some additional formatting
** options that are useful for constructing SQL statements.
** All of the usual printf() formatting options apply. In addition, there
-** is are "%q", "%Q", and "%z" options.
+** is are "%q", "%Q", "%w" and "%z" options.
**
** ^(The %q option works like %s in that it substitutes a nul-terminated
** string from the argument list. But %q also doubles every '\'' character.
** The code above will render a correct SQL statement in the zSQL
** variable even if the zText variable is a NULL pointer.
**
+** ^(The "%w" formatting option is like "%q" except that it expects to
+** be contained within double-quotes instead of single quotes, and it
+** escapes the double-quote character instead of the single-quote
+** character.)^ The "%w" formatting option is intended for safely inserting
+** table and column names into a constructed SQL statement.
+**
** ^(The "%z" formatting option works like "%s" but with the
** addition that after the string has been read and copied into
** the result, [sqlite3_free()] is called on the input string.)^
/*
** CAPI3REF: Error Codes And Messages
**
-** ^The sqlite3_errcode() interface returns the numeric [result code] or
-** [extended result code] for the most recent failed sqlite3_* API call
-** associated with a [database connection]. If a prior API call failed
-** but the most recent API call succeeded, the return value from
-** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode()
+** ^If the most recent sqlite3_* API call associated with
+** [database connection] D failed, then the sqlite3_errcode(D) interface
+** returns the numeric [result code] or [extended result code] for that
+** API call.
+** If the most recent API call was successful,
+** then the return value from sqlite3_errcode() is undefined.
+** ^The sqlite3_extended_errcode()
** interface is the same except that it always returns the
** [extended result code] even when extended result codes are
** disabled.
** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
** use UTF-16.
**
-** ^If the nByte argument is less than zero, then zSql is read up to the
-** first zero terminator. ^If nByte is non-negative, then it is the maximum
-** number of bytes read from zSql. ^When nByte is non-negative, the
-** zSql string ends at either the first '\000' or '\u0000' character or
-** the nByte-th byte, whichever comes first. If the caller knows
-** that the supplied string is nul-terminated, then there is a small
-** performance advantage to be gained by passing an nByte parameter that
-** is equal to the number of bytes in the input string <i>including</i>
-** the nul-terminator bytes as this saves SQLite from having to
-** make a copy of the input string.
+** ^If the nByte argument is negative, then zSql is read up to the
+** first zero terminator. ^If nByte is positive, then it is the
+** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** statement is generated.
+** If the caller knows that the supplied string is nul-terminated, then
+** there is a small performance advantage to passing an nByte parameter that
+** is the number of bytes in the input string <i>including</i>
+** the nul-terminator.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
** These functions are [deprecated]. In order to maintain
** backwards compatibility with older code, these functions continue
** to be supported. However, new applications should avoid
-** the use of these functions. To help encourage people to avoid
-** using these functions, we are not going to tell you what they do.
+** the use of these functions. To encourage programmers to avoid
+** these functions, we will not explain what they do.
*/
#ifndef SQLITE_OMIT_DEPRECATED
SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
+** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
+** and will always return SQLITE_MISUSE. On those systems,
+** shared cache mode should be enabled per-database connection via
+** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
+**
** This interface is threadsafe on processors where writing a
** 32-bit integer is atomic.
**
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
- int nRef; /* NO LONGER USED */
+ int nRef; /* Number of open cursors */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
#define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_SORTER_MMAP 24
-#define SQLITE_TESTCTRL_LAST 24
+#define SQLITE_TESTCTRL_IMPOSTER 25
+#define SQLITE_TESTCTRL_LAST 25
/*
** CAPI3REF: SQLite Runtime Status
**
-** ^This interface is used to retrieve runtime status information
+** ^These interfaces are used to retrieve runtime status information
** about the performance of SQLite, and optionally to reset various
** highwater marks. ^The first argument is an integer code for
** the specific parameter to measure. ^(Recognized integer codes
** ^(Other parameters record only the highwater mark and not the current
** value. For these latter parameters nothing is written into *pCurrent.)^
**
-** ^The sqlite3_status() routine returns SQLITE_OK on success and a
-** non-zero [error code] on failure.
+** ^The sqlite3_status() and sqlite3_status64() routines return
+** SQLITE_OK on success and a non-zero [error code] on failure.
**
-** This routine is threadsafe but is not atomic. This routine can be
-** called while other threads are running the same or different SQLite
-** interfaces. However the values returned in *pCurrent and
-** *pHighwater reflect the status of SQLite at different points in time
-** and it is possible that another thread might change the parameter
-** in between the times when *pCurrent and *pHighwater are written.
+** If either the current value or the highwater mark is too large to
+** be represented by a 32-bit integer, then the values returned by
+** sqlite3_status() are undefined.
**
** See also: [sqlite3_db_status()]
*/
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+int sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+);
/*
** is not a permanent error and does not affect the return value of
** sqlite3_backup_finish().
**
-** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
+** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]]
** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b>
**
-** ^Each call to sqlite3_backup_step() sets two values inside
-** the [sqlite3_backup] object: the number of pages still to be backed
-** up and the total number of pages in the source database file.
-** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces
-** retrieve these two values, respectively.
-**
-** ^The values returned by these functions are only updated by
-** sqlite3_backup_step(). ^If the source database is modified during a backup
-** operation, then the values are not updated to account for any extra
-** pages that need to be updated or the size of the source database file
-** changing.
+** ^The sqlite3_backup_remaining() routine returns the number of pages still
+** to be backed up at the conclusion of the most recent sqlite3_backup_step().
+** ^The sqlite3_backup_pagecount() routine returns the total number of pages
+** in the source database at the conclusion of the most recent
+** sqlite3_backup_step().
+** ^(The values returned by these functions are only updated by
+** sqlite3_backup_step(). If the source database is modified in a way that
+** changes the size of the source database or the number of pages remaining,
+** those changes are not reflected in the output of sqlite3_backup_pagecount()
+** and sqlite3_backup_remaining() until after the next
+** sqlite3_backup_step().)^
**
** <b>Concurrent Usage of Database Handles</b>
**
*/
#include "msvc.h"
+/*
+** Special setup for VxWorks
+*/
+#include "vxworks.h"
+
/*
** These #defines should enable >2GB file support on POSIX if the
** underlying operating system supports it. If the OS lacks
*/
typedef INT16_TYPE LogEst;
+/*
+** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer
+*/
+#ifndef SQLITE_PTRSIZE
+# if defined(__SIZEOF_POINTER__)
+# define SQLITE_PTRSIZE __SIZEOF_POINTER__
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(_M_ARM) || defined(__arm__) || defined(__x86)
+# define SQLITE_PTRSIZE 4
+# else
+# define SQLITE_PTRSIZE 8
+# endif
+#endif
+
/*
** Macros to determine whether the machine is big or little endian,
** and whether or not that determination is run-time or compile-time.
u8 iDb; /* Which db file is being initialized */
u8 busy; /* TRUE if currently initializing */
u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */
+ u8 imposterTable; /* Building an imposter table */
} init;
int nVdbeActive; /* Number of VDBEs currently running */
int nVdbeRead; /* Number of active VDBEs that read or write */
int nVdbeWrite; /* Number of active VDBEs that read and write */
int nVdbeExec; /* Number of nested calls to VdbeExec() */
+ int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
void (*xTrace)(void*,const char*); /* Trace function */
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
-#define EP_Constant 0x080000 /* Node is a constant */
+#define EP_ConstFunc 0x080000 /* Node is a SQLITE_FUNC_CONSTANT function */
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
+#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
+
+/*
+** Combinations of two or more EP_* flags
+*/
+#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */
/*
** These macros can be used to test, set, or clear bits in the
#define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */
#define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */
#define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */
- /* 0x0080 // not currently used */
+#define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */
#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */
#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
+#define SF_Converted 0x2000 /* By convertCompoundSelectToSubquery() */
/*
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
-#define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */
+#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
+#define OPFLAG_P2ISREG 0x04 /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
/*
int sqlite3MutexEnd(void);
#endif
-int sqlite3StatusValue(int);
-void sqlite3StatusAdd(int, int);
+sqlite3_int64 sqlite3StatusValue(int);
+void sqlite3StatusUp(int, int);
+void sqlite3StatusDown(int, int);
void sqlite3StatusSet(int, int);
+/* Access to mutexes used by sqlite3_status() */
+sqlite3_mutex *sqlite3Pcache1Mutex(void);
+sqlite3_mutex *sqlite3MallocMutex(void);
+
#ifndef SQLITE_OMIT_FLOATING_POINT
int sqlite3IsNaN(double);
#else
void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
void sqlite3ExprListDelete(sqlite3*, ExprList*);
+u32 sqlite3ExprListFlags(const ExprList*);
int sqlite3Init(sqlite3*, char**);
int sqlite3InitCallback(void*, int, char**, char**);
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
-Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
+Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
Expr *sqlite3ExprSkipCollate(Expr*);
int sqlite3CheckCollSeq(Parse *, CollSeq *);
int sqlite3MemJournalSize(void);
int sqlite3IsMemJournal(sqlite3_file *);
+void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
#if SQLITE_MAX_EXPR_DEPTH>0
- void sqlite3ExprSetHeight(Parse *pParse, Expr *p);
int sqlite3SelectExprHeight(Select *);
int sqlite3ExprCheckHeight(Parse*, int);
#else
- #define sqlite3ExprSetHeight(x,y)
#define sqlite3SelectExprHeight(x) 0
#define sqlite3ExprCheckHeight(x,y)
#endif
#ifdef SQLITE_ENABLE_IOTRACE
# define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
void sqlite3VdbeIOTraceSql(Vdbe*);
-SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
+SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
#else
# define IOTRACE(A)
# define sqlite3VdbeIOTraceSql(X)
#endif
/*
-** The maximum number of in-memory pages to use for the main database
-** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
+** The suggested maximum number of in-memory pages to use for
+** the main database table and for temporary tables.
+**
+** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
+** is 2000 pages.
+** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
+** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
*/
#ifndef SQLITE_DEFAULT_CACHE_SIZE
# define SQLITE_DEFAULT_CACHE_SIZE 2000
#endif
-#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
-# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
-#endif
/*
** The default number of frames to accumulate in the log file before
*/
typedef struct sqlite3StatType sqlite3StatType;
static SQLITE_WSD struct sqlite3StatType {
- int nowValue[10]; /* Current value */
- int mxValue[10]; /* Maximum value */
+#if SQLITE_PTRSIZE>4
+ sqlite3_int64 nowValue[10]; /* Current value */
+ sqlite3_int64 mxValue[10]; /* Maximum value */
+#else
+ u32 nowValue[10]; /* Current value */
+ u32 mxValue[10]; /* Maximum value */
+#endif
} sqlite3Stat = { {0,}, {0,} };
+/*
+** Elements of sqlite3Stat[] are protected by either the memory allocator
+** mutex, or by the pcache1 mutex. The following array determines which.
+*/
+static const char statMutex[] = {
+ 0, /* SQLITE_STATUS_MEMORY_USED */
+ 1, /* SQLITE_STATUS_PAGECACHE_USED */
+ 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */
+ 0, /* SQLITE_STATUS_SCRATCH_USED */
+ 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */
+ 0, /* SQLITE_STATUS_MALLOC_SIZE */
+ 0, /* SQLITE_STATUS_PARSER_STACK */
+ 1, /* SQLITE_STATUS_PAGECACHE_SIZE */
+ 0, /* SQLITE_STATUS_SCRATCH_SIZE */
+ 0, /* SQLITE_STATUS_MALLOC_COUNT */
+};
+
/* The "wsdStat" macro will resolve to the status information
** state vector. If writable static data is unsupported on the target,
#endif
/*
-** Return the current value of a status parameter.
+** Return the current value of a status parameter. The caller must
+** be holding the appropriate mutex.
*/
-int sqlite3StatusValue(int op){
+sqlite3_int64 sqlite3StatusValue(int op){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
return wsdStat.nowValue[op];
}
/*
-** Add N to the value of a status record. It is assumed that the
-** caller holds appropriate locks.
+** Add N to the value of a status record. The caller must hold the
+** appropriate mutex. (Locking is checked by assert()).
+**
+** The StatusUp() routine can accept positive or negative values for N.
+** The value of N is added to the current status value and the high-water
+** mark is adjusted if necessary.
+**
+** The StatusDown() routine lowers the current value by N. The highwater
+** mark is unchanged. N must be non-negative for StatusDown().
*/
-void sqlite3StatusAdd(int op, int N){
+void sqlite3StatusUp(int op, int N){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
wsdStat.nowValue[op] += N;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
}
+void sqlite3StatusDown(int op, int N){
+ wsdStatInit;
+ assert( N>=0 );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
+ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ wsdStat.nowValue[op] -= N;
+}
/*
-** Set the value of a status to X.
+** Set the value of a status to X. The highwater mark is adjusted if
+** necessary. The caller must hold the appropriate mutex.
*/
void sqlite3StatusSet(int op, int X){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
wsdStat.nowValue[op] = X;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
/*
** Query status information.
-**
-** This implementation assumes that reading or writing an aligned
-** 32-bit integer is an atomic operation. If that assumption is not true,
-** then this routine is not threadsafe.
*/
-int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+int sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+){
+ sqlite3_mutex *pMutex;
wsdStatInit;
if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
return SQLITE_MISUSE_BKPT;
#ifdef SQLITE_ENABLE_API_ARMOR
if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
#endif
+ pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex();
+ sqlite3_mutex_enter(pMutex);
*pCurrent = wsdStat.nowValue[op];
*pHighwater = wsdStat.mxValue[op];
if( resetFlag ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
+ sqlite3_mutex_leave(pMutex);
+ (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */
return SQLITE_OK;
}
+int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+ sqlite3_int64 iCur, iHwtr;
+ int rc;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag);
+ if( rc==0 ){
+ *pCurrent = (int)iCur;
+ *pHighwater = (int)iHwtr;
+ }
+ return rc;
+}
/*
** Query status information for a single database connection
#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){
char zBuf[64];
- sprintf(zBuf, "%d", iArg);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iArg);
Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY);
- sprintf(zBuf, "%d", nArg);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nArg);
Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY);
}
#else
}
/*
- ** $db function NAME [-argcount N] SCRIPT
+ ** $db function NAME [-argcount N] [-deterministic] SCRIPT
**
** Create a new SQL function called NAME. Whenever that function is
** called, invoke SCRIPT to evaluate the function.
*/
case DB_FUNCTION: {
+ int flags = SQLITE_UTF8;
SqlFunc *pFunc;
Tcl_Obj *pScript;
char *zName;
int nArg = -1;
- if( objc==6 ){
- const char *z = Tcl_GetString(objv[3]);
+ int i;
+ if( objc<4 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "NAME ?SWITCHES? SCRIPT");
+ return TCL_ERROR;
+ }
+ for(i=3; i<(objc-1); i++){
+ const char *z = Tcl_GetString(objv[i]);
int n = strlen30(z);
if( n>2 && strncmp(z, "-argcount",n)==0 ){
- if( Tcl_GetIntFromObj(interp, objv[4], &nArg) ) return TCL_ERROR;
+ if( i==(objc-2) ){
+ Tcl_AppendResult(interp, "option requires an argument: ", z, 0);
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, objv[i+1], &nArg) ) return TCL_ERROR;
if( nArg<0 ){
Tcl_AppendResult(interp, "number of arguments must be non-negative",
(char*)0);
return TCL_ERROR;
}
+ i++;
+ }else
+ if( n>2 && strncmp(z, "-deterministic",n)==0 ){
+ flags |= SQLITE_DETERMINISTIC;
+ }else{
+ Tcl_AppendResult(interp, "bad option \"", z,
+ "\": must be -argcount or -deterministic", 0
+ );
+ return TCL_ERROR;
}
- pScript = objv[5];
- }else if( objc!=4 ){
- Tcl_WrongNumArgs(interp, 2, objv, "NAME [-argcount N] SCRIPT");
- return TCL_ERROR;
- }else{
- pScript = objv[3];
}
+
+ pScript = objv[objc-1];
zName = Tcl_GetStringFromObj(objv[2], 0);
pFunc = findSqlFunc(pDb, zName);
if( pFunc==0 ) return TCL_ERROR;
pFunc->pScript = pScript;
Tcl_IncrRefCount(pScript);
pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
- rc = sqlite3_create_function(pDb->db, zName, nArg, SQLITE_UTF8,
+ rc = sqlite3_create_function(pDb->db, zName, nArg, flags,
pFunc, tclSqlFunc, 0, 0);
if( rc!=SQLITE_OK ){
rc = TCL_ERROR;
for(i=j=0; i<16; i+=2){
x = digest[i]*256 + digest[i+1];
if( i>0 ) zDigest[j++] = '-';
- sprintf(&zDigest[j], "%05u", x);
+ sqlite3_snprintf(50-j, &zDigest[j], "%05u", x);
j += 5;
}
zDigest[j] = 0;
return TCL_ERROR;
}
p = (struct SqliteDb*)cmdInfo.objClientData;
- sprintf(zBuf, "%p", p->db);
- if( strncmp(zBuf,"0x",2) ){
- sprintf(zBuf, "0x%p", p->db);
- }
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p->db);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
&& sqlite3_errcode(db)!=rc ){
char zBuf[200];
int r2 = sqlite3_errcode(db);
- sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)",
+ sqlite3_snprintf(sizeof(zBuf), zBuf,
+ "error code %s (%d) does not match sqlite3_errcode %s (%d)",
t1ErrorName(rc), rc, t1ErrorName(r2), r2);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, zBuf, 0);
zSql = sqlite3_mprintf(argv[2], argv[3]);
rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr);
sqlite3_free(zSql);
- sprintf(zBuf, "%d", rc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
Tcl_AppendElement(interp, zBuf);
Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
Tcl_DStringFree(&str);
zSql[i] = 0;
Tcl_DStringInit(&str);
rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr);
- sprintf(zBuf, "%d", rc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
Tcl_AppendElement(interp, zBuf);
Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
Tcl_DStringFree(&str);
zSql[j] = 0;
rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr);
sqlite3_free(zSql);
- sprintf(zBuf, "%d", rc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
Tcl_AppendElement(interp, zBuf);
Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
Tcl_DStringFree(&str);
resCount = (nRow+1)*nCol;
}
sqlite3_free(zSql);
- sprintf(zBuf, "%d", rc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
Tcl_AppendElement(interp, zBuf);
if( rc==SQLITE_OK ){
if( argc==4 ){
- sprintf(zBuf, "%d", nRow);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nRow);
Tcl_AppendElement(interp, zBuf);
- sprintf(zBuf, "%d", nCol);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nCol);
Tcl_AppendElement(interp, zBuf);
}
for(i=0; i<resCount; i++){
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
- sprintf(zBuf, "%lld", sqlite3_last_insert_rowid(db));
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", sqlite3_last_insert_rowid(db));
Tcl_AppendResult(interp, zBuf, 0);
return SQLITE_OK;
}
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);
+ sqlite3_snprintf(sizeof(zBuf)-i*2, &zBuf[i*2], "%02x", z[i]);
}
zBuf[i*2] = 0;
sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
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);
+ sqlite3_snprintf(sizeof(zBuf)-i*4, &zBuf[i*4],"%04x", z[i]&0xff);
}
zBuf[i*4] = 0;
sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
if( rc ){
char zBuf[50];
- sprintf(zBuf, "(%d) ", rc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0);
return TCL_ERROR;
}
}
if( rc!=SQLITE_OK ){
assert( pStmt==0 );
- sprintf(zBuf, "(%d) ", rc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
}
if( rc!=SQLITE_OK ){
assert( pStmt==0 );
- sprintf(zBuf, "(%d) ", rc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
if( rc!=SQLITE_OK ){
assert( pStmt==0 );
- sprintf(zBuf, "(%d) ", rc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
- sprintf(zBuf, "%d", sqlite3_get_autocommit(db));
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3_get_autocommit(db));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
Tcl_AppendResult(interp, "PWD too big", (void*)0);
return TCL_ERROR;
}
- sprintf(proxyPath, "%s/test.proxy", zPwd);
+ sqlite3_snprintf(sizeof(proxyPath), proxyPath, "%s/test.proxy", zPwd);
rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath);
if( rc ){
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
int i;
} aVerb[] = {
{ "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT },
- { "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP },
+ { "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP },
+ { "SQLITE_TESTCTRL_IMPOSTER", SQLITE_TESTCTRL_IMPOSTER },
};
int iVerb;
int iFlag;
sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val);
break;
}
+
+ case SQLITE_TESTCTRL_IMPOSTER: {
+ int onOff, tnum;
+ const char *zDbName;
+ sqlite3 *db;
+ if( objc!=6 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "DB dbName onOff tnum");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
+ zDbName = Tcl_GetString(objv[3]);
+ if( Tcl_GetIntFromObj(interp, objv[4], &onOff) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[5], &tnum) ) return TCL_ERROR;
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zDbName, onOff, tnum);
+ break;
+ }
}
Tcl_ResetResult(interp);
memset(&r, 0, sizeof(r));
getrusage(RUSAGE_SELF, &r);
- sprintf(buf, "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d",
+ sqlite3_snprintf(sizeof(buf), buf,
+ "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d",
(int)r.ru_utime.tv_sec, (int)r.ru_utime.tv_usec,
(int)r.ru_stime.tv_sec, (int)r.ru_stime.tv_usec,
(int)r.ru_minflt, (int)r.ru_majflt
char zErr[200];
n1 = putVarint(zBuf, in);
if( n1>9 || n1<1 ){
- sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "putVarint returned %d - should be between 1 and 9", n1);
Tcl_AppendResult(interp, zErr, 0);
return TCL_ERROR;
}
n2 = getVarint(zBuf, &out);
if( n1!=n2 ){
- sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "putVarint returned %d and getVarint returned %d", n1, n2);
Tcl_AppendResult(interp, zErr, 0);
return TCL_ERROR;
}
if( in!=out ){
- sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "Wrote 0x%016llx and got back 0x%016llx", in, out);
Tcl_AppendResult(interp, zErr, 0);
return TCL_ERROR;
}
n2 = getVarint32(zBuf, out32);
out = out32;
if( n1!=n2 ){
- sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "putVarint returned %d and GetVarint32 returned %d",
n1, n2);
Tcl_AppendResult(interp, zErr, 0);
return TCL_ERROR;
}
if( in!=out ){
- sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
in, out);
Tcl_AppendResult(interp, zErr, 0);
return TCL_ERROR;
return TCL_ERROR;
}
thread_wait(&threadset[i]);
- sprintf(zBuf, "%d", threadset[i].argc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
return TCL_ERROR;
}
client_wait(&threadset[i]);
- sprintf(zBuf, "%d", threadset[i].argc);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
zSpace = (char *)(&aCol[nCol]);
for(ii=0; ii<nCol; ii++){
aCol[ii] = zSpace;
- zSpace += sprintf(zSpace, "%s", sqlite3_column_name(pStmt, ii));
- zSpace++;
+ sqlite3_snprintf(nBytes, zSpace, "%s", sqlite3_column_name(pStmt,ii));
+ zSpace += (int)strlen(zSpace) + 1;
}
assert( (zSpace-nBytes)==(char *)aCol );
}
*/
#include "tcl.h"
-#include <sqlite3.h>
+#include "sqlite3.h"
#include <assert.h>
/* These functions are implemented in main.c. */
LINKVAR( MAX_PAGE_COUNT );
LINKVAR( MAX_LIKE_PATTERN_LENGTH );
LINKVAR( MAX_TRIGGER_DEPTH );
- LINKVAR( DEFAULT_TEMP_CACHE_SIZE );
LINKVAR( DEFAULT_CACHE_SIZE );
LINKVAR( DEFAULT_PAGE_SIZE );
LINKVAR( DEFAULT_FILE_FORMAT );
#if !defined(SQLITE_TEST) || SQLITE_OS_UNIX
-#include <sqlite3.h>
+#include "sqlite3.h"
#include <assert.h>
#include <string.h>
Tcl_DecrRefCount(pRet);
}
+/*
+** The implementation of scalar SQL function "test_zeroblob()". This is
+** similar to the built-in zeroblob() function, except that it does not
+** check that the integer parameter is within range before passing it
+** to sqlite3_result_zeroblob().
+*/
+static void test_zeroblob(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int nZero = sqlite3_value_int(argv[0]);
+ sqlite3_result_zeroblob(context, nZero);
+}
static int registerTestFunctions(sqlite3 *db){
static const struct {
char *zName;
signed char nArg;
- unsigned char eTextRep; /* 1: UTF-16. 0: UTF-8 */
+ unsigned int eTextRep; /* 1: UTF-16. 0: UTF-8 */
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = {
{ "randstr", 2, SQLITE_UTF8, randStr },
{ "real2hex", 1, SQLITE_UTF8, real2hex},
{ "test_decode", 1, SQLITE_UTF8, test_decode},
{ "test_extract", 2, SQLITE_UTF8, test_extract},
+ { "test_zeroblob", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, test_zeroblob},
};
int i;
rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
if( rc==SQLITE_OK && zName ){
int bExists;
+ if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
+ pGroup->bEnabled = 0;
+ }else
if( sz==0 ){
if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
/* If opening a main journal file and the first chunk is zero
break;
case SQLITE_FCNTL_PRAGMA: {
char **aFcntl = (char**)pArg;
+ /*
+ ** EVIDENCE-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA
+ ** file control is an array of pointers to strings (char**) in which the
+ ** second element of the array is the name of the pragma and the third
+ ** element is the argument to the pragma or NULL if the pragma has no
+ ** argument.
+ */
if( aFcntl[1] && sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){
if( aFcntl[2] && aFcntl[2][0] ){
if( sqlite3_stricmp(aFcntl[2], "on")==0
pGroup->bTruncate = 0;
}
}
+ /* EVIDENCE-OF: R-27806-26076 The handler for an SQLITE_FCNTL_PRAGMA
+ ** file control can optionally make the first element of the char**
+ ** argument point to a string obtained from sqlite3_mprintf() or the
+ ** equivalent and that string will become the result of the pragma
+ ** or the error message if the pragma fails.
+ */
aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off");
rc = SQLITE_OK;
break;
** is not included in the SQLite library.
*/
-#include <sqlite3.h>
+#include "sqlite3.h"
#include <tcl.h>
/* Solely for the UNUSED_PARAMETER() macro. */
FILE *fd;
char *zVar = getenv(ENVIRONMENT_VARIABLE1_NAME);
if( zVar==0 || strlen(zVar)+10>=(sizeof(sqllogglobal.zPrefix)) ) return;
- sprintf(sqllogglobal.zPrefix, "%s/sqllog_%d", zVar, getProcessId());
- sprintf(sqllogglobal.zIdx, "%s.idx", sqllogglobal.zPrefix);
+ sqlite3_snprintf(sizeof(sqllogglobal.zPrefix), sqllogglobal.zPrefix,
+ "%s/sqllog_%d", zVar, getProcessId());
+ sqlite3_snprintf(sizeof(sqllogglobal.zIdx), sqllogglobal.zIdx,
+ "%s.idx", sqllogglobal.zPrefix);
if( getenv(ENVIRONMENT_VARIABLE2_NAME) ){
sqllogglobal.bReuse = atoi(getenv(ENVIRONMENT_VARIABLE2_NAME));
}
if( p->nCell ){
int i; /* Used to iterate through cells */
- int nUsable = szPage - sqlite3BtreeGetReserve(pBt);
+ int nUsable; /* Usable bytes per page */
+ sqlite3BtreeEnter(pBt);
+ nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
+ sqlite3BtreeLeave(pBt);
p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell));
memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
while( p->iCell<p->nCell ){
StatCell *pCell = &p->aCell[p->iCell];
if( pCell->iOvfl<pCell->nOvfl ){
- int nUsable = sqlite3BtreeGetPageSize(pBt)-sqlite3BtreeGetReserve(pBt);
+ int nUsable;
+ sqlite3BtreeEnter(pBt);
+ nUsable = sqlite3BtreeGetPageSize(pBt) -
+ sqlite3BtreeGetReserveNoMutex(pBt);
+ sqlite3BtreeLeave(pBt);
pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
pCsr->zPagetype = "overflow";
** sqlite3demo_superunlock()
*/
-#include <sqlite3.h>
+#include "sqlite3.h"
#include <string.h> /* memset(), strlen() */
#include <assert.h> /* assert() */
}
if( rc!=SQLITE_OK ){
assert( pStmt==0 );
- sprintf(zBuf, "%s ", (char *)sqlite3ErrName(rc));
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%s ", (char *)sqlite3ErrName(rc));
Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break;
}
if( !pBuffer ){
- int nByte = sizeof(TestvfsBuffer) + (int)strlen(pFd->zFilename) + 1;
+ int szName = (int)strlen(pFd->zFilename);
+ int nByte = sizeof(TestvfsBuffer) + szName + 1;
pBuffer = (TestvfsBuffer *)ckalloc(nByte);
memset(pBuffer, 0, nByte);
pBuffer->zFile = (char *)&pBuffer[1];
- strcpy(pBuffer->zFile, pFd->zFilename);
+ memcpy(pBuffer->zFile, pFd->zFilename, szName+1);
pBuffer->pNext = p->pBuffer;
p->pBuffer = pBuffer;
}
TestvfsFd *pFd = tvfsGetFd(pFile);
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
+ if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
+ const char *z = pFd->pShm ? pFd->pShm->zFile : "";
+ tvfsExecTcl(p, "xShmBarrier", Tcl_NewStringObj(z, -1), pFd->pShmId, 0, 0);
+ }
+
if( p->isFullshm ){
sqlite3OsShmBarrier(pFd->pReal);
return;
}
-
- if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
- tvfsExecTcl(p, "xShmBarrier",
- Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0
- );
- }
}
static int tvfsShmUnmap(
return TCL_OK;
bad_args:
- Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?");
+ Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-fullshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?");
return TCL_ERROR;
}
/********************************* Win32 Threads ****************************/
-#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
+#if SQLITE_OS_WIN_THREADS
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
#include <process.h>
return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
}
-#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */
+#endif /* SQLITE_OS_WIN_THREADS */
/******************************** End Win32 Threads *************************/
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
-
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( zSql==0 || pzErrMsg==0 ) return SQLITE_MISUSE_BKPT;
-#endif
+ assert( zSql!=0 );
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
if( db->nVdbeActive==0 ){
db->u1.isInterrupted = 0;
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
#ifdef YYTRACKMAXSTACKDEPTH
+ sqlite3_mutex_enter(sqlite3MallocMutex());
sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
sqlite3ParserStackPeak(pEngine)
);
+ sqlite3_mutex_leave(sqlite3MallocMutex());
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
db->lookaside.bEnabled = enableLookaside;
** cause problems for the call to BtreeSetPageSize() below. */
sqlite3BtreeCommit(pTemp);
- nRes = sqlite3BtreeGetReserve(pMain);
+ nRes = sqlite3BtreeGetOptimalReserve(pMain);
/* A VACUUM cannot change the pagesize of an encrypted database. */
#ifdef SQLITE_HAS_CODEC
** Synopsis: r[P2]='P4'
**
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
-** into a String before it is executed for the first time. During
+** into a String opcode before it is executed for the first time. During
** this transformation, the length of string P4 is computed and stored
** as the P1 parameter.
*/
/* Fall through to the next case, OP_String */
}
-/* Opcode: String P1 P2 * P4 *
+/* Opcode: String P1 P2 P3 P4 P5
** Synopsis: r[P2]='P4' (len=P1)
**
** The string value P4 of length P1 (bytes) is stored in register P2.
+**
+** If P5!=0 and the content of register P3 is greater than zero, then
+** the datatype of the register P2 is converted to BLOB. The content is
+** the same sequence of bytes, it is merely interpreted as a BLOB instead
+** of a string, as if it had been CAST.
*/
case OP_String: { /* out2-prerelease */
assert( pOp->p4.z!=0 );
pOut->n = pOp->p1;
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
+ if( pOp->p5 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=(p->nMem-p->nCursor) );
+ pIn3 = &aMem[pOp->p3];
+ assert( pIn3->flags & MEM_Int );
+ if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
+ }
break;
}
**
** The interface used by the implementation of the aforementioned functions
** to retrieve the collation sequence set by this opcode is not available
-** publicly, only to user functions defined in func.c.
+** publicly. Only built-in functions have access to this feature.
*/
case OP_CollSeq: {
assert( pOp->p4type==P4_COLLSEQ );
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
sqlite3VdbeMemStringify(pIn1, encoding, 1);
+ testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
+ flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
}
if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_Real );
sqlite3VdbeMemStringify(pIn3, encoding, 1);
+ testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) );
+ flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
}
}
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
}
}
/* Undo any changes made by applyAffinity() to the input registers. */
+ assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
pIn1->flags = flags1;
+ assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
pIn3->flags = flags3;
break;
}
p->nStmtDefImmCons = db->nDeferredImmCons;
}
- /* Gather the schema version number for checking */
+ /* Gather the schema version number for checking:
+ ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite
+ ** each time a query is executed to ensure that the internal cache of the
+ ** schema used when compiling the SQL query matches the schema of the
+ ** database against which the compiled query is actually executed.
+ */
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
}else{
** See also OpenRead.
*/
case OP_ReopenIdx: {
+ int nField;
+ KeyInfo *pKeyInfo;
+ int p2;
+ int iDb;
+ int wrFlag;
+ Btree *pX;
VdbeCursor *pCur;
+ Db *pDb;
- assert( pOp->p5==0 );
+ assert( pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
assert( pOp->p4type==P4_KEYINFO );
pCur = p->apCsr[pOp->p1];
if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){
assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */
- break;
+ goto open_cursor_set_hints;
}
/* If the cursor is not currently open or is open on a different
** index, then fall through into OP_OpenRead to force a reopen */
-}
case OP_OpenRead:
-case OP_OpenWrite: {
- int nField;
- KeyInfo *pKeyInfo;
- int p2;
- int iDb;
- int wrFlag;
- Btree *pX;
- VdbeCursor *pCur;
- Db *pDb;
+case OP_OpenWrite:
- assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
- assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
+ assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR|OPFLAG_SEEKEQ))==pOp->p5 );
+ assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
assert( p->bIsReader );
assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
|| p->readOnly==0 );
pCur->pgnoRoot = p2;
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
pCur->pKeyInfo = pKeyInfo;
- assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
- sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR));
-
/* Set the VdbeCursor.isTable variable. Previous versions of
** SQLite used to check if the root-page flags were sane at this point
** and report database corruption if they were not, but this check has
** since moved into the btree layer. */
pCur->isTable = pOp->p4type!=P4_KEYINFO;
+
+open_cursor_set_hints:
+ assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
+ assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
+ sqlite3BtreeCursorHints(pCur->pCursor,
+ (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
break;
}
#ifdef SQLITE_DEBUG
pC->seekOp = pOp->opcode;
#endif
+
+ /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
+ ** OP_SeekLE opcodes are allowed, and these must be immediately followed
+ ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
+ */
+#ifdef SQLITE_DEBUG
+ if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){
+ assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
+ assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
+ assert( pOp[1].p1==pOp[0].p1 );
+ assert( pOp[1].p2==pOp[0].p2 );
+ assert( pOp[1].p3==pOp[0].p3 );
+ assert( pOp[1].p4.i==pOp[0].p4.i );
+ }
+#endif
+
if( pC->isTable ){
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
*/
case OP_Destroy: { /* out2-prerelease */
int iMoved;
- int iCnt;
- Vdbe *pVdbe;
int iDb;
assert( p->readOnly==0 );
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- iCnt = 0;
- for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){
- if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->bIsReader
- && pVdbe->inVtabMethod<2 && pVdbe->pc>=0
- ){
- iCnt++;
- }
- }
-#else
- iCnt = db->nVdbeRead;
-#endif
pOut->flags = MEM_Null;
- if( iCnt>1 ){
+ if( db->nVdbeRead > db->nVDestroy+1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
iDb = pOp->p3;
- assert( iCnt==1 );
assert( DbMaskTest(p->btreeMask, iDb) );
iMoved = 0; /* Not needed. Only to silence a warning. */
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
/* Opcode: IfPos P1 P2 * * *
** Synopsis: if r[P1]>0 goto P2
**
-** If the value of register P1 is 1 or greater, jump to P2.
+** Register P1 must contain an integer.
+** If the value of register P1 is 1 or greater, jump to P2 and
+** add the literal value P3 to register P1.
**
-** It is illegal to use this instruction on a register that does
-** not contain an integer. An assertion fault will result if you try.
+** If the initial value of register P1 is less than 1, then the
+** value is unchanged and control passes through to the next instruction.
*/
case OP_IfPos: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
break;
}
-/* Opcode: IfZero P1 P2 P3 * *
-** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2
+/* Opcode: IfNotZero P1 P2 P3 * *
+** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2
**
-** The register P1 must contain an integer. Add literal P3 to the
-** value in register P1. If the result is exactly 0, jump to P2.
+** Register P1 must contain an integer. If the content of register P1 is
+** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is
+** initially zero, leave it unchanged and fall through.
*/
-case OP_IfZero: { /* jump, in1 */
+case OP_IfNotZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
- pIn1->u.i += pOp->p3;
+ VdbeBranchTaken(pIn1->u.i<0, 2);
+ if( pIn1->u.i ){
+ pIn1->u.i += pOp->p3;
+ pc = pOp->p2 - 1;
+ }
+ break;
+}
+
+/* Opcode: DecrJumpZero P1 P2 * * *
+** Synopsis: if (--r[P1])==0 goto P2
+**
+** Register P1 must hold an integer. Decrement the value in register P1
+** then jump to P2 if the new value is exactly zero.
+*/
+case OP_DecrJumpZero: { /* jump, in1 */
+ pIn1 = &aMem[pOp->p1];
+ assert( pIn1->flags&MEM_Int );
+ pIn1->u.i--;
VdbeBranchTaken(pIn1->u.i==0, 2);
if( pIn1->u.i==0 ){
pc = pOp->p2 - 1;
break;
}
+
+/* Opcode: JumpZeroIncr P1 P2 * * *
+** Synopsis: if (r[P1]++)==0 ) goto P2
+**
+** The register P1 must contain an integer. If register P1 is initially
+** zero, then jump to P2. Increment register P1 regardless of whether or
+** not the jump is taken.
+*/
+case OP_JumpZeroIncr: { /* jump, in1 */
+ pIn1 = &aMem[pOp->p1];
+ assert( pIn1->flags&MEM_Int );
+ VdbeBranchTaken(pIn1->u.i==0, 2);
+ if( (pIn1->u.i++)==0 ){
+ pc = pOp->p2 - 1;
+ }
+ break;
+}
+
/* Opcode: AggStep * P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VCreate P1 * * P4 *
+/* Opcode: VCreate P1 P2 * * *
**
-** P4 is the name of a virtual table in database P1. Call the xCreate method
-** for that table.
+** P2 is a register that holds the name of a virtual table in database
+** P1. Call the xCreate method for that table.
*/
case OP_VCreate: {
- rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p4.z, &p->zErrMsg);
+ Mem sMem; /* For storing the record being decoded */
+ const char *zTab; /* Name of the virtual table */
+
+ memset(&sMem, 0, sizeof(sMem));
+ sMem.db = db;
+ /* Because P2 is always a static string, it is impossible for the
+ ** sqlite3VdbeMemCopy() to fail */
+ assert( (aMem[pOp->p2].flags & MEM_Str)!=0 );
+ assert( (aMem[pOp->p2].flags & MEM_Static)!=0 );
+ rc = sqlite3VdbeMemCopy(&sMem, &aMem[pOp->p2]);
+ assert( rc==SQLITE_OK );
+ zTab = (const char*)sqlite3_value_text(&sMem);
+ assert( zTab || db->mallocFailed );
+ if( zTab ){
+ rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg);
+ }
+ sqlite3VdbeMemRelease(&sMem);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
** of that table.
*/
case OP_VDestroy: {
- p->inVtabMethod = 2;
+ db->nVDestroy++;
rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
- p->inVtabMethod = 0;
+ db->nVDestroy--;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
- sqlite3_module *pModule;
+ const sqlite3_module *pModule;
assert( p->bIsReader );
pCur = 0;
pVtabCursor = 0;
pVtab = pOp->p4.pVtab->pVtab;
- pModule = (sqlite3_module *)pVtab->pModule;
- assert(pVtab && pModule);
+ if( pVtab==0 || NEVER(pVtab->pModule==0) ){
+ rc = SQLITE_LOCKED;
+ break;
+ }
+ pModule = pVtab->pModule;
rc = pModule->xOpen(pVtab, &pVtabCursor);
sqlite3VtabImportErrmsg(p, pVtab);
if( SQLITE_OK==rc ){
pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
if( pCur ){
pCur->pVtabCursor = pVtabCursor;
+ pVtab->nRef++;
}else{
db->mallocFailed = 1;
pModule->xClose(pVtabCursor);
apArg[i] = &pArgc[i+1];
}
- p->inVtabMethod = 1;
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
- p->inVtabMethod = 0;
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pVtabCursor);
** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor.
*/
- p->inVtabMethod = 1;
rc = pModule->xNext(pCur->pVtabCursor);
- p->inVtabMethod = 0;
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
*/
case OP_VUpdate: {
sqlite3_vtab *pVtab;
- sqlite3_module *pModule;
+ const sqlite3_module *pModule;
int nArg;
int i;
sqlite_int64 rowid;
);
assert( p->readOnly==0 );
pVtab = pOp->p4.pVtab->pVtab;
- pModule = (sqlite3_module *)pVtab->pModule;
+ if( pVtab==0 || NEVER(pVtab->pModule==0) ){
+ rc = SQLITE_LOCKED;
+ break;
+ }
+ pModule = pVtab->pModule;
nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
if( ALWAYS(pModule->xUpdate) ){
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
** is really a pointer to an instance of this structure.
-**
-** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
-** any virtual table method invocations made by the vdbe program. It is
-** set to 2 for xDestroy method calls and 1 for all other methods. This
-** variable is used for two purposes: to allow xDestroy methods to execute
-** "DROP TABLE" statements and to prevent some nasty side effects of
-** malloc failure when SQLite is invoked recursively by a virtual table
-** method function.
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
u32 cacheCtr; /* VdbeCursor row cache generation counter */
int pc; /* The program counter */
int rc; /* Value to return */
+#ifdef SQLITE_DEBUG
+ int rcApp; /* errcode set by sqlite3_result_error_code() */
+#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
bft explain:2; /* True if EXPLAIN present on SQL command */
- bft inVtabMethod:2; /* See comments above */
bft changeCntOn:1; /* True to update the change-counter */
bft expired:1; /* True if the VM needs to be recompiled */
bft runOnlyOnce:1; /* Automatically expire on reset */
return sqlite3ValueText(pVal, SQLITE_UTF16LE);
}
#endif /* SQLITE_OMIT_UTF16 */
+/* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five
+** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating
+** point number string BLOB NULL
+*/
int sqlite3_value_type(sqlite3_value* pVal){
static const u8 aType[] = {
SQLITE_BLOB, /* 0x00 */
void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode;
pCtx->fErrorOrAux = 1;
+#ifdef SQLITE_DEBUG
+ if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
+#endif
if( pCtx->pOut->flags & MEM_Null ){
sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
SQLITE_UTF8, SQLITE_STATIC);
** or SQLITE_BUSY error.
*/
#ifdef SQLITE_OMIT_AUTORESET
- if( p->rc==SQLITE_BUSY || p->rc==SQLITE_LOCKED ){
+ if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
sqlite3_reset((sqlite3_stmt*)p);
}else{
return SQLITE_MISUSE_BKPT;
if( p->bIsReader ) db->nVdbeRead++;
p->pc = 0;
}
+#ifdef SQLITE_DEBUG
+ p->rcApp = SQLITE_OK;
+#endif
#ifndef SQLITE_OMIT_EXPLAIN
if( p->explain ){
rc = sqlite3VdbeList(p);
assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| rc==SQLITE_BUSY || rc==SQLITE_MISUSE
);
- assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE );
+ assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
/* If this statement was prepared using sqlite3_prepare_v2(), and an
** error has occurred, then return the error code in p->rc to the
}
/*
-** Return the current time for a statement
+** Return the current time for a statement. If the current time
+** is requested more than once within the same run of a single prepared
+** statement, the exact same time is returned for each invocation regardless
+** of the amount of time that elapses between invocations. In other words,
+** the time returned is always the time of the first call.
*/
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
- Vdbe *v = p->pVdbe;
int rc;
- if( v->iCurrentTime==0 ){
- rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &v->iCurrentTime);
- if( rc ) v->iCurrentTime = 0;
+#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
+ sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime;
+ assert( p->pVdbe!=0 );
+#else
+ sqlite3_int64 iTime = 0;
+ sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime;
+#endif
+ if( *piTime==0 ){
+ rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime);
+ if( rc ) *piTime = 0;
}
- return v->iCurrentTime;
+ return *piTime;
}
/*
AuxData *pAuxData;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+#if SQLITE_ENABLE_STAT3_OR_STAT4
+ if( pCtx->pVdbe==0 ) return 0;
+#else
+ assert( pCtx->pVdbe!=0 );
+#endif
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
}
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
if( iArg<0 ) goto failed;
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ if( pVdbe==0 ) goto failed;
+#else
+ assert( pVdbe!=0 );
+#endif
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
#ifndef SQLITE_OMIT_VIRTUALTABLE
case P4_VTAB: {
sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
- sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
+ sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab);
break;
}
#endif
else if( pCx->pVtabCursor ){
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
- p->inVtabMethod = 1;
+ assert( pVtabCursor->pVtab->nRef>0 );
+ pVtabCursor->pVtab->nRef--;
pModule->xClose(pVtabCursor);
- p->inVtabMethod = 0;
}
#endif
}
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(pVfs, zMaster, 1);
+ rc = sqlite3OsDelete(pVfs, zMaster, needSync);
sqlite3DbFree(db, zMaster);
zMaster = 0;
if( rc ){
if( CORRUPT_DB ) return;
idx = getVarint32(aKey, szHdr);
- assert( szHdr<=nKey );
+ assert( nKey>=0 );
+ assert( szHdr<=(u32)nKey );
while( idx<szHdr ){
idx += getVarint32(aKey+idx, notUsed);
nField++;
Incrblob *pBlob = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) || ppBlob==0 || zTable==0 ){
+ if( ppBlob==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
- flags = !!flags; /* flags = (flags ? 1 : 0); */
*ppBlob = 0;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ flags = !!flags; /* flags = (flags ? 1 : 0); */
sqlite3_mutex_enter(db->mutex);
sqlite3_mutex_enter(db->mutex);
v = (Vdbe*)p->pStmt;
- if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){
+ if( n<0 || iOffset<0 || ((sqlite3_int64)iOffset+n)>p->nByte ){
/* Request is out of range. Return a transient error. */
rc = SQLITE_ERROR;
}else if( v==0 ){
** Otherwise, if the second argument is non-zero, then this function is
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
** already been allocated, allocate the UnpackedRecord structure that
-** that function will return to its caller here. Then return a pointer
+** that function will return to its caller here. Then return a pointer to
** an sqlite3_value within the UnpackedRecord.a[] array.
*/
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
return sqlite3ValueNew(db);
}
+/*
+** The expression object indicated by the second argument is guaranteed
+** to be a scalar SQL function. If
+**
+** * all function arguments are SQL literals,
+** * the SQLITE_FUNC_CONSTANT function flag is set, and
+** * the SQLITE_FUNC_NEEDCOLL function flag is not set,
+**
+** then this routine attempts to invoke the SQL function. Assuming no
+** error occurs, output parameter (*ppVal) is set to point to a value
+** object containing the result before returning SQLITE_OK.
+**
+** Affinity aff is applied to the result of the function before returning.
+** If the result is a text value, the sqlite3_value object uses encoding
+** enc.
+**
+** If the conditions above are not met, this function returns SQLITE_OK
+** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to
+** NULL and an SQLite error code returned.
+*/
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+static int valueFromFunction(
+ sqlite3 *db, /* The database connection */
+ Expr *p, /* The expression to evaluate */
+ u8 enc, /* Encoding to use */
+ u8 aff, /* Affinity to use */
+ sqlite3_value **ppVal, /* Write the new value here */
+ struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */
+){
+ sqlite3_context ctx; /* Context object for function invocation */
+ sqlite3_value **apVal = 0; /* Function arguments */
+ int nVal = 0; /* Size of apVal[] array */
+ FuncDef *pFunc = 0; /* Function definition */
+ sqlite3_value *pVal = 0; /* New value */
+ int rc = SQLITE_OK; /* Return code */
+ int nName; /* Size of function name in bytes */
+ ExprList *pList = 0; /* Function arguments */
+ int i; /* Iterator variable */
+
+ assert( pCtx!=0 );
+ assert( (p->flags & EP_TokenOnly)==0 );
+ pList = p->x.pList;
+ if( pList ) nVal = pList->nExpr;
+ nName = sqlite3Strlen30(p->u.zToken);
+ pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
+ assert( pFunc );
+ if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0
+ || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ ){
+ return SQLITE_OK;
+ }
+
+ if( pList ){
+ apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal);
+ if( apVal==0 ){
+ rc = SQLITE_NOMEM;
+ goto value_from_function_out;
+ }
+ for(i=0; i<nVal; i++){
+ rc = sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]);
+ if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
+ }
+ }
+
+ pVal = valueNew(db, pCtx);
+ if( pVal==0 ){
+ rc = SQLITE_NOMEM;
+ goto value_from_function_out;
+ }
+
+ assert( pCtx->pParse->rc==SQLITE_OK );
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.pOut = pVal;
+ ctx.pFunc = pFunc;
+ pFunc->xFunc(&ctx, nVal, apVal);
+ if( ctx.isError ){
+ rc = ctx.isError;
+ sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
+ }else{
+ sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
+ assert( rc==SQLITE_OK );
+ rc = sqlite3VdbeChangeEncoding(pVal, enc);
+ if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
+ rc = SQLITE_TOOBIG;
+ pCtx->pParse->nErr++;
+ }
+ }
+ pCtx->pParse->rc = rc;
+
+ value_from_function_out:
+ if( rc!=SQLITE_OK ){
+ pVal = 0;
+ }
+ if( apVal ){
+ for(i=0; i<nVal; i++){
+ sqlite3ValueFree(apVal[i]);
+ }
+ sqlite3DbFree(db, apVal);
+ }
+
+ *ppVal = pVal;
+ return rc;
+}
+#else
+# define valueFromFunction(a,b,c,d,e,f) SQLITE_OK
+#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
+
/*
** Extract a value from the supplied expression in the manner described
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
+ /* Compressed expressions only appear when parsing the DEFAULT clause
+ ** on a table column definition, and hence only when pCtx==0. This
+ ** check ensures that an EP_TokenOnly expression is never passed down
+ ** into valueFromFunction(). */
+ assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 );
+
if( op==TK_CAST ){
u8 aff = sqlite3AffinityType(pExpr->u.zToken,0);
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
}
#endif
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ else if( op==TK_FUNCTION && pCtx!=0 ){
+ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
+ }
+#endif
+
*ppVal = pVal;
return rc;
sqlite3_file **ppFd
){
int rc;
+ if( sqlite3FaultSim(202) ) return SQLITE_IOERR_ACCESS;
rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd,
SQLITE_OPEN_TEMP_JOURNAL |
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
char *zStmt;
char *zWhere;
int iDb;
+ int iReg;
Vdbe *v;
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
- sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
- pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
+
+ iReg = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, iReg, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
}
/* If we are rereading the sqlite_master table create the in-memory
char *zErr = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+ if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
#endif
sqlite3_mutex_enter(db->mutex);
if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
- VTable *p = vtabDisconnectAll(db, pTab);
-
- assert( rc==SQLITE_OK );
+ VTable *p;
+ for(p=pTab->pVTable; p; p=p->pNext){
+ assert( p->pVtab );
+ if( p->pVtab->nRef>0 ){
+ return SQLITE_LOCKED;
+ }
+ }
+ p = vtabDisconnectAll(db, pTab);
rc = p->pMod->pModule->xDestroy(p->pVtab);
-
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
if( rc==SQLITE_OK ){
assert( pTab->pVTable==p && p->pNext==0 );
--- /dev/null
+/*
+** 2015-03-02
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains code that is specific to Wind River's VxWorks
+*/
+#if defined(__RTP__) || defined(_WRS_KERNEL)
+/* This is VxWorks. Set up things specially for that OS
+*/
+#include <vxWorks.h>
+#include <pthread.h> /* amalgamator: dontcache */
+#define OS_VXWORKS 1
+#define SQLITE_OS_OTHER 0
+#define SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1
+#define SQLITE_OMIT_LOAD_EXTENSION 1
+#define SQLITE_ENABLE_LOCKING_STYLE 0
+#define HAVE_UTIME 1
+#else
+/* This is not VxWorks. */
+#define OS_VXWORKS 0
+#endif /* defined(_WRS_KERNEL) */
SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
}
-static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){
int rc;
if( pWal->exclusiveMode ) return SQLITE_OK;
+ if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0);
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
assert( pWal->writeLock );
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
nLock = SQLITE_SHM_NLOCK - iLock;
- rc = walLockExclusive(pWal, iLock, nLock);
+ rc = walLockExclusive(pWal, iLock, nLock, 0);
if( rc ){
return rc;
}
){
int rc;
do {
- rc = walLockExclusive(pWal, lockIdx, n);
+ rc = walLockExclusive(pWal, lockIdx, n, 0);
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
return rc;
}
walUnlockShared(pWal, WAL_WRITE_LOCK);
rc = SQLITE_READONLY_RECOVERY;
}
- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+ }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){
pWal->writeLock = 1;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
&& (mxReadMark<pWal->hdr.mxFrame || mxI==0)
){
for(i=1; i<WAL_NREADER; i++){
- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1, 0);
if( rc==SQLITE_OK ){
mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
mxI = i;
/* Only one writer allowed at a time. Get the write lock. Return
** SQLITE_BUSY if unable.
*/
- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0);
if( rc ){
return rc;
}
if( pInfo->nBackfill>0 ){
u32 salt1;
sqlite3_randomness(4, &salt1);
- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0);
if( rc==SQLITE_OK ){
/* If all readers are using WAL_READ_LOCK(0) (in other words if no
** readers are currently using the WAL), then the transactions
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
** "checkpoint" lock on the database file. */
- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0);
if( rc ){
/* EVIDENCE-OF: R-10421-19736 If any other process is running a
** checkpoint operation at the same time, the lock cannot be obtained and
** calling this routine. Such pointers may be reinitialized by referencing
** the pWC->a[] array.
*/
-static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
+static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
WhereTerm *pTerm;
int idx;
testcase( wtFlags & TERM_VIRTUAL );
** so and false if not.
**
** In order for the operator to be optimizible, the RHS must be a string
-** literal that does not begin with a wildcard.
+** literal that does not begin with a wildcard. The LHS must be a column
+** that may only be NULL, a string, or a BLOB, never a number. (This means
+** that virtual tables cannot participate in the LIKE optimization.) If the
+** collating sequence for the column on the LHS must be appropriate for
+** the operator.
*/
static int isLikeOrGlob(
Parse *pParse, /* Parsing and code generating context */
pLeft = pList->a[1].pExpr;
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
- || IsVirtual(pLeft->pTab)
+ || IsVirtual(pLeft->pTab) /* Value might be numeric */
){
/* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
** be the name of an indexed column with TEXT affinity. */
pWC->a[iParent].nChild++;
}
+/*
+** Return the N-th AND-connected subterm of pTerm. Or if pTerm is not
+** a conjunction, then return just pTerm when N==0. If N is exceeds
+** the number of available subterms, return NULL.
+*/
+static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){
+ if( pTerm->eOperator!=WO_AND ){
+ return N==0 ? pTerm : 0;
+ }
+ if( N<pTerm->u.pAndInfo->wc.nTerm ){
+ return &pTerm->u.pAndInfo->wc.a[N];
+ }
+ return 0;
+}
+
+/*
+** Subterms pOne and pTwo are contained within WHERE clause pWC. The
+** two subterms are in disjunction - they are OR-ed together.
+**
+** If these two terms are both of the form: "A op B" with the same
+** A and B values but different operators and if the operators are
+** compatible (if one is = and the other is <, for example) then
+** add a new virtual AND term to pWC that is the combination of the
+** two.
+**
+** Some examples:
+**
+** x<y OR x=y --> x<=y
+** x=y OR x=y --> x=y
+** x<=y OR x<y --> x<=y
+**
+** The following is NOT generated:
+**
+** x<y OR x>y --> x!=y
+*/
+static void whereCombineDisjuncts(
+ SrcList *pSrc, /* the FROM clause */
+ WhereClause *pWC, /* The complete WHERE clause */
+ WhereTerm *pOne, /* First disjunct */
+ WhereTerm *pTwo /* Second disjunct */
+){
+ u16 eOp = pOne->eOperator | pTwo->eOperator;
+ sqlite3 *db; /* Database connection (for malloc) */
+ Expr *pNew; /* New virtual expression */
+ int op; /* Operator for the combined expression */
+ int idxNew; /* Index in pWC of the next virtual term */
+
+ if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
+ if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
+ if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp
+ && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return;
+ assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 );
+ assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 );
+ if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
+ if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return;
+ /* If we reach this point, it means the two subterms can be combined */
+ if( (eOp & (eOp-1))!=0 ){
+ if( eOp & (WO_LT|WO_LE) ){
+ eOp = WO_LE;
+ }else{
+ assert( eOp & (WO_GT|WO_GE) );
+ eOp = WO_GE;
+ }
+ }
+ db = pWC->pWInfo->pParse->db;
+ pNew = sqlite3ExprDup(db, pOne->pExpr, 0);
+ if( pNew==0 ) return;
+ for(op=TK_EQ; eOp!=(WO_EQ<<(op-TK_EQ)); op++){ assert( op<TK_GE ); }
+ pNew->op = op;
+ idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
+ exprAnalyze(pSrc, pWC, idxNew);
+}
+
#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
/*
** Analyze a term that consists of two or more OR-connected
** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15)
** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*')
** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6)
+** (F) x>A OR (x=A AND y>=B)
**
** CASE 1:
**
**
** CASE 2:
**
+** If there are exactly two disjuncts one side has x>A and the other side
+** has x=A (for the same x and A) then add a new virtual conjunct term to the
+** WHERE clause of the form "x>=A". Example:
+**
+** x>A OR (x=A AND y>B) adds: x>=A
+**
+** The added conjunct can sometimes be helpful in query planning.
+**
+** CASE 3:
+**
** If all subterms are indexable by a single table T, then set
**
** WhereTerm.eOperator = WO_OR
}
/*
- ** Record the set of tables that satisfy case 2. The set might be
+ ** Record the set of tables that satisfy case 3. The set might be
** empty.
*/
pOrInfo->indexable = indexable;
pTerm->eOperator = indexable==0 ? 0 : WO_OR;
+ /* For a two-way OR, attempt to implementation case 2.
+ */
+ if( indexable && pOrWc->nTerm==2 ){
+ int iOne = 0;
+ WhereTerm *pOne;
+ while( (pOne = whereNthSubterm(&pOrWc->a[0],iOne++))!=0 ){
+ int iTwo = 0;
+ WhereTerm *pTwo;
+ while( (pTwo = whereNthSubterm(&pOrWc->a[1],iTwo++))!=0 ){
+ whereCombineDisjuncts(pSrc, pWC, pOne, pTwo);
+ }
+ }
+ }
+
/*
** chngToIN holds a set of tables that *might* satisfy case 1. But
** we have to do some additional checking to see if case 1 really
}else{
sqlite3ExprListDelete(db, pList);
}
- pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
+ pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */
}
}
}
Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
- int noCase = 0; /* LIKE/GLOB distinguishes case */
+ int noCase = 0; /* uppercase equivalent to lowercase */
int op; /* Top-level operator. pExpr->op */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection */
/* Add constraints to reduce the search space on a LIKE or GLOB
** operator.
**
- ** A like pattern of the form "x LIKE 'abc%'" is changed into constraints
+ ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints
**
- ** x>='abc' AND x<'abd' AND x LIKE 'abc%'
+ ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%'
**
** The last character of the prefix "abc" is incremented to form the
- ** termination condition "abd".
+ ** termination condition "abd". If case is not significant (the default
+ ** for LIKE) then the lower-bound is made all uppercase and the upper-
+ ** bound is made all lowercase so that the bounds also work when comparing
+ ** BLOBs.
*/
if( pWC->op==TK_AND
&& isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase)
Expr *pNewExpr2;
int idxNew1;
int idxNew2;
- Token sCollSeqName; /* Name of collating sequence */
+ const char *zCollSeqName; /* Name of collating sequence */
+ const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC;
pLeft = pExpr->x.pList->a[1].pExpr;
pStr2 = sqlite3ExprDup(db, pStr1, 0);
+
+ /* Convert the lower bound to upper-case and the upper bound to
+ ** lower-case (upper-case is less than lower-case in ASCII) so that
+ ** the range constraints also work for BLOBs
+ */
+ if( noCase && !pParse->db->mallocFailed ){
+ int i;
+ char c;
+ pTerm->wtFlags |= TERM_LIKE;
+ for(i=0; (c = pStr1->u.zToken[i])!=0; i++){
+ pStr1->u.zToken[i] = sqlite3Toupper(c);
+ pStr2->u.zToken[i] = sqlite3Tolower(c);
+ }
+ }
+
if( !db->mallocFailed ){
u8 c, *pC; /* Last character before the first wildcard */
pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
}
*pC = c + 1;
}
- sCollSeqName.z = noCase ? "NOCASE" : "BINARY";
- sCollSeqName.n = 6;
+ zCollSeqName = noCase ? "NOCASE" : "BINARY";
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
- pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
- sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
+ pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
+ sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
pStr1, 0);
transferJoinMarkings(pNewExpr1, pExpr);
- idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
+ idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
- sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
+ sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
pStr2, 0);
transferJoinMarkings(pNewExpr2, pExpr);
- idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
+ idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
pLoop = pLevel->pWLoop;
idxCols = 0;
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ Expr *pExpr = pTerm->pExpr;
+ assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */
+ || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */
+ || pLoop->prereq!=0 ); /* table of a LEFT JOIN */
if( pLoop->prereq==0
&& (pTerm->wtFlags & TERM_VIRTUAL)==0
- && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
- && sqlite3ExprIsTableConstant(pTerm->pExpr, pSrc->iCursor) ){
+ && !ExprHasProperty(pExpr, EP_FromJoin)
+ && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){
pPartial = sqlite3ExprAnd(pParse->db, pPartial,
- sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
+ sqlite3ExprDup(pParse->db, pExpr, 0));
}
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
int iCol = pTerm->u.leftColumn;
** Estimate the location of a particular key among all keys in an
** index. Store the results in aStat as follows:
**
-** aStat[0] Est. number of rows less than pVal
-** aStat[1] Est. number of rows equal to pVal
+** aStat[0] Est. number of rows less than pRec
+** aStat[1] Est. number of rows equal to pRec
**
** Return the index of the sample that is the smallest sample that
-** is greater than or equal to pRec.
+** is greater than or equal to pRec. Note that this index is not an index
+** into the aSample[] array - it is an index into a virtual set of samples
+** based on the contents of aSample[] and the number of fields in record
+** pRec.
*/
static int whereKeyStats(
Parse *pParse, /* Database connection */
){
IndexSample *aSample = pIdx->aSample;
int iCol; /* Index of required stats in anEq[] etc. */
+ int i; /* Index of first sample >= pRec */
+ int iSample; /* Smallest sample larger than or equal to pRec */
int iMin = 0; /* Smallest sample not yet tested */
- int i = pIdx->nSample; /* Smallest sample larger than or equal to pRec */
int iTest; /* Next sample to test */
int res; /* Result of comparison operation */
+ int nField; /* Number of fields in pRec */
+ tRowcnt iLower = 0; /* anLt[] + anEq[] of largest sample pRec is > */
#ifndef SQLITE_DEBUG
UNUSED_PARAMETER( pParse );
#endif
assert( pRec!=0 );
- iCol = pRec->nField - 1;
assert( pIdx->nSample>0 );
- assert( pRec->nField>0 && iCol<pIdx->nSampleCol );
+ assert( pRec->nField>0 && pRec->nField<=pIdx->nSampleCol );
+
+ /* Do a binary search to find the first sample greater than or equal
+ ** to pRec. If pRec contains a single field, the set of samples to search
+ ** is simply the aSample[] array. If the samples in aSample[] contain more
+ ** than one fields, all fields following the first are ignored.
+ **
+ ** If pRec contains N fields, where N is more than one, then as well as the
+ ** samples in aSample[] (truncated to N fields), the search also has to
+ ** consider prefixes of those samples. For example, if the set of samples
+ ** in aSample is:
+ **
+ ** aSample[0] = (a, 5)
+ ** aSample[1] = (a, 10)
+ ** aSample[2] = (b, 5)
+ ** aSample[3] = (c, 100)
+ ** aSample[4] = (c, 105)
+ **
+ ** Then the search space should ideally be the samples above and the
+ ** unique prefixes [a], [b] and [c]. But since that is hard to organize,
+ ** the code actually searches this set:
+ **
+ ** 0: (a)
+ ** 1: (a, 5)
+ ** 2: (a, 10)
+ ** 3: (a, 10)
+ ** 4: (b)
+ ** 5: (b, 5)
+ ** 6: (c)
+ ** 7: (c, 100)
+ ** 8: (c, 105)
+ ** 9: (c, 105)
+ **
+ ** For each sample in the aSample[] array, N samples are present in the
+ ** effective sample array. In the above, samples 0 and 1 are based on
+ ** sample aSample[0]. Samples 2 and 3 on aSample[1] etc.
+ **
+ ** Often, sample i of each block of N effective samples has (i+1) fields.
+ ** Except, each sample may be extended to ensure that it is greater than or
+ ** equal to the previous sample in the array. For example, in the above,
+ ** sample 2 is the first sample of a block of N samples, so at first it
+ ** appears that it should be 1 field in size. However, that would make it
+ ** smaller than sample 1, so the binary search would not work. As a result,
+ ** it is extended to two fields. The duplicates that this creates do not
+ ** cause any problems.
+ */
+ nField = pRec->nField;
+ iCol = 0;
+ iSample = pIdx->nSample * nField;
do{
- iTest = (iMin+i)/2;
- res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec);
+ int iSamp; /* Index in aSample[] of test sample */
+ int n; /* Number of fields in test sample */
+
+ iTest = (iMin+iSample)/2;
+ iSamp = iTest / nField;
+ if( iSamp>0 ){
+ /* The proposed effective sample is a prefix of sample aSample[iSamp].
+ ** Specifically, the shortest prefix of at least (1 + iTest%nField)
+ ** fields that is greater than the previous effective sample. */
+ for(n=(iTest % nField) + 1; n<nField; n++){
+ if( aSample[iSamp-1].anLt[n-1]!=aSample[iSamp].anLt[n-1] ) break;
+ }
+ }else{
+ n = iTest + 1;
+ }
+
+ pRec->nField = n;
+ res = sqlite3VdbeRecordCompare(aSample[iSamp].n, aSample[iSamp].p, pRec);
if( res<0 ){
+ iLower = aSample[iSamp].anLt[n-1] + aSample[iSamp].anEq[n-1];
+ iMin = iTest+1;
+ }else if( res==0 && n<nField ){
+ iLower = aSample[iSamp].anLt[n-1];
iMin = iTest+1;
+ res = -1;
}else{
- i = iTest;
+ iSample = iTest;
+ iCol = n-1;
}
- }while( res && iMin<i );
+ }while( res && iMin<iSample );
+ i = iSample / nField;
#ifdef SQLITE_DEBUG
/* The following assert statements check that the binary search code
** above found the right answer. This block serves no purpose other
** than to invoke the asserts. */
- if( res==0 ){
- /* If (res==0) is true, then sample $i must be equal to pRec */
- assert( i<pIdx->nSample );
- assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
- || pParse->db->mallocFailed );
- }else{
- /* Otherwise, pRec must be smaller than sample $i and larger than
- ** sample ($i-1). */
- assert( i==pIdx->nSample
- || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
- || pParse->db->mallocFailed );
- assert( i==0
- || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
- || pParse->db->mallocFailed );
+ if( pParse->db->mallocFailed==0 ){
+ if( res==0 ){
+ /* If (res==0) is true, then pRec must be equal to sample i. */
+ assert( i<pIdx->nSample );
+ assert( iCol==nField-1 );
+ pRec->nField = nField;
+ assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
+ || pParse->db->mallocFailed
+ );
+ }else{
+ /* Unless i==pIdx->nSample, indicating that pRec is larger than
+ ** all samples in the aSample[] array, pRec must be smaller than the
+ ** (iCol+1) field prefix of sample i. */
+ assert( i<=pIdx->nSample && i>=0 );
+ pRec->nField = iCol+1;
+ assert( i==pIdx->nSample
+ || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
+ || pParse->db->mallocFailed );
+
+ /* if i==0 and iCol==0, then record pRec is smaller than all samples
+ ** in the aSample[] array. Otherwise, if (iCol>0) then pRec must
+ ** be greater than or equal to the (iCol) field prefix of sample i.
+ ** If (i>0), then pRec must also be greater than sample (i-1). */
+ if( iCol>0 ){
+ pRec->nField = iCol;
+ assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0
+ || pParse->db->mallocFailed );
+ }
+ if( i>0 ){
+ pRec->nField = nField;
+ assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
+ || pParse->db->mallocFailed );
+ }
+ }
}
#endif /* ifdef SQLITE_DEBUG */
- /* At this point, aSample[i] is the first sample that is greater than
- ** or equal to pVal. Or if i==pIdx->nSample, then all samples are less
- ** than pVal. If aSample[i]==pVal, then res==0.
- */
if( res==0 ){
+ /* Record pRec is equal to sample i */
+ assert( iCol==nField-1 );
aStat[0] = aSample[i].anLt[iCol];
aStat[1] = aSample[i].anEq[iCol];
}else{
- tRowcnt iLower, iUpper, iGap;
- if( i==0 ){
- iLower = 0;
- iUpper = aSample[0].anLt[iCol];
+ /* At this point, the (iCol+1) field prefix of aSample[i] is the first
+ ** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec
+ ** is larger than all samples in the array. */
+ tRowcnt iUpper, iGap;
+ if( i>=pIdx->nSample ){
+ iUpper = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
}else{
- i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
- iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol];
- iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
+ iUpper = aSample[i].anLt[iCol];
}
- aStat[1] = pIdx->aAvgEq[iCol];
+
if( iLower>=iUpper ){
iGap = 0;
}else{
iGap = iGap/3;
}
aStat[0] = iLower + iGap;
+ aStat[1] = pIdx->aAvgEq[iCol];
}
+
+ /* Restore the pRec->nField value before returning. */
+ pRec->nField = nField;
return i;
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
** but joins might run a little slower. The trick is to disable as much
** as we can without disabling too much. If we disabled in (1), we'd get
** the wrong answer. See ticket #813.
+**
+** If all the children of a term are disabled, then that term is also
+** automatically disabled. In this way, terms get disabled if derived
+** virtual terms are tested first. For example:
+**
+** x GLOB 'abc*' AND x>='abc' AND x<'acd'
+** \___________/ \______/ \_____/
+** parent child1 child2
+**
+** Only the parent term was in the original WHERE clause. The child1
+** and child2 terms were added by the LIKE optimization. If both of
+** the virtual child terms are valid, then testing of the parent can be
+** skipped.
+**
+** Usually the parent term is marked as TERM_CODED. But if the parent
+** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead.
+** The TERM_LIKECOND marking indicates that the term should be coded inside
+** a conditional such that is only evaluated on the second pass of a
+** LIKE-optimization loop, when scanning BLOBs instead of strings.
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
- if( pTerm
+ int nLoop = 0;
+ while( pTerm
&& (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
&& (pLevel->notReady & pTerm->prereqAll)==0
){
- pTerm->wtFlags |= TERM_CODED;
- if( pTerm->iParent>=0 ){
- WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent];
- if( (--pOther->nChild)==0 ){
- disableTerm(pLevel, pOther);
- }
+ if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
+ pTerm->wtFlags |= TERM_LIKECOND;
+ }else{
+ pTerm->wtFlags |= TERM_CODED;
}
+ if( pTerm->iParent<0 ) break;
+ pTerm = &pTerm->pWC->a[pTerm->iParent];
+ pTerm->nChild--;
+ if( pTerm->nChild!=0 ) break;
+ nLoop++;
}
}
# define addScanStatus(a, b, c, d) ((void)d)
#endif
-
+/*
+** If the most recently coded instruction is a constant range contraint
+** that originated from the LIKE optimization, then change the P3 to be
+** pLoop->iLikeRepCntr and set P5.
+**
+** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
+** expression: "x>='ABC' AND x<'abd'". But this requires that the range
+** scan loop run twice, once for strings and a second time for BLOBs.
+** The OP_String opcodes on the second pass convert the upper and lower
+** bound string contants to blobs. This routine makes the necessary changes
+** to the OP_String opcodes for that to happen.
+*/
+static void whereLikeOptimizationStringFixup(
+ Vdbe *v, /* prepared statement under construction */
+ WhereLevel *pLevel, /* The loop that contains the LIKE operator */
+ WhereTerm *pTerm /* The upper or lower bound just coded */
+){
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ VdbeOp *pOp;
+ assert( pLevel->iLikeRepCntr>0 );
+ pOp = sqlite3VdbeGetOp(v, -1);
+ assert( pOp!=0 );
+ assert( pOp->opcode==OP_String8
+ || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
+ pOp->p3 = pLevel->iLikeRepCntr;
+ pOp->p5 = 1;
+ }
+}
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
pRangeStart = pLoop->aLTerm[j++];
nExtraReg = 1;
+ /* Like optimization range constraints always occur in pairs */
+ assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
+ (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
}
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
pRangeEnd = pLoop->aLTerm[j++];
nExtraReg = 1;
+ if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
+ assert( pRangeStart!=0 ); /* LIKE opt constraints */
+ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */
+ pLevel->iLikeRepCntr = ++pParse->nMem;
+ testcase( bRev );
+ testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC),
+ pLevel->iLikeRepCntr);
+ VdbeComment((v, "LIKE loop counter"));
+ pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
+ }
if( pRangeStart==0
&& (j = pIdx->aiColumn[nEq])>=0
&& pIdx->pTable->aCol[j].notNull==0
if( pRangeStart ){
Expr *pRight = pRangeStart->pExpr->pRight;
sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
if( (pRangeStart->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
Expr *pRight = pRangeEnd->pExpr->pRight;
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
*/
wctrlFlags = WHERE_OMIT_OPEN_CLOSE
| WHERE_FORCE_TABLE
- | WHERE_ONETABLE_ONLY;
+ | WHERE_ONETABLE_ONLY
+ | WHERE_NO_AUTOINDEX;
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
*/
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
Expr *pE;
+ int skipLikeAddr = 0;
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
continue;
}
+ if( pTerm->wtFlags & TERM_LIKECOND ){
+ assert( pLevel->iLikeRepCntr>0 );
+ skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr);
+ VdbeCoverage(v);
+ }
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
+ if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
pTerm->wtFlags |= TERM_CODED;
}
}
if( pTerm->prereqRight & pNew->maskSelf ) continue;
+ /* Do not allow the upper bound of a LIKE optimization range constraint
+ ** to mix with a lower range bound from some other source */
+ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
+
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
pNew->nLTerm = saved_nLTerm;
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
pBtm = pTerm;
pTop = 0;
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ /* Range contraints that come from the LIKE optimization are
+ ** always used in pairs. */
+ pTop = &pTerm[1];
+ assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
+ assert( pTop->wtFlags & TERM_LIKEOPT );
+ assert( pTop->eOperator==WO_LT );
+ if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ pNew->aLTerm[pNew->nLTerm++] = pTop;
+ pNew->wsFlags |= WHERE_TOP_LIMIT;
+ }
}else{
assert( eOp & (WO_LT|WO_LE) );
testcase( eOp & WO_LT );
int i;
WhereTerm *pTerm;
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- if( sqlite3ExprImpliesExpr(pTerm->pExpr, pWhere, iTab)
- && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
+ Expr *pExpr = pTerm->pExpr;
+ if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab)
+ && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
){
return 1;
}
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/* Automatic indexes */
if( !pBuilder->pOrSet
+ && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
&& pSrc->pIndex==0
&& !pSrc->viaCoroutine
/* Seed the search with a single WherePath containing zero WhereLoops.
**
- ** TUNING: Do not let the number of iterations go above 25. If the cost
- ** of computing an automatic index is not paid back within the first 25
+ ** TUNING: Do not let the number of iterations go above 28. If the cost
+ ** of computing an automatic index is not paid back within the first 28
** rows, then do not use the automatic index. */
- aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
+ aFrom[0].nRow = MIN(pParse->nQueryLoop, 48); assert( 48==sqlite3LogEst(28) );
nFrom = 1;
assert( aFrom[0].isOrdered==0 );
if( nOrderBy ){
if( op ){
sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
+ if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
+ && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
+ && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
+ ){
+ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
+ }
VdbeComment((v, "%s", pIx->zName));
}
}
sqlite3VdbeJumpHere(v, pLevel->addrSkip);
sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
}
+ if( pLevel->addrLikeRep ){
+ int op;
+ if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){
+ op = OP_DecrJumpZero;
+ }else{
+ op = OP_JumpZeroIncr;
+ }
+ sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep);
+ VdbeCoverage(v);
+ }
if( pLevel->iLeftJoin ){
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
int addrCont; /* Jump here to continue with the next loop cycle */
int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */
+ int iLikeRepCntr; /* LIKE range processing counter register */
+ int addrLikeRep; /* LIKE range processing address */
u8 iFrom; /* Which entry in the FROM clause */
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
int p1, p2; /* Operands of the opcode used to ends the loop */
} u;
LogEst truthProb; /* Probability of truth for this expression */
u16 eOperator; /* A WO_xx value describing <op> */
- u8 wtFlags; /* TERM_xxx bit flags. See below */
+ u16 wtFlags; /* TERM_xxx bit flags. See below */
u8 nChild; /* Number of children that must disable us */
WhereClause *pWC; /* The clause this term is part of */
Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
#else
# define TERM_VNULL 0x00 /* Disabled if not using stat3 */
#endif
+#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */
+#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */
+#define TERM_LIKE 0x400 /* The original LIKE operator */
/*
** An instance of the WhereScan object is used as an iterator for locating
IF NOT DEFINED _CECHO (SET _CECHO=REM)\r
IF NOT DEFINED _VECHO (SET _VECHO=REM)\r
\r
+SET REDIRECT=^>\r
+IF DEFINED __ECHO SET REDIRECT=^^^>\r
+\r
%_AECHO% Running %0 %*\r
\r
REM SET DFLAGS=/L\r
%_AECHO% Building the %%B configuration for platform %%P with name %%D...\r
\r
IF /I "%%B" == "Debug" (\r
- SET DEBUG=2\r
+ REM\r
+ REM NOTE: Using this level for the DEBUG environment variable should\r
+ REM disable all compiler optimizations and prevent use of the\r
+ REM NDEBUG define. Additionally, both SQLITE_ENABLE_API_ARMOR\r
+ REM and SQLITE_DEBUG defines should be enabled.\r
+ REM\r
+ SET DEBUG=3\r
+\r
+ REM\r
+ REM NOTE: Setting this to non-zero should enable the SQLITE_MEMDEBUG\r
+ REM define.\r
+ REM\r
SET MEMDEBUG=1\r
) ELSE (\r
CALL :fn_UnsetVariable DEBUG\r
) ELSE (\r
REM\r
REM NOTE: Even when the cleaning step has been disabled, we still\r
- REM need to remove the build output for the files we are\r
+ REM need to remove the build output for all the files we are\r
REM specifically wanting to build for each platform.\r
REM\r
- %_AECHO% Cleaning final output files only...\r
- %__ECHO% DEL /Q *.lo sqlite3.dll sqlite3.lib sqlite3.pdb\r
+ %_AECHO% Cleaning final core library output files only...\r
+ %__ECHO% DEL /Q *.lo sqlite3.dll sqlite3.lib sqlite3.pdb 2%REDIRECT% NUL\r
)\r
\r
REM\r
GOTO errors\r
)\r
)\r
+\r
+ REM\r
+ REM NOTE: If requested, also build the shell executable.\r
+ REM\r
+ IF DEFINED BUILD_ALL_SHELL (\r
+ REM\r
+ REM NOTE: If necessary, make sure any previous build output for the\r
+ REM shell executable is deleted.\r
+ REM\r
+ IF DEFINED NOCLEAN (\r
+ REM\r
+ REM NOTE: Even when the cleaning step has been disabled, we still\r
+ REM need to remove the build output for all the files we are\r
+ REM specifically wanting to build for each platform.\r
+ REM\r
+ %_AECHO% Cleaning final shell executable output files only...\r
+ %__ECHO% DEL /Q sqlite3.exe sqlite3sh.pdb 2%REDIRECT% NUL\r
+ )\r
+\r
+ REM\r
+ REM NOTE: Call NMAKE with the MSVC makefile to build the "sqlite3.exe"\r
+ REM binary. The x86 compiler will be used to compile the native\r
+ REM command line tools needed during the build process itself.\r
+ REM Also, disable looking for and/or linking to the native Tcl\r
+ REM runtime library.\r
+ REM\r
+ %__ECHO% %NMAKE_CMD% sqlite3.exe XCOMPILE=1 USE_NATIVE_LIBPATHS=1 NO_TCL=1 %NMAKE_ARGS%\r
+\r
+ IF ERRORLEVEL 1 (\r
+ ECHO Failed to build %%B "sqlite3.exe" for platform %%P.\r
+ GOTO errors\r
+ )\r
+\r
+ REM\r
+ REM NOTE: Copy the "sqlite3.exe" file to the appropriate directory\r
+ REM for the build and platform beneath the binary directory.\r
+ REM\r
+ %__ECHO% XCOPY sqlite3.exe "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS%\r
+\r
+ IF ERRORLEVEL 1 (\r
+ ECHO Failed to copy "sqlite3.exe" to "%BINARYDIRECTORY%\%%B\%%D\".\r
+ GOTO errors\r
+ )\r
+\r
+ REM\r
+ REM NOTE: Copy the "sqlite3sh.pdb" file to the appropriate directory\r
+ REM for the build and platform beneath the binary directory\r
+ REM unless we are prevented from doing so.\r
+ REM\r
+ IF NOT DEFINED NOSYMBOLS (\r
+ %__ECHO% XCOPY sqlite3sh.pdb "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS%\r
+\r
+ IF ERRORLEVEL 1 (\r
+ ECHO Failed to copy "sqlite3sh.pdb" to "%BINARYDIRECTORY%\%%B\%%D\".\r
+ GOTO errors\r
+ )\r
+ )\r
+ )\r
)\r
)\r
)\r
#
# To add new pragmas, first add the name and other relevant attributes
# of the pragma to the "pragma_def" object below. Then run this script
-# to generate the C-code for the lookup table and copy/paste the output
-# of this script into the appropriate spot in the pragma.c source file.
+# to generate the ../src/pragma.h header file that contains macros and
+# the lookup table needed for pragma name lookup in the pragma.c module.
# Then add the extra "case PragTyp_XXXXX:" and subsequent code for the
-# new pragma.
+# new pragma in ../src/pragma.c.
#
set pragma_def {
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
NAME: index_info
+ TYPE: INDEX_INFO
+ ARG: 0
+ FLAG: NeedSchema
+ IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
+
+ NAME: index_xinfo
+ TYPE: INDEX_INFO
+ ARG: 1
FLAG: NeedSchema
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
NAME: threads
}
-fconfigure stdout -translation lf
+
+# Open the output file
+#
+set destfile "[file dir [file dir [file normal $argv0]]]/src/pragma.h"
+puts "Overwriting $destfile with new pragma table..."
+set fd [open $destfile wb]
+puts $fd {/* DO NOT EDIT!
+** This file is automatically generated by the script at
+** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit
+** that script and rerun it.
+*/}
+
+# Parse the PRAGMA table above.
+#
set name {}
set type {}
set if {}
set if [lindex $allbyname($name) 2]
if {[regexp SQLITE_DEBUG $if] || [regexp SQLITE_HAS_CODEC $if]} continue
set seentype($type) 1
- puts [format {#define %-35s %4d} PragTyp_$type $pnum]
+ puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum]
incr pnum
}
foreach name $allnames {
set if [lindex $allbyname($name) 2]
if {[regexp SQLITE_DEBUG $if]} continue
set seentype($type) 1
- puts [format {#define %-35s %4d} PragTyp_$type $pnum]
+ puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum]
incr pnum
}
foreach name $allnames {
set type [lindex $allbyname($name) 0]
if {[info exists seentype($type)]} continue
set seentype($type) 1
- puts [format {#define %-35s %4d} PragTyp_$type $pnum]
+ puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum]
incr pnum
}
#
set fv 1
foreach f [lsort [array names allflags]] {
- puts [format {#define PragFlag_%-20s 0x%02x} $f $fv]
+ puts $fd [format {#define PragFlag_%-20s 0x%02x} $f $fv]
set fv [expr {$fv*2}]
}
# Generate the lookup table
#
-puts "static const struct sPragmaNames \173"
-puts " const char *const zName; /* Name of pragma */"
-puts " u8 ePragTyp; /* PragTyp_XXX value */"
-puts " u8 mPragFlag; /* Zero or more PragFlag_XXX values */"
-puts " u32 iArg; /* Extra argument */"
-puts "\175 aPragmaNames\[\] = \173"
+puts $fd "static const struct sPragmaNames \173"
+puts $fd " const char *const zName; /* Name of pragma */"
+puts $fd " u8 ePragTyp; /* PragTyp_XXX value */"
+puts $fd " u8 mPragFlag; /* Zero or more PragFlag_XXX values */"
+puts $fd " u32 iArg; /* Extra argument */"
+puts $fd "\175 aPragmaNames\[\] = \173"
set current_if {}
set spacer [format { %26s } {}]
if {$if!=$current_if} {
if {$current_if!=""} {
foreach this_if $current_if {
- puts "#endif"
+ puts $fd "#endif"
}
}
set current_if $if
if {$current_if!=""} {
foreach this_if $current_if {
- puts "#if $this_if"
+ puts $fd "#if $this_if"
}
}
}
} else {
set flagx PragFlag_[join $flag {|PragFlag_}]
}
- puts " \173 /* zName: */ \"$name\","
- puts " /* ePragTyp: */ PragTyp_$type,"
- puts " /* ePragFlag: */ $flagx,"
- puts " /* iArg: */ $arg \175,"
+ puts $fd " \173 /* zName: */ \"$name\","
+ puts $fd " /* ePragTyp: */ PragTyp_$type,"
+ puts $fd " /* ePragFlag: */ $flagx,"
+ puts $fd " /* iArg: */ $arg \175,"
}
if {$current_if!=""} {
foreach this_if $current_if {
- puts "#endif"
+ puts $fd "#endif"
}
}
-puts "\175;"
+puts $fd "\175;"
# count the number of pragmas, for information purposes
#
if {[regexp {^defined} $if] || [regexp {[^!]defined} $if]} continue
incr dfltcnt
}
-puts "/* Number of pragmas: $dfltcnt on by default, $allcnt total. */"
+puts $fd "/* Number of pragmas: $dfltcnt on by default, $allcnt total. */"
# After the "tsrc" directory has been created and populated, run
# this script:
#
-# tclsh mksqlite3c.tcl
+# tclsh mksqlite3c-noext.tcl
#
# The amalgamated SQLite code will be written into sqlite3.c
#
# Begin by reading the "sqlite3.h" header file. Extract the version number
-# from in this file. The versioon number is needed to generate the header
+# from in this file. The version number is needed to generate the header
# comment of the amalgamation.
#
if {[lsearch $argv --nostatic]>=0} {
puts $out \
{#ifndef SQLITE_PRIVATE
# define SQLITE_PRIVATE static
-#endif
-#ifndef SQLITE_API
-# define SQLITE_API
#endif}
}
pager.h
parse.h
pcache.h
+ pragma.h
sqlite3ext.h
sqlite3.h
sqliteicu.h
sqliteLimit.h
vdbe.h
vdbeInt.h
+ vxworks.h
wal.h
+ whereInt.h
} {
set available_hdr($hdr) 1
}
set available_hdr(sqliteInt.h) 0
+# These headers should be copied into the amalgamation without modifying any
+# of their function declarations or definitions.
+set varonly_hdr(sqlite3.h) 1
+
+# These are the functions that accept a variable number of arguments. They
+# always need to use the "cdecl" calling convention even when another calling
+# convention (e.g. "stcall") is being used for the rest of the library.
+set cdecllist {
+ sqlite3_config
+ sqlite3_db_config
+ sqlite3_log
+ sqlite3_mprintf
+ sqlite3_snprintf
+ sqlite3_test_control
+ sqlite3_vtab_config
+}
+
# 78 stars used for comment formatting.
set s78 \
{*****************************************************************************}
# Read the source file named $filename and write it into the
# sqlite3.c output file. If any #include statements are seen,
-# process them approprately.
+# process them appropriately.
#
proc copy_file {filename} {
- global seen_hdr available_hdr out addstatic linemacros
+ global seen_hdr available_hdr varonly_hdr cdecllist out addstatic linemacros
set ln 0
set tail [file tail $filename]
section_comment "Begin file $tail"
if {$linemacros} {puts $out "#line 1 \"$filename\""}
set in [open $filename r]
set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
- set declpattern {[a-zA-Z][a-zA-Z_0-9 ]+ \**(sqlite3[_a-zA-Z0-9]+)\(}
+ set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)}
if {[file extension $filename]==".h"} {
set declpattern " *$declpattern"
}
- set declpattern ^$declpattern
+ set declpattern ^$declpattern\$
while {![eof $in]} {
set line [gets $in]
incr ln
if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""}
}
} elseif {![info exists seen_hdr($hdr)]} {
- set seen_hdr($hdr) 1
+ if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} {
+ set seen_hdr($hdr) 1
+ }
+ puts $out $line
+ } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} {
+ # This include file must be kept because there was a "keep"
+ # directive inside of a line comment.
puts $out $line
} else {
- puts $out "/* $line */"
+ # Comment out the entire line, replacing any nested comment
+ # begin/end markers with the harmless substring "**".
+ puts $out "/* [string map [list /* ** */ **] $line] */"
}
} elseif {[regexp {^#ifdef __cplusplus} $line]} {
puts $out "#if 0"
} elseif {!$linemacros && [regexp {^#line} $line]} {
# Skip #line directives.
} elseif {$addstatic && ![regexp {^(static|typedef)} $line]} {
- regsub {^SQLITE_API } $line {} line
- if {[regexp $declpattern $line all funcname]} {
+ # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before
+ # functions if this header file does not need it.
+ if {![info exists varonly_hdr($tail)]
+ && [regexp $declpattern $line all rettype funcname rest]} {
+ regsub {^SQLITE_API } $line {} line
# Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
# so that linkage can be modified at compile-time.
if {[regexp {^sqlite3_} $funcname]} {
- puts $out "SQLITE_API $line"
+ set line SQLITE_API
+ append line " " [string trim $rettype]
+ if {[string index $rettype end] ne "*"} {
+ append line " "
+ }
+ if {[lsearch -exact $cdecllist $funcname] >= 0} {
+ append line SQLITE_CDECL
+ } else {
+ append line SQLITE_STDCALL
+ }
+ append line " " $funcname $rest
+ puts $out $line
} else {
puts $out "SQLITE_PRIVATE $line"
}
} elseif {[regexp $varpattern $line all varname]} {
- # Add the SQLITE_PRIVATE before variable declarations or
- # definitions for internal use
- if {![regexp {^sqlite3_} $varname]} {
- regsub {^extern } $line {} line
- puts $out "SQLITE_PRIVATE $line"
- } else {
- if {[regexp {const char sqlite3_version\[\];} $line]} {
- set line {const char sqlite3_version[] = SQLITE_VERSION;}
+ # Add the SQLITE_PRIVATE before variable declarations or
+ # definitions for internal use
+ regsub {^SQLITE_API } $line {} line
+ if {![regexp {^sqlite3_} $varname]} {
+ regsub {^extern } $line {} line
+ puts $out "SQLITE_PRIVATE $line"
+ } else {
+ if {[regexp {const char sqlite3_version\[\];} $line]} {
+ set line {const char sqlite3_version[] = SQLITE_VERSION;}
+ }
+ regsub {^SQLITE_EXTERN } $line {} line
+ puts $out "SQLITE_API $line"
}
- regsub {^SQLITE_EXTERN } $line {} line
- puts $out "SQLITE_API $line"
- }
} elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
+ regsub {^SQLITE_API } $line {} line
regsub {^SQLITE_EXTERN } $line {} line
- puts $out "SQLITE_PRIVATE $line"
+ puts $out $line
} elseif {[regexp {^void \(\*sqlite3Os} $line]} {
+ regsub {^SQLITE_API } $line {} line
puts $out "SQLITE_PRIVATE $line"
} else {
puts $out $line
puts $out \
{#ifndef SQLITE_PRIVATE
# define SQLITE_PRIVATE static
-#endif
-#ifndef SQLITE_API
-# define SQLITE_API
#endif}
}
pager.h
parse.h
pcache.h
+ pragma.h
rtree.h
sqlite3ext.h
sqlite3.h
sqliteLimit.h
vdbe.h
vdbeInt.h
+ vxworks.h
wal.h
whereInt.h
} {
}
set available_hdr(sqliteInt.h) 0
+# These headers should be copied into the amalgamation without modifying any
+# of their function declarations or definitions.
+set varonly_hdr(sqlite3.h) 1
+
+# These are the functions that accept a variable number of arguments. They
+# always need to use the "cdecl" calling convention even when another calling
+# convention (e.g. "stcall") is being used for the rest of the library.
+set cdecllist {
+ sqlite3_config
+ sqlite3_db_config
+ sqlite3_log
+ sqlite3_mprintf
+ sqlite3_snprintf
+ sqlite3_test_control
+ sqlite3_vtab_config
+}
+
# 78 stars used for comment formatting.
set s78 \
{*****************************************************************************}
# process them appropriately.
#
proc copy_file {filename} {
- global seen_hdr available_hdr out addstatic linemacros
+ global seen_hdr available_hdr varonly_hdr cdecllist out addstatic linemacros
set ln 0
set tail [file tail $filename]
section_comment "Begin file $tail"
if {$linemacros} {puts $out "#line 1 \"$filename\""}
set in [open $filename r]
set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
- set declpattern {[a-zA-Z][a-zA-Z_0-9 ]+ \**(sqlite3[_a-zA-Z0-9]+)\(}
+ set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)}
if {[file extension $filename]==".h"} {
set declpattern " *$declpattern"
}
- set declpattern ^$declpattern
+ set declpattern ^$declpattern\$
while {![eof $in]} {
set line [gets $in]
incr ln
} elseif {!$linemacros && [regexp {^#line} $line]} {
# Skip #line directives.
} elseif {$addstatic && ![regexp {^(static|typedef)} $line]} {
- regsub {^SQLITE_API } $line {} line
- if {[regexp $declpattern $line all funcname]} {
+ # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before
+ # functions if this header file does not need it.
+ if {![info exists varonly_hdr($tail)]
+ && [regexp $declpattern $line all rettype funcname rest]} {
+ regsub {^SQLITE_API } $line {} line
# Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
# so that linkage can be modified at compile-time.
if {[regexp {^sqlite3_} $funcname]} {
- puts $out "SQLITE_API $line"
+ set line SQLITE_API
+ append line " " [string trim $rettype]
+ if {[string index $rettype end] ne "*"} {
+ append line " "
+ }
+ if {[lsearch -exact $cdecllist $funcname] >= 0} {
+ append line SQLITE_CDECL
+ } else {
+ append line SQLITE_STDCALL
+ }
+ append line " " $funcname $rest
+ puts $out $line
} else {
puts $out "SQLITE_PRIVATE $line"
}
} elseif {[regexp $varpattern $line all varname]} {
- # Add the SQLITE_PRIVATE before variable declarations or
- # definitions for internal use
- if {![regexp {^sqlite3_} $varname]} {
- regsub {^extern } $line {} line
- puts $out "SQLITE_PRIVATE $line"
- } else {
- if {[regexp {const char sqlite3_version\[\];} $line]} {
- set line {const char sqlite3_version[] = SQLITE_VERSION;}
+ # Add the SQLITE_PRIVATE before variable declarations or
+ # definitions for internal use
+ regsub {^SQLITE_API } $line {} line
+ if {![regexp {^sqlite3_} $varname]} {
+ regsub {^extern } $line {} line
+ puts $out "SQLITE_PRIVATE $line"
+ } else {
+ if {[regexp {const char sqlite3_version\[\];} $line]} {
+ set line {const char sqlite3_version[] = SQLITE_VERSION;}
+ }
+ regsub {^SQLITE_EXTERN } $line {} line
+ puts $out "SQLITE_API $line"
}
- regsub {^SQLITE_EXTERN } $line {} line
- puts $out "SQLITE_API $line"
- }
} elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
+ regsub {^SQLITE_API } $line {} line
regsub {^SQLITE_EXTERN } $line {} line
puts $out $line
} elseif {[regexp {^void \(\*sqlite3Os} $line]} {
+ regsub {^SQLITE_API } $line {} line
puts $out "SQLITE_PRIVATE $line"
} else {
puts $out $line
# Set up patterns for recognizing API declarations.
#
set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+sqlite3_[_a-zA-Z0-9]+(\[|;| =)}
-set declpattern {^ *[a-zA-Z][a-zA-Z_0-9 ]+ \**sqlite3_[_a-zA-Z0-9]+\(}
+set declpattern {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3_[_a-zA-Z0-9]+)(\(.*)$}
# Force the output to use unix line endings, even on Windows.
fconfigure stdout -translation lf
$TOP/ext/rtree/sqlite3rtree.h
}]
+# These are the functions that accept a variable number of arguments. They
+# always need to use the "cdecl" calling convention even when another calling
+# convention (e.g. "stcall") is being used for the rest of the library.
+set cdecllist {
+ sqlite3_config
+ sqlite3_db_config
+ sqlite3_log
+ sqlite3_mprintf
+ sqlite3_snprintf
+ sqlite3_test_control
+ sqlite3_vtab_config
+}
+
# Process the source files.
#
foreach file $filelist {
regsub -- --VERS-- $line $zVersion line
regsub -- --VERSION-NUMBER-- $line $nVersion line
regsub -- --SOURCE-ID-- $line "$zDate $zUuid" line
-
- if {[regexp {define SQLITE_EXTERN extern} $line]} {
- puts $line
- puts [gets $in]
- puts ""
- puts "#ifndef SQLITE_API"
- puts "# define SQLITE_API"
- puts "#endif"
- set line ""
- }
-
- if {([regexp $varpattern $line] && ![regexp {^ *typedef} $line])
- || ([regexp $declpattern $line])
- } {
+
+ if {[regexp $varpattern $line] && ![regexp {^ *typedef} $line]} {
set line "SQLITE_API $line"
+ } else {
+ if {[regexp $declpattern $line all rettype funcname rest]} {
+ set line SQLITE_API
+ append line " " [string trim $rettype]
+ if {[string index $rettype end] ne "*"} {
+ append line " "
+ }
+ if {[lsearch -exact $cdecllist $funcname] >= 0} {
+ append line SQLITE_CDECL
+ } else {
+ append line SQLITE_STDCALL
+ }
+ append line " " $funcname $rest
+ }
}
puts $line
}
int szPgHdr, /* Size of the page header. 0 or 100 */
int ofst /* Cell begins at a[ofst] */
){
- int i, j;
+ int i, j = 0;
int leftChild;
i64 k;
i64 nPayload;
--- /dev/null
+/*
+** This file implements a simple command-line utility that shows all of the
+** Posix Advisory Locks on a file.
+**
+** Usage:
+**
+** showlocks FILENAME
+**
+** To compile: gcc -o showlocks showlocks.c
+*/
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* This utility only looks for locks in the first 2 billion bytes */
+#define MX_LCK 2147483647
+
+/*
+** Print all locks on the inode of "fd" that occur in between
+** lwr and upr, inclusive.
+*/
+static int showLocksInRange(int fd, off_t lwr, off_t upr){
+ int cnt = 0;
+ struct flock x;
+
+ x.l_type = F_WRLCK;
+ x.l_whence = SEEK_SET;
+ x.l_start = lwr;
+ x.l_len = upr-lwr;
+ fcntl(fd, F_GETLK, &x);
+ if( x.l_type==F_UNLCK ) return 0;
+ printf("start: %-12d len: %-5d pid: %-5d type: %s\n",
+ (int)x.l_start, (int)x.l_len,
+ x.l_pid, x.l_type==F_WRLCK ? "WRLCK" : "RDLCK");
+ cnt++;
+ if( x.l_start>lwr ){
+ cnt += showLocksInRange(fd, lwr, x.l_start-1);
+ }
+ if( x.l_start+x.l_len<upr ){
+ cnt += showLocksInRange(fd, x.l_start+x.l_len+1, upr);
+ }
+ return cnt;
+}
+
+int main(int argc, char **argv){
+ int fd;
+ int cnt;
+
+ if( argc!=2 ){
+ fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
+ return 1;
+ }
+ fd = open(argv[1], O_RDWR, 0);
+ if( fd<0 ){
+ fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[1]);
+ return 1;
+ }
+ cnt = showLocksInRange(fd, 0, MX_LCK);
+ if( cnt==0 ) printf("no locks\n");
+ close(fd);
+ return 0;
+}
#
if {[catch {
+
+# Argument $tname is the name of a table within the database opened by
+# database handle [db]. Return true if it is a WITHOUT ROWID table, or
+# false otherwise.
+#
+proc is_without_rowid {tname} {
+ set t [string map {' ''} $tname]
+ db eval "PRAGMA index_list = '$t'" o {
+ if {$o(origin) == "pk"} {
+ set n $o(name)
+ if {0==[db one { SELECT count(*) FROM sqlite_master WHERE name=$n }]} {
+ return 1
+ }
+ }
+ }
+ return 0
+}
+
# Get the name of the database to analyze
#
proc usage {} {
foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] {
set is_index [expr {$name!=$tblname}]
+ set idx_btree [expr {$is_index || [is_without_rowid $name]}]
db eval {
SELECT
sum(ncell) AS nentry,
- sum(isleaf(pagetype, $is_index) * ncell) AS leaf_entries,
+ sum(isleaf(pagetype, $idx_btree) * ncell) AS leaf_entries,
sum(payload) AS payload,
- sum(isoverflow(pagetype, $is_index) * payload) AS ovfl_payload,
+ sum(isoverflow(pagetype, $idx_btree) * payload) AS ovfl_payload,
sum(path LIKE '%+000000') AS ovfl_cnt,
max(mx_payload) AS mx_payload,
- sum(isinternal(pagetype, $is_index)) AS int_pages,
- sum(isleaf(pagetype, $is_index)) AS leaf_pages,
- sum(isoverflow(pagetype, $is_index)) AS ovfl_pages,
- sum(isinternal(pagetype, $is_index) * unused) AS int_unused,
- sum(isleaf(pagetype, $is_index) * unused) AS leaf_unused,
- sum(isoverflow(pagetype, $is_index) * unused) AS ovfl_unused,
+ sum(isinternal(pagetype, $idx_btree)) AS int_pages,
+ sum(isleaf(pagetype, $idx_btree)) AS leaf_pages,
+ sum(isoverflow(pagetype, $idx_btree)) AS ovfl_pages,
+ sum(isinternal(pagetype, $idx_btree) * unused) AS int_unused,
+ sum(isleaf(pagetype, $idx_btree) * unused) AS leaf_unused,
+ sum(isoverflow(pagetype, $idx_btree) * unused) AS ovfl_unused,
sum(pgsize) AS compressed_size
FROM temp.dbstat WHERE name = $name
} break