mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-31 06:21:07 +00:00
Merge sqlite-release(3.8.10.2) into prerelease-integration
This commit is contained in:
+5
-1
@@ -126,6 +126,7 @@ static void renameParentFunc(
|
||||
n = sqlite3GetToken(z, &token);
|
||||
}while( token==TK_SPACE );
|
||||
|
||||
if( token==TK_ILLEGAL ) break;
|
||||
zParent = sqlite3DbStrNDup(db, (const char *)z, n);
|
||||
if( zParent==0 ) break;
|
||||
sqlite3Dequote(zParent);
|
||||
@@ -690,7 +691,10 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
+9
-6
@@ -1519,14 +1519,17 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
z = argv[2];
|
||||
|
||||
if( pIndex ){
|
||||
tRowcnt *aiRowEst = 0;
|
||||
int nCol = pIndex->nKeyCol+1;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
tRowcnt * const aiRowEst = pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(
|
||||
sizeof(tRowcnt) * nCol
|
||||
);
|
||||
if( aiRowEst==0 ) pInfo->db->mallocFailed = 1;
|
||||
#else
|
||||
tRowcnt * const aiRowEst = 0;
|
||||
/* Index.aiRowEst may already be set here if there are duplicate
|
||||
** sqlite_stat1 entries for this index. In that case just clobber
|
||||
** the old data with the new instead of allocating a new array. */
|
||||
if( pIndex->aiRowEst==0 ){
|
||||
pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol);
|
||||
if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1;
|
||||
}
|
||||
aiRowEst = pIndex->aiRowEst;
|
||||
#endif
|
||||
pIndex->bUnordered = 0;
|
||||
decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex);
|
||||
|
||||
+2
-3
@@ -191,7 +191,7 @@ static void attachFunc(
|
||||
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;
|
||||
@@ -298,7 +298,7 @@ static void detachFunc(
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
sqlite3CollapseDatabaseArray(db);
|
||||
return;
|
||||
|
||||
detach_error:
|
||||
@@ -332,7 +332,6 @@ static void codeAttach(
|
||||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
|
||||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
|
||||
){
|
||||
pParse->nErr++;
|
||||
goto attach_end;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -247,7 +247,7 @@ static int backupOnePage(
|
||||
** 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;
|
||||
|
||||
+1
-1
@@ -341,7 +341,7 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){
|
||||
** bits to act as the reference */
|
||||
pBitvec = sqlite3BitvecCreate( sz );
|
||||
pV = sqlite3MallocZero( (sz+7)/8 + 1 );
|
||||
pTmpSpace = sqlite3_malloc(BITVEC_SZ);
|
||||
pTmpSpace = sqlite3_malloc64(BITVEC_SZ);
|
||||
if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
|
||||
|
||||
/* NULL pBitvec tests */
|
||||
|
||||
@@ -141,6 +141,7 @@ static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){
|
||||
** 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--;
|
||||
|
||||
+147
-50
@@ -175,6 +175,12 @@ static int hasSharedCacheTableLock(
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -594,10 +600,15 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
|
||||
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 */
|
||||
|
||||
@@ -668,7 +679,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
|
||||
){
|
||||
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;
|
||||
@@ -740,17 +751,19 @@ static int btreeMoveto(
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -802,9 +815,10 @@ int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){
|
||||
*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;
|
||||
@@ -1945,16 +1959,18 @@ int sqlite3BtreeOpen(
|
||||
*/
|
||||
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);
|
||||
@@ -2011,8 +2027,8 @@ int sqlite3BtreeOpen(
|
||||
** 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 );
|
||||
@@ -2399,6 +2415,9 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
|
||||
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;
|
||||
@@ -2410,7 +2429,7 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
|
||||
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
|
||||
((pageSize-1)&pageSize)==0 ){
|
||||
assert( (pageSize & 7)==0 );
|
||||
assert( !pBt->pPage1 && !pBt->pCursor );
|
||||
assert( !pBt->pCursor );
|
||||
pBt->pageSize = (u32)pageSize;
|
||||
freeTempSpace(pBt);
|
||||
}
|
||||
@@ -2428,7 +2447,6 @@ int sqlite3BtreeGetPageSize(Btree *p){
|
||||
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
|
||||
@@ -2441,25 +2459,33 @@ int sqlite3BtreeGetPageSize(Btree *p){
|
||||
** 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.
|
||||
@@ -2490,7 +2516,6 @@ int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
|
||||
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'
|
||||
@@ -3610,7 +3635,7 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
|
||||
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);
|
||||
@@ -4016,6 +4041,8 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
|
||||
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;
|
||||
@@ -4424,13 +4451,18 @@ static const void *fetchPayload(
|
||||
BtCursor *pCur, /* Cursor pointing to entry to read from */
|
||||
u32 *pAmt /* Write the number of available bytes here */
|
||||
){
|
||||
u32 amt;
|
||||
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->info.nSize>0 );
|
||||
*pAmt = pCur->info.nLocal;
|
||||
assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
|
||||
assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
|
||||
amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
|
||||
if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
|
||||
*pAmt = amt;
|
||||
return (void*)pCur->info.pPayload;
|
||||
}
|
||||
|
||||
@@ -4494,7 +4526,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
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
|
||||
@@ -4503,6 +4535,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
** 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 );
|
||||
@@ -4527,19 +4561,11 @@ static void moveToParent(BtCursor *pCur){
|
||||
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]);
|
||||
@@ -6714,7 +6740,6 @@ static int balance_nonroot(
|
||||
}else if( iParentIdx==i ){
|
||||
nxDiv = i-2+bBulk;
|
||||
}else{
|
||||
assert( bBulk==0 );
|
||||
nxDiv = iParentIdx-1;
|
||||
}
|
||||
i = 2-bBulk;
|
||||
@@ -7465,7 +7490,8 @@ static int balance(BtCursor *pCur){
|
||||
** 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
|
||||
@@ -7486,6 +7512,7 @@ static int balance(BtCursor *pCur){
|
||||
/* The next iteration of the do-loop balances the parent page. */
|
||||
releasePage(pPage);
|
||||
pCur->iPage--;
|
||||
assert( pCur->iPage>=0 );
|
||||
}
|
||||
}while( rc==SQLITE_OK );
|
||||
|
||||
@@ -7962,9 +7989,13 @@ static int clearDatabasePage(
|
||||
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);
|
||||
@@ -7989,6 +8020,7 @@ static int clearDatabasePage(
|
||||
}
|
||||
|
||||
cleardatabasepage_out:
|
||||
pPage->bBusy = 0;
|
||||
releasePage(pPage);
|
||||
return rc;
|
||||
}
|
||||
@@ -8496,6 +8528,57 @@ static void checkList(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
|
||||
/*
|
||||
** An implementation of a min-heap.
|
||||
**
|
||||
** aHeap[0] is the number of elements on the heap. aHeap[1] is the
|
||||
** root element. The daughter nodes of aHeap[N] are aHeap[N*2]
|
||||
** and aHeap[N*2+1].
|
||||
**
|
||||
** The heap property is this: Every node is less than or equal to both
|
||||
** of its daughter nodes. A consequence of the heap property is that the
|
||||
** root node aHeap[1] is always the minimum value currently in the heap.
|
||||
**
|
||||
** The btreeHeapInsert() routine inserts an unsigned 32-bit number onto
|
||||
** the heap, preserving the heap property. The btreeHeapPull() routine
|
||||
** removes the root element from the heap (the minimum value in the heap)
|
||||
** and then moves other nodes around as necessary to preserve the heap
|
||||
** property.
|
||||
**
|
||||
** This heap is used for cell overlap and coverage testing. Each u32
|
||||
** entry represents the span of a cell or freeblock on a btree page.
|
||||
** The upper 16 bits are the index of the first byte of a range and the
|
||||
** lower 16 bits are the index of the last byte of that range.
|
||||
*/
|
||||
static void btreeHeapInsert(u32 *aHeap, u32 x){
|
||||
u32 j, i = ++aHeap[0];
|
||||
aHeap[i] = x;
|
||||
while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){
|
||||
x = aHeap[j];
|
||||
aHeap[j] = aHeap[i];
|
||||
aHeap[i] = x;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
static int btreeHeapPull(u32 *aHeap, u32 *pOut){
|
||||
u32 j, i, x;
|
||||
if( (x = aHeap[0])==0 ) return 0;
|
||||
*pOut = aHeap[1];
|
||||
aHeap[1] = aHeap[x];
|
||||
aHeap[x] = 0xffffffff;
|
||||
aHeap[0]--;
|
||||
i = 1;
|
||||
while( (j = i*2)<=aHeap[0] ){
|
||||
if( aHeap[j]>aHeap[j+1] ) j++;
|
||||
if( aHeap[i]<aHeap[j] ) break;
|
||||
x = aHeap[i];
|
||||
aHeap[i] = aHeap[j];
|
||||
aHeap[j] = x;
|
||||
i = j;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
/*
|
||||
** Do various sanity checks on a single page of a tree. Return
|
||||
@@ -8528,7 +8611,8 @@ static int checkTreePage(
|
||||
u8 *data;
|
||||
BtShared *pBt;
|
||||
int usableSize;
|
||||
char *hit = 0;
|
||||
u32 *heap = 0;
|
||||
u32 x, prev = 0;
|
||||
i64 nMinKey = 0;
|
||||
i64 nMaxKey = 0;
|
||||
const char *saved_zPfx = pCheck->zPfx;
|
||||
@@ -8673,15 +8757,15 @@ static int checkTreePage(
|
||||
*/
|
||||
data = pPage->aData;
|
||||
hdr = pPage->hdrOffset;
|
||||
hit = sqlite3PageMalloc( pBt->pageSize );
|
||||
heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
|
||||
pCheck->zPfx = 0;
|
||||
if( hit==0 ){
|
||||
if( heap==0 ){
|
||||
pCheck->mallocFailed = 1;
|
||||
}else{
|
||||
int contentOffset = get2byteNotZero(&data[hdr+5]);
|
||||
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
|
||||
memset(hit+contentOffset, 0, usableSize-contentOffset);
|
||||
memset(hit, 1, contentOffset);
|
||||
heap[0] = 0;
|
||||
btreeHeapInsert(heap, contentOffset-1);
|
||||
/* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
|
||||
** number of cells on the page. */
|
||||
nCell = get2byte(&data[hdr+3]);
|
||||
@@ -8693,7 +8777,6 @@ static int checkTreePage(
|
||||
for(i=0; i<nCell; i++){
|
||||
int pc = get2byte(&data[cellStart+i*2]);
|
||||
u32 size = 65536;
|
||||
int j;
|
||||
if( pc<=usableSize-4 ){
|
||||
size = cellSizePtr(pPage, &data[pc]);
|
||||
}
|
||||
@@ -8702,7 +8785,7 @@ static int checkTreePage(
|
||||
checkAppendMsg(pCheck,
|
||||
"Corruption detected in cell %d on page %d",i,iPage);
|
||||
}else{
|
||||
for(j=pc+size-1; j>=pc; j--) hit[j]++;
|
||||
btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
|
||||
}
|
||||
}
|
||||
/* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
|
||||
@@ -8714,7 +8797,7 @@ static int checkTreePage(
|
||||
assert( i<=usableSize-4 ); /* Enforced by btreeInitPage() */
|
||||
size = get2byte(&data[i+2]);
|
||||
assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */
|
||||
for(j=i+size-1; j>=i; j--) hit[j]++;
|
||||
btreeHeapInsert(heap, (i<<16)|(i+size-1));
|
||||
/* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
|
||||
** big-endian integer which is the offset in the b-tree page of the next
|
||||
** freeblock in the chain, or zero if the freeblock is the last on the
|
||||
@@ -8726,27 +8809,33 @@ static int checkTreePage(
|
||||
assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */
|
||||
i = j;
|
||||
}
|
||||
for(i=cnt=0; i<usableSize; i++){
|
||||
if( hit[i]==0 ){
|
||||
cnt++;
|
||||
}else if( hit[i]>1 ){
|
||||
cnt = 0;
|
||||
assert( heap[0]>0 );
|
||||
assert( (heap[1]>>16)==0 );
|
||||
btreeHeapPull(heap,&prev);
|
||||
while( btreeHeapPull(heap,&x) ){
|
||||
if( (prev&0xffff)+1>(x>>16) ){
|
||||
checkAppendMsg(pCheck,
|
||||
"Multiple uses for byte %d of page %d", i, iPage);
|
||||
"Multiple uses for byte %u of page %d", x>>16, iPage);
|
||||
break;
|
||||
}else{
|
||||
cnt += (x>>16) - (prev&0xffff) - 1;
|
||||
prev = x;
|
||||
}
|
||||
}
|
||||
cnt += usableSize - (prev&0xffff) - 1;
|
||||
/* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments
|
||||
** is stored in the fifth field of the b-tree page header.
|
||||
** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
|
||||
** number of fragmented free bytes within the cell content area.
|
||||
*/
|
||||
if( cnt!=data[hdr+7] ){
|
||||
if( heap[0]==0 && cnt!=data[hdr+7] ){
|
||||
checkAppendMsg(pCheck,
|
||||
"Fragmentation of %d bytes reported as %d on page %d",
|
||||
cnt, data[hdr+7], iPage);
|
||||
}
|
||||
}
|
||||
sqlite3PageFree(hit);
|
||||
sqlite3PageFree(heap);
|
||||
releasePage(pPage);
|
||||
|
||||
end_of_check:
|
||||
@@ -8810,8 +8899,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
}
|
||||
i = PENDING_BYTE_PAGE(pBt);
|
||||
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
|
||||
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
|
||||
sCheck.errMsg.useMalloc = 2;
|
||||
sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
|
||||
|
||||
/* Check the integrity of the freelist
|
||||
*/
|
||||
@@ -9128,14 +9216,23 @@ int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
|
||||
+15
-4
@@ -73,10 +73,8 @@ int sqlite3BtreeGetPageSize(Btree*);
|
||||
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);
|
||||
@@ -154,8 +152,18 @@ int sqlite3BtreeNewDb(Btree *p);
|
||||
/*
|
||||
** 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 */
|
||||
@@ -201,6 +209,9 @@ void sqlite3BtreeIncrblobCursor(BtCursor *);
|
||||
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);
|
||||
|
||||
|
||||
@@ -280,6 +280,7 @@ struct MemPage {
|
||||
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 */
|
||||
@@ -418,6 +419,9 @@ struct BtShared {
|
||||
#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 */
|
||||
|
||||
+21
-21
@@ -142,9 +142,11 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
|
||||
assert( pParse->pToplevel==0 );
|
||||
db = pParse->db;
|
||||
if( db->mallocFailed ) return;
|
||||
if( pParse->nested ) return;
|
||||
if( pParse->nErr ) return;
|
||||
if( db->mallocFailed || pParse->nErr ){
|
||||
if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin by generating some termination code at the end of the
|
||||
** vdbe program
|
||||
@@ -226,7 +228,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
|
||||
/* Get the VDBE program ready for execution
|
||||
*/
|
||||
if( v && ALWAYS(pParse->nErr==0) && !db->mallocFailed ){
|
||||
if( v && pParse->nErr==0 && !db->mallocFailed ){
|
||||
assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
|
||||
/* A minimum of one cursor is required if autoincrement is used
|
||||
* See ticket [a696379c1f08866] */
|
||||
@@ -308,10 +310,6 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
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
|
||||
@@ -765,14 +763,12 @@ int sqlite3TwoPartName(
|
||||
if( ALWAYS(pName2!=0) && pName2->n>0 ){
|
||||
if( db->init.busy ) {
|
||||
sqlite3ErrorMsg(pParse, "corrupt database");
|
||||
pParse->nErr++;
|
||||
return -1;
|
||||
}
|
||||
*pUnqual = pName2;
|
||||
iDb = sqlite3FindDb(db, pName1);
|
||||
if( iDb<0 ){
|
||||
sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
|
||||
pParse->nErr++;
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
@@ -931,7 +927,7 @@ void sqlite3StartTable(
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
||||
}else{
|
||||
assert( !db->init.busy );
|
||||
assert( !db->init.busy || CORRUPT_DB );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
}
|
||||
goto begin_table_error;
|
||||
@@ -1220,7 +1216,8 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){
|
||||
p = pParse->pNewTable;
|
||||
if( p==0 || NEVER(p->nCol<1) ) return;
|
||||
pCol = &p->aCol[p->nCol-1];
|
||||
assert( pCol->zType==0 );
|
||||
assert( pCol->zType==0 || CORRUPT_DB );
|
||||
sqlite3DbFree(pParse->db, pCol->zType);
|
||||
pCol->zType = sqlite3NameFromToken(pParse->db, pType);
|
||||
pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
|
||||
}
|
||||
@@ -1731,11 +1728,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
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;
|
||||
@@ -2451,6 +2451,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
}
|
||||
assert( pParse->nErr==0 );
|
||||
assert( pName->nSrc==1 );
|
||||
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
||||
if( noErr ) db->suppressErr++;
|
||||
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
|
||||
if( noErr ) db->suppressErr--;
|
||||
@@ -2764,7 +2765,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
|
||||
@@ -2857,8 +2859,7 @@ Index *sqlite3CreateIndex(
|
||||
char *zExtra = 0; /* Extra space after the Index object */
|
||||
Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
|
||||
|
||||
assert( pParse->nErr==0 ); /* Never called with prior errors */
|
||||
if( db->mallocFailed || IN_DECLARE_VTAB ){
|
||||
if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
@@ -3184,6 +3185,7 @@ Index *sqlite3CreateIndex(
|
||||
pIdx->onError = pIndex->onError;
|
||||
}
|
||||
}
|
||||
pRet = pIdx;
|
||||
goto exit_create_index;
|
||||
}
|
||||
}
|
||||
@@ -3776,7 +3778,6 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
|
||||
void sqlite3SrcListShiftJoinType(SrcList *p){
|
||||
if( p ){
|
||||
int i;
|
||||
assert( p->a || p->nSrc==0 );
|
||||
for(i=p->nSrc-1; i>0; i--){
|
||||
p->a[i].jointype = p->a[i-1].jointype;
|
||||
}
|
||||
@@ -4023,8 +4024,7 @@ void sqlite3UniqueConstraint(
|
||||
StrAccum errMsg;
|
||||
Table *pTab = pIdx->pTable;
|
||||
|
||||
sqlite3StrAccumInit(&errMsg, 0, 0, 200);
|
||||
errMsg.db = pParse->db;
|
||||
sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
|
||||
for(j=0; j<pIdx->nKeyCol; j++){
|
||||
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
|
||||
if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
|
||||
|
||||
+1
-1
@@ -269,7 +269,7 @@ int sqlite3_complete(const char *zSql){
|
||||
int sqlite3_complete16(const void *zSql){
|
||||
sqlite3_value *pVal;
|
||||
char const *zSql8;
|
||||
int rc = SQLITE_NOMEM;
|
||||
int rc;
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
rc = sqlite3_initialize();
|
||||
|
||||
@@ -75,6 +75,9 @@ static const char * const azCompileOpt[] = {
|
||||
#if SQLITE_ENABLE_COLUMN_METADATA
|
||||
"ENABLE_COLUMN_METADATA",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_DBSTAT_VTAB
|
||||
"ENABLE_DBSTAT_VTAB",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_EXPENSIVE_ASSERT
|
||||
"ENABLE_EXPENSIVE_ASSERT",
|
||||
#endif
|
||||
|
||||
+116
-107
@@ -18,11 +18,9 @@
|
||||
** for an example implementation.
|
||||
*/
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
# include "sqliteInt.h"
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
|
||||
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
#include "sqliteInt.h" /* Requires access to internal data structures */
|
||||
|
||||
/*
|
||||
** Page paths:
|
||||
@@ -124,6 +122,7 @@ struct StatCursor {
|
||||
struct StatTable {
|
||||
sqlite3_vtab base;
|
||||
sqlite3 *db;
|
||||
int iDb; /* Index of database to analyze */
|
||||
};
|
||||
|
||||
#ifndef get2byte
|
||||
@@ -140,15 +139,34 @@ static int statConnect(
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
StatTable *pTab;
|
||||
StatTable *pTab = 0;
|
||||
int rc = SQLITE_OK;
|
||||
int iDb;
|
||||
|
||||
pTab = (StatTable *)sqlite3_malloc(sizeof(StatTable));
|
||||
memset(pTab, 0, sizeof(StatTable));
|
||||
pTab->db = db;
|
||||
if( argc>=4 ){
|
||||
iDb = sqlite3FindDbName(db, argv[3]);
|
||||
if( iDb<0 ){
|
||||
*pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}else{
|
||||
iDb = 0;
|
||||
}
|
||||
rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
|
||||
if( pTab==0 ) rc = SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
sqlite3_declare_vtab(db, VTAB_SCHEMA);
|
||||
*ppVtab = &pTab->base;
|
||||
return SQLITE_OK;
|
||||
assert( rc==SQLITE_OK || pTab==0 );
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(pTab, 0, sizeof(StatTable));
|
||||
pTab->db = db;
|
||||
pTab->iDb = iDb;
|
||||
}
|
||||
|
||||
*ppVtab = (sqlite3_vtab*)pTab;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -195,33 +213,45 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
StatCursor *pCsr;
|
||||
int rc;
|
||||
|
||||
pCsr = (StatCursor *)sqlite3_malloc(sizeof(StatCursor));
|
||||
memset(pCsr, 0, sizeof(StatCursor));
|
||||
pCsr->base.pVtab = pVTab;
|
||||
pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
|
||||
if( pCsr==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
char *zSql;
|
||||
memset(pCsr, 0, sizeof(StatCursor));
|
||||
pCsr->base.pVtab = pVTab;
|
||||
|
||||
rc = sqlite3_prepare_v2(pTab->db,
|
||||
"SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
|
||||
" UNION ALL "
|
||||
"SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0"
|
||||
" ORDER BY name", -1,
|
||||
&pCsr->pStmt, 0
|
||||
);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(pCsr);
|
||||
return rc;
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
|
||||
" UNION ALL "
|
||||
"SELECT name, rootpage, type"
|
||||
" FROM \"%w\".sqlite_master WHERE rootpage!=0"
|
||||
" ORDER BY name", pTab->db->aDb[pTab->iDb].zName);
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(pCsr);
|
||||
pCsr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void statClearPage(StatPage *p){
|
||||
int i;
|
||||
for(i=0; i<p->nCell; i++){
|
||||
sqlite3_free(p->aCell[i].aOvfl);
|
||||
if( p->aCell ){
|
||||
for(i=0; i<p->nCell; i++){
|
||||
sqlite3_free(p->aCell[i].aOvfl);
|
||||
}
|
||||
sqlite3_free(p->aCell);
|
||||
}
|
||||
sqlite3PagerUnref(p->pPg);
|
||||
sqlite3_free(p->aCell);
|
||||
sqlite3_free(p->zPath);
|
||||
memset(p, 0, sizeof(StatPage));
|
||||
}
|
||||
@@ -301,9 +331,13 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
|
||||
if( p->nCell ){
|
||||
int i; /* Used to iterate through cells */
|
||||
int nUsable = szPage - sqlite3BtreeGetReserve(pBt);
|
||||
int nUsable; /* Usable bytes per page */
|
||||
|
||||
p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell));
|
||||
sqlite3BtreeEnter(pBt);
|
||||
nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
|
||||
sqlite3BtreeLeave(pBt);
|
||||
p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
|
||||
if( p->aCell==0 ) return SQLITE_NOMEM;
|
||||
memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
|
||||
|
||||
for(i=0; i<p->nCell; i++){
|
||||
@@ -335,7 +369,8 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
|
||||
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
|
||||
pCell->nOvfl = nOvfl;
|
||||
pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl);
|
||||
pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
|
||||
if( pCell->aOvfl==0 ) return SQLITE_NOMEM;
|
||||
pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
|
||||
for(j=1; j<nOvfl; j++){
|
||||
int rc;
|
||||
@@ -363,7 +398,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
*/
|
||||
static void statSizeAndOffset(StatCursor *pCsr){
|
||||
StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
|
||||
Btree *pBt = pTab->db->aDb[0].pBt;
|
||||
Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
|
||||
Pager *pPager = sqlite3BtreePager(pBt);
|
||||
sqlite3_file *fd;
|
||||
sqlite3_int64 x[2];
|
||||
@@ -377,7 +412,7 @@ static void statSizeAndOffset(StatCursor *pCsr){
|
||||
*/
|
||||
fd = sqlite3PagerFile(pPager);
|
||||
x[0] = pCsr->iPageno;
|
||||
if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
|
||||
if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
|
||||
pCsr->iOffset = x[0];
|
||||
pCsr->szPage = (int)x[1];
|
||||
}
|
||||
@@ -389,9 +424,10 @@ static void statSizeAndOffset(StatCursor *pCsr){
|
||||
static int statNext(sqlite3_vtab_cursor *pCursor){
|
||||
int rc;
|
||||
int nPayload;
|
||||
char *z;
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
StatTable *pTab = (StatTable *)pCursor->pVtab;
|
||||
Btree *pBt = pTab->db->aDb[0].pBt;
|
||||
Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
|
||||
Pager *pPager = sqlite3BtreePager(pBt);
|
||||
|
||||
sqlite3_free(pCsr->zPath);
|
||||
@@ -411,8 +447,9 @@ statNextRestart:
|
||||
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
|
||||
pCsr->aPage[0].iPgno = iRoot;
|
||||
pCsr->aPage[0].iCell = 0;
|
||||
pCsr->aPage[0].zPath = sqlite3_mprintf("/");
|
||||
pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
|
||||
pCsr->iPage = 0;
|
||||
if( z==0 ) rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pCsr->isEof = 1;
|
||||
return sqlite3_reset(pCsr->pStmt);
|
||||
@@ -425,13 +462,17 @@ statNextRestart:
|
||||
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";
|
||||
pCsr->nCell = 0;
|
||||
pCsr->nMxPayload = 0;
|
||||
pCsr->zPath = sqlite3_mprintf(
|
||||
pCsr->zPath = z = sqlite3_mprintf(
|
||||
"%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
|
||||
);
|
||||
if( pCell->iOvfl<pCell->nOvfl-1 ){
|
||||
@@ -443,7 +484,7 @@ statNextRestart:
|
||||
}
|
||||
pCell->iOvfl++;
|
||||
statSizeAndOffset(pCsr);
|
||||
return SQLITE_OK;
|
||||
return z==0 ? SQLITE_NOMEM : SQLITE_OK;
|
||||
}
|
||||
if( p->iRightChildPg ) break;
|
||||
p->iCell++;
|
||||
@@ -465,8 +506,9 @@ statNextRestart:
|
||||
}
|
||||
rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
|
||||
p[1].iCell = 0;
|
||||
p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
|
||||
p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
|
||||
p->iCell++;
|
||||
if( z==0 ) rc = SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
|
||||
@@ -479,31 +521,34 @@ statNextRestart:
|
||||
pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
|
||||
pCsr->iPageno = p->iPgno;
|
||||
|
||||
statDecodePage(pBt, p);
|
||||
statSizeAndOffset(pCsr);
|
||||
rc = statDecodePage(pBt, p);
|
||||
if( rc==SQLITE_OK ){
|
||||
statSizeAndOffset(pCsr);
|
||||
|
||||
switch( p->flags ){
|
||||
case 0x05: /* table internal */
|
||||
case 0x02: /* index internal */
|
||||
pCsr->zPagetype = "internal";
|
||||
break;
|
||||
case 0x0D: /* table leaf */
|
||||
case 0x0A: /* index leaf */
|
||||
pCsr->zPagetype = "leaf";
|
||||
break;
|
||||
default:
|
||||
pCsr->zPagetype = "corrupted";
|
||||
break;
|
||||
switch( p->flags ){
|
||||
case 0x05: /* table internal */
|
||||
case 0x02: /* index internal */
|
||||
pCsr->zPagetype = "internal";
|
||||
break;
|
||||
case 0x0D: /* table leaf */
|
||||
case 0x0A: /* index leaf */
|
||||
pCsr->zPagetype = "leaf";
|
||||
break;
|
||||
default:
|
||||
pCsr->zPagetype = "corrupted";
|
||||
break;
|
||||
}
|
||||
pCsr->nCell = p->nCell;
|
||||
pCsr->nUnused = p->nUnused;
|
||||
pCsr->nMxPayload = p->nMxPayload;
|
||||
pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
|
||||
if( z==0 ) rc = SQLITE_NOMEM;
|
||||
nPayload = 0;
|
||||
for(i=0; i<p->nCell; i++){
|
||||
nPayload += p->aCell[i].nLocal;
|
||||
}
|
||||
pCsr->nPayload = nPayload;
|
||||
}
|
||||
pCsr->nCell = p->nCell;
|
||||
pCsr->nUnused = p->nUnused;
|
||||
pCsr->nMxPayload = p->nMxPayload;
|
||||
pCsr->zPath = sqlite3_mprintf("%s", p->zPath);
|
||||
nPayload = 0;
|
||||
for(i=0; i<p->nCell; i++){
|
||||
nPayload += p->aCell[i].nLocal;
|
||||
}
|
||||
pCsr->nPayload = nPayload;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -533,7 +578,7 @@ static int statColumn(
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
switch( i ){
|
||||
case 0: /* name */
|
||||
sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_STATIC);
|
||||
sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
|
||||
break;
|
||||
case 1: /* path */
|
||||
sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
|
||||
@@ -559,7 +604,8 @@ static int statColumn(
|
||||
case 8: /* pgoffset */
|
||||
sqlite3_result_int64(ctx, pCsr->iOffset);
|
||||
break;
|
||||
case 9: /* pgsize */
|
||||
default: /* pgsize */
|
||||
assert( i==9 );
|
||||
sqlite3_result_int(ctx, pCsr->szPage);
|
||||
break;
|
||||
}
|
||||
@@ -572,6 +618,9 @@ static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this routine to register the "dbstat" virtual table module
|
||||
*/
|
||||
int sqlite3_dbstat_register(sqlite3 *db){
|
||||
static sqlite3_module dbstat_module = {
|
||||
0, /* iVersion */
|
||||
@@ -595,46 +644,6 @@ int sqlite3_dbstat_register(sqlite3 *db){
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
|
||||
return SQLITE_OK;
|
||||
return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_TEST) || TCLSH==2
|
||||
#include <tcl.h>
|
||||
|
||||
static int test_dbstat(
|
||||
void *clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||
Tcl_AppendResult(interp, "dbstat not available because of "
|
||||
"SQLITE_OMIT_VIRTUALTABLE", (void*)0);
|
||||
return TCL_ERROR;
|
||||
#else
|
||||
struct SqliteDb { sqlite3 *db; };
|
||||
char *zDb;
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
zDb = Tcl_GetString(objv[1]);
|
||||
if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
|
||||
sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
|
||||
sqlite3_dbstat_register(db);
|
||||
}
|
||||
return TCL_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SqlitetestStat_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* if defined(SQLITE_TEST) || TCLSH==2 */
|
||||
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
|
||||
+1
-1
@@ -189,7 +189,7 @@ Expr *sqlite3LimitWhere(
|
||||
|
||||
pInClause->x.pSelect = pSelect;
|
||||
pInClause->flags |= EP_xIsSelect;
|
||||
sqlite3ExprSetHeight(pParse, pInClause);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, pInClause);
|
||||
return pInClause;
|
||||
|
||||
/* something went wrong. clean up anything allocated. */
|
||||
|
||||
+70
-19
@@ -69,10 +69,11 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
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;
|
||||
@@ -86,7 +87,7 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
|
||||
assert( zC!=0 );
|
||||
s.z = zC;
|
||||
s.n = sqlite3Strlen30(s.z);
|
||||
return sqlite3ExprAddCollateToken(pParse, pExpr, &s);
|
||||
return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -132,9 +133,9 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
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 */
|
||||
@@ -146,10 +147,25 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
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;
|
||||
@@ -355,6 +371,9 @@ static void heightOfSelect(Select *p, int *pnHeight){
|
||||
** 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;
|
||||
@@ -362,8 +381,9 @@ static void exprSetHeight(Expr *p){
|
||||
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;
|
||||
}
|
||||
@@ -372,8 +392,12 @@ static void exprSetHeight(Expr *p){
|
||||
** 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);
|
||||
}
|
||||
@@ -387,8 +411,17 @@ int sqlite3SelectExprHeight(Select *p){
|
||||
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 */
|
||||
|
||||
/*
|
||||
@@ -490,11 +523,11 @@ void sqlite3ExprAttachSubtrees(
|
||||
}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);
|
||||
}
|
||||
@@ -594,7 +627,7 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
|
||||
}
|
||||
pNew->x.pList = pList;
|
||||
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
|
||||
sqlite3ExprSetHeight(pParse, pNew);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, pNew);
|
||||
return pNew;
|
||||
}
|
||||
|
||||
@@ -1209,6 +1242,22 @@ void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
||||
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++){
|
||||
Expr *pExpr = pList->a[i].pExpr;
|
||||
if( ALWAYS(pExpr) ) m |= 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
|
||||
@@ -1249,7 +1298,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
** 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;
|
||||
@@ -1643,7 +1692,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||
** ephemeral table.
|
||||
*/
|
||||
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||
if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
|
||||
if( pParse->nErr==0 && isCandidateForInOpt(p) ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
@@ -1968,6 +2017,7 @@ int sqlite3CodeSubselect(
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
|
||||
&sqlite3IntTokens[1]);
|
||||
pSel->iLimit = 0;
|
||||
pSel->selFlags &= ~SF_MultiValue;
|
||||
if( sqlite3Select(pParse, pSel, &dest) ){
|
||||
return 0;
|
||||
}
|
||||
@@ -2256,7 +2306,8 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
||||
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
|
||||
@@ -3332,7 +3383,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
break;
|
||||
}
|
||||
case TK_ID: {
|
||||
sqlite3TreeViewLine(pView,"ID %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
@@ -3967,7 +4018,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
|
||||
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2;
|
||||
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
|
||||
if( ALWAYS((combinedFlags & EP_Reduced)==0) ){
|
||||
if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){
|
||||
if( pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( pA->iTable!=pB->iTable
|
||||
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
|
||||
|
||||
+14
-14
@@ -1184,7 +1184,8 @@ static Trigger *fkActionTrigger(
|
||||
|
||||
iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
|
||||
assert( iFromCol>=0 );
|
||||
tToCol.z = pIdx ? pTab->aCol[pIdx->aiColumn[i]].zName : "oid";
|
||||
assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
|
||||
tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
|
||||
tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
|
||||
|
||||
tToCol.n = sqlite3Strlen30(tToCol.z);
|
||||
@@ -1196,10 +1197,10 @@ static Trigger *fkActionTrigger(
|
||||
** parent table are used for the comparison. */
|
||||
pEq = sqlite3PExpr(pParse, TK_EQ,
|
||||
sqlite3PExpr(pParse, TK_DOT,
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld),
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol)
|
||||
sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
|
||||
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
|
||||
, 0),
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tFromCol)
|
||||
sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0)
|
||||
, 0);
|
||||
pWhere = sqlite3ExprAnd(db, pWhere, pEq);
|
||||
|
||||
@@ -1211,12 +1212,12 @@ static Trigger *fkActionTrigger(
|
||||
if( pChanges ){
|
||||
pEq = sqlite3PExpr(pParse, TK_IS,
|
||||
sqlite3PExpr(pParse, TK_DOT,
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld),
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol),
|
||||
sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
|
||||
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
|
||||
0),
|
||||
sqlite3PExpr(pParse, TK_DOT,
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew),
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol),
|
||||
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
|
||||
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
|
||||
0),
|
||||
0);
|
||||
pWhen = sqlite3ExprAnd(db, pWhen, pEq);
|
||||
@@ -1226,8 +1227,8 @@ static Trigger *fkActionTrigger(
|
||||
Expr *pNew;
|
||||
if( action==OE_Cascade ){
|
||||
pNew = sqlite3PExpr(pParse, TK_DOT,
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew),
|
||||
sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol)
|
||||
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
|
||||
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
|
||||
, 0);
|
||||
}else if( action==OE_SetDflt ){
|
||||
Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
|
||||
@@ -1274,13 +1275,12 @@ static Trigger *fkActionTrigger(
|
||||
pTrigger = (Trigger *)sqlite3DbMallocZero(db,
|
||||
sizeof(Trigger) + /* struct Trigger */
|
||||
sizeof(TriggerStep) + /* Single step in trigger program */
|
||||
nFrom + 1 /* Space for pStep->target.z */
|
||||
nFrom + 1 /* Space for pStep->zTarget */
|
||||
);
|
||||
if( pTrigger ){
|
||||
pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
|
||||
pStep->target.z = (char *)&pStep[1];
|
||||
pStep->target.n = nFrom;
|
||||
memcpy((char *)pStep->target.z, zFrom, nFrom);
|
||||
pStep->zTarget = (char *)&pStep[1];
|
||||
memcpy((char *)pStep->zTarget, zFrom, nFrom);
|
||||
|
||||
pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
|
||||
|
||||
+22
-8
@@ -22,7 +22,9 @@
|
||||
** 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;
|
||||
@@ -230,13 +232,13 @@ static void printfFunc(
|
||||
StrAccum str;
|
||||
const char *zFormat;
|
||||
int n;
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
|
||||
if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){
|
||||
x.nArg = argc-1;
|
||||
x.nUsed = 0;
|
||||
x.apArg = argv+1;
|
||||
sqlite3StrAccumInit(&str, 0, 0, SQLITE_MAX_LENGTH);
|
||||
str.db = sqlite3_context_db_handle(context);
|
||||
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
|
||||
sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x);
|
||||
n = str.nChar;
|
||||
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
|
||||
@@ -291,6 +293,14 @@ static void substrFunc(
|
||||
}
|
||||
}
|
||||
}
|
||||
#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 ){
|
||||
@@ -378,7 +388,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Allocate nByte bytes of space using sqlite3_malloc(). If the
|
||||
** Allocate nByte bytes of space using sqlite3Malloc(). If the
|
||||
** allocation fails, call sqlite3_result_error_nomem() to notify
|
||||
** the database handle that malloc() has failed and return NULL.
|
||||
** If nByte is larger than the maximum string or blob length, then
|
||||
@@ -1047,7 +1057,7 @@ static void charFunc(
|
||||
){
|
||||
unsigned char *z, *zOut;
|
||||
int i;
|
||||
zOut = z = sqlite3_malloc( argc*4+1 );
|
||||
zOut = z = sqlite3_malloc64( argc*4+1 );
|
||||
if( z==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
@@ -1195,7 +1205,7 @@ static void replaceFunc(
|
||||
return;
|
||||
}
|
||||
zOld = zOut;
|
||||
zOut = sqlite3_realloc(zOut, (int)nOut);
|
||||
zOut = sqlite3_realloc64(zOut, (int)nOut);
|
||||
if( zOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
sqlite3_free(zOld);
|
||||
@@ -1557,8 +1567,7 @@ static void groupConcatStep(
|
||||
|
||||
if( pAccum ){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
int firstTerm = pAccum->useMalloc==0;
|
||||
pAccum->useMalloc = 2;
|
||||
int firstTerm = pAccum->mxAlloc==0;
|
||||
pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
|
||||
if( !firstTerm ){
|
||||
if( argc==2 ){
|
||||
@@ -1656,6 +1665,11 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
||||
** 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;
|
||||
|
||||
+5
-5
@@ -46,16 +46,16 @@ const unsigned char sqlite3UpperToLower[] = {
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
+60
-24
@@ -342,20 +342,23 @@ static int xferOptimization(
|
||||
/*
|
||||
** This routine is called to handle SQL of the following forms:
|
||||
**
|
||||
** insert into TABLE (IDLIST) values(EXPRLIST)
|
||||
** insert into TABLE (IDLIST) values(EXPRLIST),(EXPRLIST),...
|
||||
** insert into TABLE (IDLIST) select
|
||||
** insert into TABLE (IDLIST) default values
|
||||
**
|
||||
** The IDLIST following the table name is always optional. If omitted,
|
||||
** then a list of all columns for the table is substituted. The IDLIST
|
||||
** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted.
|
||||
** then a list of all (non-hidden) columns for the table is substituted.
|
||||
** The IDLIST appears in the pColumn parameter. pColumn is NULL if IDLIST
|
||||
** is omitted.
|
||||
**
|
||||
** The pList parameter holds EXPRLIST in the first form of the INSERT
|
||||
** statement above, and pSelect is NULL. For the second form, pList is
|
||||
** NULL and pSelect is a pointer to the select statement used to generate
|
||||
** data for the insert.
|
||||
** For the pSelect parameter holds the values to be inserted for the
|
||||
** first two forms shown above. A VALUES clause is really just short-hand
|
||||
** for a SELECT statement that omits the FROM clause and everything else
|
||||
** that follows. If the pSelect parameter is NULL, that means that the
|
||||
** DEFAULT VALUES form of the INSERT statement is intended.
|
||||
**
|
||||
** The code generated follows one of four templates. For a simple
|
||||
** insert with data coming from a VALUES clause, the code executes
|
||||
** insert with data coming from a single-row VALUES clause, the code executes
|
||||
** once straight down through. Pseudo-code follows (we call this
|
||||
** the "1st template"):
|
||||
**
|
||||
@@ -462,7 +465,7 @@ void sqlite3Insert(
|
||||
u8 useTempTable = 0; /* Store SELECT results in intermediate table */
|
||||
u8 appendFlag = 0; /* True if the insert is likely to be an append */
|
||||
u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
|
||||
u8 bIdListInOrder = 1; /* True if IDLIST is in table order */
|
||||
u8 bIdListInOrder; /* True if IDLIST is in table order */
|
||||
ExprList *pList = 0; /* List of VALUES() to be inserted */
|
||||
|
||||
/* Register allocations */
|
||||
@@ -487,8 +490,8 @@ void sqlite3Insert(
|
||||
}
|
||||
|
||||
/* If the Select object is really just a simple VALUES() list with a
|
||||
** single row values (the common case) then keep that one row of values
|
||||
** and go ahead and discard the Select object
|
||||
** single row (the common case) then keep that one row of values
|
||||
** and discard the other (unused) parts of the pSelect object
|
||||
*/
|
||||
if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){
|
||||
pList = pSelect->pEList;
|
||||
@@ -596,6 +599,7 @@ void sqlite3Insert(
|
||||
** is appears in the original table. (The index of the INTEGER
|
||||
** PRIMARY KEY in the original table is pTab->iPKey.)
|
||||
*/
|
||||
bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0;
|
||||
if( pColumn ){
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
pColumn->a[i].idx = -1;
|
||||
@@ -631,7 +635,8 @@ void sqlite3Insert(
|
||||
** co-routine is the common header to the 3rd and 4th templates.
|
||||
*/
|
||||
if( pSelect ){
|
||||
/* Data is coming from a SELECT. Generate a co-routine to run the SELECT */
|
||||
/* Data is coming from a SELECT or from a multi-row VALUES clause.
|
||||
** Generate a co-routine to run the SELECT. */
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int rc; /* Result code */
|
||||
@@ -644,8 +649,7 @@ void sqlite3Insert(
|
||||
dest.nSdst = pTab->nCol;
|
||||
rc = sqlite3Select(pParse, pSelect, &dest);
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( rc || db->mallocFailed ) goto insert_cleanup;
|
||||
if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
||||
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
||||
assert( pSelect->pEList );
|
||||
@@ -693,8 +697,8 @@ void sqlite3Insert(
|
||||
sqlite3ReleaseTempReg(pParse, regTempRowid);
|
||||
}
|
||||
}else{
|
||||
/* This is the case if the data for the INSERT is coming from a VALUES
|
||||
** clause
|
||||
/* This is the case if the data for the INSERT is coming from a
|
||||
** single-row VALUES clause
|
||||
*/
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
@@ -1765,6 +1769,7 @@ static int xferOptimization(
|
||||
int onError, /* How to handle constraint errors */
|
||||
int iDbDest /* The database of pDest */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
ExprList *pEList; /* The result set of the SELECT */
|
||||
Table *pSrc; /* The table in the FROM clause of SELECT */
|
||||
Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
|
||||
@@ -1912,11 +1917,11 @@ static int xferOptimization(
|
||||
** the extra complication to make this rule less restrictive is probably
|
||||
** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
|
||||
*/
|
||||
if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
|
||||
if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if( (pParse->db->flags & SQLITE_CountRows)!=0 ){
|
||||
if( (db->flags & SQLITE_CountRows)!=0 ){
|
||||
return 0; /* xfer opt does not play well with PRAGMA count_changes */
|
||||
}
|
||||
|
||||
@@ -1927,7 +1932,7 @@ static int xferOptimization(
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_xferopt_count++;
|
||||
#endif
|
||||
iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema);
|
||||
iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
sqlite3CodeVerifySchema(pParse, iDbSrc);
|
||||
iSrc = pParse->nTab++;
|
||||
@@ -1937,14 +1942,18 @@ static int xferOptimization(
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
||||
assert( HasRowid(pDest) || destHasUniqueIdx );
|
||||
if( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|
||||
if( (db->flags & SQLITE_Vacuum)==0 && (
|
||||
(pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|
||||
|| destHasUniqueIdx /* (2) */
|
||||
|| (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
|
||||
){
|
||||
)){
|
||||
/* In some circumstances, we are able to run the xfer optimization
|
||||
** only if the destination table is initially empty. This code makes
|
||||
** that determination. Conditions under which the destination must
|
||||
** be empty:
|
||||
** only if the destination table is initially empty. Unless the
|
||||
** SQLITE_Vacuum flag is set, this block generates code to make
|
||||
** that determination. If SQLITE_Vacuum is set, then the destination
|
||||
** table is always empty.
|
||||
**
|
||||
** Conditions under which the destination must be empty:
|
||||
**
|
||||
** (1) There is no INTEGER PRIMARY KEY but there are indices.
|
||||
** (If the destination is not initially empty, the rowid fields
|
||||
@@ -1987,6 +1996,7 @@ static int xferOptimization(
|
||||
sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName);
|
||||
}
|
||||
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
||||
u8 useSeekResult = 0;
|
||||
for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
|
||||
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
||||
}
|
||||
@@ -2000,7 +2010,33 @@ static int xferOptimization(
|
||||
VdbeComment((v, "%s", pDestIdx->zName));
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
|
||||
if( db->flags & SQLITE_Vacuum ){
|
||||
/* This INSERT command is part of a VACUUM operation, which guarantees
|
||||
** that the destination table is empty. If all indexed columns use
|
||||
** collation sequence BINARY, then it can also be assumed that the
|
||||
** index will be populated by inserting keys in strictly sorted
|
||||
** order. In this case, instead of seeking within the b-tree as part
|
||||
** of every OP_IdxInsert opcode, an OP_Last is added before the
|
||||
** OP_IdxInsert to seek to the point within the b-tree where each key
|
||||
** should be inserted. This is faster.
|
||||
**
|
||||
** If any of the indexed columns use a collation sequence other than
|
||||
** BINARY, this optimization is disabled. This is because the user
|
||||
** might change the definition of a collation sequence and then run
|
||||
** a VACUUM command. In that case keys may not be written in strictly
|
||||
** sorted order. */
|
||||
for(i=0; i<pSrcIdx->nColumn; i++){
|
||||
char *zColl = pSrcIdx->azColl[i];
|
||||
assert( zColl!=0 );
|
||||
if( sqlite3_stricmp("BINARY", zColl) ) break;
|
||||
}
|
||||
if( i==pSrcIdx->nColumn ){
|
||||
useSeekResult = OPFLAG_USESEEKRESULT;
|
||||
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
|
||||
sqlite3VdbeChangeP5(v, useSeekResult);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
|
||||
+10
-10
@@ -430,7 +430,7 @@ static int sqlite3LoadExtension(
|
||||
const char *zEntry;
|
||||
char *zAltEntry = 0;
|
||||
void **aHandle;
|
||||
int nMsg = 300 + sqlite3Strlen30(zFile);
|
||||
u64 nMsg = 300 + sqlite3Strlen30(zFile);
|
||||
int ii;
|
||||
|
||||
/* Shared library endings to try if zFile cannot be loaded as written */
|
||||
@@ -473,7 +473,7 @@ static int sqlite3LoadExtension(
|
||||
#endif
|
||||
if( handle==0 ){
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
|
||||
*pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
|
||||
if( zErrmsg ){
|
||||
sqlite3_snprintf(nMsg, zErrmsg,
|
||||
"unable to open shared library [%s]", zFile);
|
||||
@@ -499,7 +499,7 @@ static int sqlite3LoadExtension(
|
||||
if( xInit==0 && zProc==0 ){
|
||||
int iFile, iEntry, c;
|
||||
int ncFile = sqlite3Strlen30(zFile);
|
||||
zAltEntry = sqlite3_malloc(ncFile+30);
|
||||
zAltEntry = sqlite3_malloc64(ncFile+30);
|
||||
if( zAltEntry==0 ){
|
||||
sqlite3OsDlClose(pVfs, handle);
|
||||
return SQLITE_NOMEM;
|
||||
@@ -521,7 +521,7 @@ static int sqlite3LoadExtension(
|
||||
if( xInit==0 ){
|
||||
if( pzErrMsg ){
|
||||
nMsg += sqlite3Strlen30(zEntry);
|
||||
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
|
||||
*pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
|
||||
if( zErrmsg ){
|
||||
sqlite3_snprintf(nMsg, zErrmsg,
|
||||
"no entry point [%s] in shared library [%s]", zEntry, zFile);
|
||||
@@ -620,7 +620,7 @@ static const sqlite3_api_routines sqlite3Apis = { 0 };
|
||||
*/
|
||||
typedef struct sqlite3AutoExtList sqlite3AutoExtList;
|
||||
static SQLITE_WSD struct sqlite3AutoExtList {
|
||||
int nExt; /* Number of entries in aExt[] */
|
||||
u32 nExt; /* Number of entries in aExt[] */
|
||||
void (**aExt)(void); /* Pointers to the extension init functions */
|
||||
} sqlite3Autoext = { 0, 0 };
|
||||
|
||||
@@ -653,7 +653,7 @@ int sqlite3_auto_extension(void (*xInit)(void)){
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
u32 i;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
#endif
|
||||
@@ -663,9 +663,9 @@ int sqlite3_auto_extension(void (*xInit)(void)){
|
||||
if( wsdAutoext.aExt[i]==xInit ) break;
|
||||
}
|
||||
if( i==wsdAutoext.nExt ){
|
||||
int nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
|
||||
u64 nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
|
||||
void (**aNew)(void);
|
||||
aNew = sqlite3_realloc(wsdAutoext.aExt, nByte);
|
||||
aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
|
||||
if( aNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -697,7 +697,7 @@ int sqlite3_cancel_auto_extension(void (*xInit)(void)){
|
||||
int n = 0;
|
||||
wsdAutoextInit;
|
||||
sqlite3_mutex_enter(mutex);
|
||||
for(i=wsdAutoext.nExt-1; i>=0; i--){
|
||||
for(i=(int)wsdAutoext.nExt-1; i>=0; i--){
|
||||
if( wsdAutoext.aExt[i]==xInit ){
|
||||
wsdAutoext.nExt--;
|
||||
wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt];
|
||||
@@ -735,7 +735,7 @@ void sqlite3_reset_auto_extension(void){
|
||||
** If anything goes wrong, set an error in the database connection.
|
||||
*/
|
||||
void sqlite3AutoLoadExtensions(sqlite3 *db){
|
||||
int i;
|
||||
u32 i;
|
||||
int go = 1;
|
||||
int rc;
|
||||
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
|
||||
+102
-22
@@ -55,6 +55,18 @@ int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
|
||||
*/
|
||||
int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
|
||||
|
||||
/*
|
||||
** When compiling the test fixture or with debugging enabled (on Win32),
|
||||
** this variable being set to non-zero will cause OSTRACE macros to emit
|
||||
** extra diagnostic information.
|
||||
*/
|
||||
#ifdef SQLITE_HAVE_OS_TRACE
|
||||
# ifndef SQLITE_DEBUG_OS_TRACE
|
||||
# define SQLITE_DEBUG_OS_TRACE 0
|
||||
# endif
|
||||
int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
|
||||
/*
|
||||
** If the following function pointer is not NULL and if
|
||||
@@ -62,7 +74,7 @@ int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
|
||||
** 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
|
||||
|
||||
/*
|
||||
@@ -128,6 +140,11 @@ int sqlite3_initialize(void){
|
||||
}
|
||||
#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
|
||||
@@ -340,26 +357,28 @@ int sqlite3_config(int op, ...){
|
||||
*/
|
||||
#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
|
||||
@@ -471,7 +490,8 @@ int sqlite3_config(int op, ...){
|
||||
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);
|
||||
@@ -576,7 +596,9 @@ int sqlite3_config(int op, ...){
|
||||
** 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;
|
||||
@@ -1184,7 +1206,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
** Return a static string containing the name corresponding to the error code
|
||||
** specified in the argument.
|
||||
*/
|
||||
#if (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) || defined(SQLITE_TEST)
|
||||
#if defined(SQLITE_NEED_ERR_NAME)
|
||||
const char *sqlite3ErrName(int rc){
|
||||
const char *zName = 0;
|
||||
int i, origRc = rc;
|
||||
@@ -1414,7 +1436,7 @@ int sqlite3_busy_handler(
|
||||
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;
|
||||
@@ -2409,18 +2431,30 @@ int sqlite3ParseUri(
|
||||
int eState; /* Parser state when parsing URI */
|
||||
int iIn; /* Input character index */
|
||||
int iOut = 0; /* Output character index */
|
||||
int nByte = nUri+2; /* Bytes of space to allocate */
|
||||
u64 nByte = nUri+2; /* Bytes of space to allocate */
|
||||
|
||||
/* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
|
||||
** method that there may be extra parameters following the file-name. */
|
||||
flags |= SQLITE_OPEN_URI;
|
||||
|
||||
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
|
||||
zFile = sqlite3_malloc(nByte);
|
||||
zFile = sqlite3_malloc64(nByte);
|
||||
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;
|
||||
@@ -2570,7 +2604,7 @@ int sqlite3ParseUri(
|
||||
}
|
||||
|
||||
}else{
|
||||
zFile = sqlite3_malloc(nUri+2);
|
||||
zFile = sqlite3_malloc64(nUri+2);
|
||||
if( !zFile ) return SQLITE_NOMEM;
|
||||
memcpy(zFile, zUri, nUri);
|
||||
zFile[nUri] = '\0';
|
||||
@@ -2707,6 +2741,9 @@ static int openDatabase(
|
||||
#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
|
||||
@@ -2839,6 +2876,13 @@ static int openDatabase(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
int sqlite3_dbstat_register(sqlite3*);
|
||||
rc = sqlite3_dbstat_register(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
|
||||
** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
|
||||
** mode. Doing nothing at all also makes NORMAL the default.
|
||||
@@ -2860,7 +2904,8 @@ static int openDatabase(
|
||||
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);
|
||||
@@ -3142,13 +3187,19 @@ int sqlite3_table_column_metadata(
|
||||
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);
|
||||
@@ -3295,7 +3346,7 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3598,6 +3649,35 @@ int sqlite3_test_control(int op, ...){
|
||||
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 */
|
||||
|
||||
+32
-22
@@ -75,6 +75,13 @@ static SQLITE_WSD struct Mem0Global {
|
||||
|
||||
#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
|
||||
@@ -97,7 +104,7 @@ static int sqlite3MemoryAlarm(
|
||||
void *pArg,
|
||||
sqlite3_int64 iThreshold
|
||||
){
|
||||
int nUsed;
|
||||
sqlite3_int64 nUsed;
|
||||
sqlite3_mutex_enter(mem0.mutex);
|
||||
mem0.alarmCallback = xCallback;
|
||||
mem0.alarmArg = pArg;
|
||||
@@ -155,6 +162,7 @@ void sqlite3_soft_heap_limit(int n){
|
||||
** Initialize the memory allocation subsystem.
|
||||
*/
|
||||
int sqlite3MallocInit(void){
|
||||
int rc;
|
||||
if( sqlite3GlobalConfig.m.xMalloc==0 ){
|
||||
sqlite3MemSetDefault();
|
||||
}
|
||||
@@ -190,7 +198,9 @@ int sqlite3MallocInit(void){
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -266,7 +276,7 @@ static int mallocWithAlarm(int n, void **pp){
|
||||
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);
|
||||
@@ -283,8 +293,8 @@ static int mallocWithAlarm(int n, void **pp){
|
||||
#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;
|
||||
@@ -361,14 +371,14 @@ void *sqlite3ScratchMalloc(int n){
|
||||
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);
|
||||
@@ -409,19 +419,19 @@ void sqlite3ScratchFree(void *p){
|
||||
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{
|
||||
@@ -452,7 +462,7 @@ int sqlite3MallocSize(void *p){
|
||||
}
|
||||
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{
|
||||
@@ -461,13 +471,13 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
||||
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);
|
||||
}
|
||||
@@ -478,11 +488,11 @@ sqlite3_uint64 sqlite3_msize(void *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{
|
||||
@@ -523,7 +533,7 @@ void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
}
|
||||
}
|
||||
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);
|
||||
@@ -536,7 +546,7 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
|
||||
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 */
|
||||
}
|
||||
@@ -570,7 +580,7 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
|
||||
}
|
||||
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{
|
||||
@@ -703,7 +713,7 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
|
||||
}
|
||||
}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 ){
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#pragma warning(disable : 4055)
|
||||
#pragma warning(disable : 4100)
|
||||
#pragma warning(disable : 4127)
|
||||
#pragma warning(disable : 4130)
|
||||
#pragma warning(disable : 4152)
|
||||
#pragma warning(disable : 4189)
|
||||
#pragma warning(disable : 4206)
|
||||
|
||||
+13
-4
@@ -120,8 +120,12 @@ static sqlite3_mutex *debugMutexAlloc(int id){
|
||||
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;
|
||||
@@ -136,8 +140,13 @@ static sqlite3_mutex *debugMutexAlloc(int id){
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+18
-13
@@ -40,8 +40,10 @@
|
||||
*/
|
||||
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 */
|
||||
@@ -157,9 +159,6 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
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;
|
||||
@@ -167,9 +166,6 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
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;
|
||||
@@ -182,12 +178,12 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -199,9 +195,18 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+9
-10
@@ -194,8 +194,8 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
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
|
||||
@@ -215,12 +215,9 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
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
|
||||
@@ -239,13 +236,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -29,16 +29,6 @@
|
||||
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
|
||||
# ifndef SQLITE_DEBUG_OS_TRACE
|
||||
# define SQLITE_DEBUG_OS_TRACE 0
|
||||
# endif
|
||||
int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
|
||||
# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
|
||||
#else
|
||||
# define OSTRACE(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros for performance tracing. Normally turned off. Only works
|
||||
** on i486 hardware.
|
||||
|
||||
+202
-173
File diff suppressed because it is too large
Load Diff
+121
-43
@@ -197,8 +197,10 @@ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
|
||||
#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 */
|
||||
|
||||
@@ -1066,6 +1068,32 @@ static struct win_syscall {
|
||||
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 */
|
||||
|
||||
/*
|
||||
@@ -1949,11 +1977,11 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){
|
||||
/*
|
||||
** 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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2433,7 +2461,8 @@ static int winClose(sqlite3_file *id){
|
||||
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);
|
||||
@@ -2462,7 +2491,8 @@ static int winClose(sqlite3_file *id){
|
||||
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);
|
||||
@@ -2490,7 +2520,8 @@ static int winRead(
|
||||
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
|
||||
@@ -2499,7 +2530,8 @@ static int winRead(
|
||||
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);
|
||||
@@ -2513,7 +2545,8 @@ static int winRead(
|
||||
|
||||
#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) ){
|
||||
@@ -2527,19 +2560,22 @@ static int winRead(
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2562,7 +2598,8 @@ static int winWrite(
|
||||
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
|
||||
@@ -2571,7 +2608,8 @@ static int winWrite(
|
||||
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);
|
||||
@@ -2634,17 +2672,20 @@ static int winWrite(
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2658,8 +2699,8 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
|
||||
|
||||
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
|
||||
@@ -2691,7 +2732,8 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -2715,7 +2757,7 @@ static int winSync(sqlite3_file *id, int flags){
|
||||
BOOL rc;
|
||||
#endif
|
||||
#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \
|
||||
(defined(SQLITE_TEST) && defined(SQLITE_DEBUG))
|
||||
defined(SQLITE_HAVE_OS_TRACE)
|
||||
/*
|
||||
** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or
|
||||
** OSTRACE() macros.
|
||||
@@ -2736,8 +2778,9 @@ static int winSync(sqlite3_file *id, int flags){
|
||||
*/
|
||||
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);
|
||||
@@ -2752,19 +2795,38 @@ static int winSync(sqlite3_file *id, int 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
|
||||
}
|
||||
@@ -3372,7 +3434,7 @@ struct winShmNode {
|
||||
int nRef; /* Number of winShm objects pointing to this */
|
||||
winShm *pFirst; /* All winShm objects pointing to this */
|
||||
winShmNode *pNext; /* Next in list of all winShmNode objects */
|
||||
#ifdef SQLITE_DEBUG
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
||||
u8 nextShmId; /* Next available winShm.id value */
|
||||
#endif
|
||||
};
|
||||
@@ -3403,7 +3465,7 @@ struct winShm {
|
||||
u8 hasMutex; /* True if holding the winShmNode mutex */
|
||||
u16 sharedMask; /* Mask of shared locks held */
|
||||
u16 exclMask; /* Mask of exclusive locks held */
|
||||
#ifdef SQLITE_DEBUG
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
||||
u8 id; /* Id of this connection with its winShmNode */
|
||||
#endif
|
||||
};
|
||||
@@ -3594,7 +3656,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
|
||||
/* Make the new connection a child of the winShmNode */
|
||||
p->pShmNode = pShmNode;
|
||||
#ifdef SQLITE_DEBUG
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
||||
p->id = pShmNode->nextShmId++;
|
||||
#endif
|
||||
pShmNode->nRef++;
|
||||
@@ -3814,16 +3876,16 @@ static int winShmMap(
|
||||
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 );
|
||||
@@ -3863,7 +3925,7 @@ static int winShmMap(
|
||||
}
|
||||
|
||||
/* Map the requested memory region into this processes address space. */
|
||||
apNew = (struct ShmRegion *)sqlite3_realloc(
|
||||
apNew = (struct ShmRegion *)sqlite3_realloc64(
|
||||
pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
|
||||
);
|
||||
if( !apNew ){
|
||||
@@ -4735,7 +4797,7 @@ static int winOpen(
|
||||
}
|
||||
}
|
||||
#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"));
|
||||
@@ -4919,7 +4981,7 @@ static int winDelete(
|
||||
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)));
|
||||
@@ -4969,7 +5031,7 @@ static int winAccess(
|
||||
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",
|
||||
@@ -5310,7 +5372,7 @@ static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
int n = 0;
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
#if defined(SQLITE_TEST)
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
|
||||
n = nBuf;
|
||||
memset(zBuf, 0, nBuf);
|
||||
#else
|
||||
@@ -5344,7 +5406,23 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
memcpy(&zBuf[n], &i, sizeof(i));
|
||||
n += sizeof(i);
|
||||
}
|
||||
#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
|
||||
#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -5522,7 +5600,7 @@ int sqlite3_os_init(void){
|
||||
|
||||
/* 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));
|
||||
|
||||
@@ -74,4 +74,15 @@
|
||||
# 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_ */
|
||||
|
||||
+2
-4
@@ -3044,9 +3044,7 @@ static int pagerWalFrames(
|
||||
){
|
||||
int rc; /* Return code */
|
||||
int nList; /* Number of pages in pList */
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
|
||||
PgHdr *p; /* For looping over pages */
|
||||
#endif
|
||||
|
||||
assert( pPager->pWal );
|
||||
assert( pList );
|
||||
@@ -3063,7 +3061,6 @@ static int pagerWalFrames(
|
||||
** any pages with page numbers greater than nTruncate into the WAL file.
|
||||
** They will never be read by any client. So remove them from the pDirty
|
||||
** list here. */
|
||||
PgHdr *p;
|
||||
PgHdr **ppNext = &pList;
|
||||
nList = 0;
|
||||
for(p=pList; (*ppNext = p)!=0; p=p->pDirty){
|
||||
@@ -3083,7 +3080,6 @@ static int pagerWalFrames(
|
||||
pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
|
||||
);
|
||||
if( rc==SQLITE_OK && pPager->pBackup ){
|
||||
PgHdr *p;
|
||||
for(p=pList; p; p=p->pDirty){
|
||||
sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
|
||||
}
|
||||
@@ -7014,6 +7010,8 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
|
||||
}
|
||||
assert( state==pPager->eState );
|
||||
}
|
||||
}else if( eMode==PAGER_JOURNALMODE_OFF ){
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+41
-29
@@ -409,28 +409,35 @@ cmd ::= select(X). {
|
||||
%type oneselect {Select*}
|
||||
%destructor oneselect {sqlite3SelectDelete(pParse->db, $$);}
|
||||
|
||||
select(A) ::= with(W) selectnowith(X). {
|
||||
Select *p = X, *pNext, *pLoop;
|
||||
if( p ){
|
||||
int cnt = 0, mxSelect;
|
||||
p->pWith = W;
|
||||
%include {
|
||||
/*
|
||||
** For a compound SELECT statement, make sure p->pPrior->pNext==p for
|
||||
** all elements in the list. And make sure list length does not exceed
|
||||
** SQLITE_LIMIT_COMPOUND_SELECT.
|
||||
*/
|
||||
static void parserDoubleLinkSelect(Parse *pParse, Select *p){
|
||||
if( p->pPrior ){
|
||||
u16 allValues = SF_Values;
|
||||
pNext = 0;
|
||||
Select *pNext = 0, *pLoop;
|
||||
int mxSelect, cnt = 0;
|
||||
for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
|
||||
pLoop->pNext = pNext;
|
||||
pLoop->selFlags |= SF_Compound;
|
||||
allValues &= pLoop->selFlags;
|
||||
}
|
||||
if( allValues ){
|
||||
p->selFlags |= SF_AllValues;
|
||||
}else if(
|
||||
(mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
|
||||
&& cnt>mxSelect
|
||||
if( (p->selFlags & SF_MultiValue)==0 &&
|
||||
(mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
|
||||
cnt>mxSelect
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select(A) ::= with(W) selectnowith(X). {
|
||||
Select *p = X;
|
||||
if( p ){
|
||||
p->pWith = W;
|
||||
parserDoubleLinkSelect(pParse, p);
|
||||
}else{
|
||||
sqlite3WithDelete(pParse->db, W);
|
||||
}
|
||||
@@ -445,12 +452,14 @@ selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). {
|
||||
SrcList *pFrom;
|
||||
Token x;
|
||||
x.n = 0;
|
||||
parserDoubleLinkSelect(pParse, pRhs);
|
||||
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
|
||||
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
|
||||
}
|
||||
if( pRhs ){
|
||||
pRhs->op = (u8)Y;
|
||||
pRhs->pPrior = X;
|
||||
pRhs->selFlags &= ~SF_MultiValue;
|
||||
if( Y!=TK_ALL ) pParse->hasCompound = 1;
|
||||
}else{
|
||||
sqlite3SelectDelete(pParse->db, X);
|
||||
@@ -498,13 +507,16 @@ values(A) ::= VALUES LP nexprlist(X) RP. {
|
||||
A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0,0);
|
||||
}
|
||||
values(A) ::= values(X) COMMA LP exprlist(Y) RP. {
|
||||
Select *pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values,0,0);
|
||||
Select *pRight, *pLeft = X;
|
||||
pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
|
||||
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
|
||||
if( pRight ){
|
||||
pRight->op = TK_ALL;
|
||||
pRight->pPrior = X;
|
||||
pLeft = X;
|
||||
pRight->pPrior = pLeft;
|
||||
A = pRight;
|
||||
}else{
|
||||
A = X;
|
||||
A = pLeft;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,7 +872,7 @@ expr(A) ::= VARIABLE(X). {
|
||||
spanSet(&A, &X, &X);
|
||||
}
|
||||
expr(A) ::= expr(E) COLLATE ids(C). {
|
||||
A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C);
|
||||
A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C, 1);
|
||||
A.zStart = E.zStart;
|
||||
A.zEnd = &C.z[C.n];
|
||||
}
|
||||
@@ -1078,7 +1090,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pList = Y;
|
||||
sqlite3ExprSetHeight(pParse, A.pExpr);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
}
|
||||
@@ -1091,8 +1103,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pSelect = X;
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect);
|
||||
sqlite3ExprSetHeight(pParse, A.pExpr);
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3SelectDelete(pParse->db, X);
|
||||
}
|
||||
@@ -1103,8 +1115,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pSelect = Y;
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect);
|
||||
sqlite3ExprSetHeight(pParse, A.pExpr);
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3SelectDelete(pParse->db, Y);
|
||||
}
|
||||
@@ -1117,8 +1129,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect);
|
||||
sqlite3ExprSetHeight(pParse, A.pExpr);
|
||||
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3SrcListDelete(pParse->db, pSrc);
|
||||
}
|
||||
@@ -1130,8 +1142,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
Expr *p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
|
||||
if( p ){
|
||||
p->x.pSelect = Y;
|
||||
ExprSetProperty(p, EP_xIsSelect);
|
||||
sqlite3ExprSetHeight(pParse, p);
|
||||
ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, p);
|
||||
}else{
|
||||
sqlite3SelectDelete(pParse->db, Y);
|
||||
}
|
||||
@@ -1145,7 +1157,7 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
|
||||
sqlite3ExprSetHeight(pParse, A.pExpr);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
sqlite3ExprDelete(pParse->db, Z);
|
||||
@@ -1206,14 +1218,14 @@ uniqueflag(A) ::= . {A = OE_None;}
|
||||
idxlist_opt(A) ::= . {A = 0;}
|
||||
idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
|
||||
idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). {
|
||||
Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C);
|
||||
Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1);
|
||||
A = sqlite3ExprListAppend(pParse,X, p);
|
||||
sqlite3ExprListSetName(pParse,A,&Y,1);
|
||||
sqlite3ExprListCheckLength(pParse, A, "index");
|
||||
if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z;
|
||||
}
|
||||
idxlist(A) ::= nm(Y) collate(C) sortorder(Z). {
|
||||
Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C);
|
||||
Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1);
|
||||
A = sqlite3ExprListAppend(pParse,0, p);
|
||||
sqlite3ExprListSetName(pParse, A, &Y, 1);
|
||||
sqlite3ExprListCheckLength(pParse, A, "index");
|
||||
|
||||
+9
-1
@@ -114,12 +114,20 @@ static void pcacheUnpin(PgHdr *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** 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));
|
||||
}
|
||||
}
|
||||
|
||||
+14
-5
@@ -195,7 +195,6 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
|
||||
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;
|
||||
@@ -204,7 +203,8 @@ static void *pcache1Alloc(int nByte){
|
||||
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);
|
||||
}
|
||||
@@ -217,7 +217,8 @@ static void *pcache1Alloc(int nByte){
|
||||
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
|
||||
@@ -235,7 +236,7 @@ static int pcache1Free(void *p){
|
||||
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;
|
||||
@@ -249,7 +250,7 @@ static int pcache1Free(void *p){
|
||||
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);
|
||||
@@ -986,6 +987,14 @@ void sqlite3PCacheSetDefault(void){
|
||||
*/
|
||||
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
|
||||
|
||||
+82
-488
@@ -22,464 +22,13 @@
|
||||
#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,
|
||||
@@ -615,15 +164,15 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
||||
*/
|
||||
static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int mem = ++pParse->nMem;
|
||||
int nMem = ++pParse->nMem;
|
||||
i64 *pI64 = sqlite3DbMallocRaw(pParse->db, sizeof(value));
|
||||
if( pI64 ){
|
||||
memcpy(pI64, &value, sizeof(value));
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_Int64, 0, mem, 0, (char*)pI64, P4_INT64);
|
||||
sqlite3VdbeAddOp4(v, OP_Int64, 0, nMem, 0, (char*)pI64, P4_INT64);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -732,13 +281,13 @@ void sqlite3Pragma(
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
Db *pDb; /* The specific database being pragmaed */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
|
||||
const struct sPragmaNames *pPragma;
|
||||
/* BEGIN SQLCIPHER */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
extern int sqlcipher_codec_pragma(sqlite3*, int, Parse *, const char *, const char *);
|
||||
#endif
|
||||
/* END SQLCIPHER */
|
||||
|
||||
|
||||
if( v==0 ) return;
|
||||
sqlite3VdbeRunOnlyOnce(v);
|
||||
pParse->nMem = 2;
|
||||
@@ -773,6 +322,17 @@ void sqlite3Pragma(
|
||||
/* 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;
|
||||
@@ -782,11 +342,11 @@ void sqlite3Pragma(
|
||||
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( aFcntl[0] ){
|
||||
int mem = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, mem, 0, aFcntl[0], 0);
|
||||
int nMem = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, nMem, 0, aFcntl[0], 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "result", SQLITE_STATIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1);
|
||||
sqlite3_free(aFcntl[0]);
|
||||
}
|
||||
goto pragma_out;
|
||||
@@ -825,14 +385,15 @@ void sqlite3Pragma(
|
||||
}
|
||||
}
|
||||
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)
|
||||
/*
|
||||
@@ -1400,7 +961,9 @@ void sqlite3Pragma(
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Safety level may not be changed inside a transaction");
|
||||
}else{
|
||||
pDb->safety_level = getSafetyLevel(zRight,0,1)+1;
|
||||
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
|
||||
if( iLevel==0 ) iLevel = 1;
|
||||
pDb->safety_level = iLevel;
|
||||
setAllPagerFlags(db);
|
||||
}
|
||||
}
|
||||
@@ -1411,10 +974,9 @@ void sqlite3Pragma(
|
||||
#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. */
|
||||
@@ -1496,7 +1058,7 @@ void sqlite3Pragma(
|
||||
}else if( pPk==0 ){
|
||||
k = 1;
|
||||
}else{
|
||||
for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
|
||||
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
|
||||
@@ -1543,20 +1105,42 @@ void sqlite3Pragma(
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1569,17 +1153,22 @@ void sqlite3Pragma(
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2149,9 +1738,9 @@ void sqlite3Pragma(
|
||||
** 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 */
|
||||
@@ -2253,8 +1842,9 @@ void sqlite3Pragma(
|
||||
/*
|
||||
** 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);
|
||||
@@ -2271,7 +1861,7 @@ void sqlite3Pragma(
|
||||
** 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));
|
||||
}
|
||||
@@ -2283,8 +1873,12 @@ void sqlite3Pragma(
|
||||
** 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;
|
||||
|
||||
+459
@@ -0,0 +1,459 @@
|
||||
/* 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. */
|
||||
+3
-3
@@ -67,7 +67,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
||||
if( argv[1]==0 ){
|
||||
corruptSchema(pData, argv[0], 0);
|
||||
}else if( argv[2] && argv[2][0] ){
|
||||
}else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){
|
||||
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
||||
** But because db->init.busy is set to 1, no VDBE code is generated
|
||||
** or executed. All the parser does is build the internal data
|
||||
@@ -98,8 +98,8 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}else if( argv[0]==0 ){
|
||||
corruptSchema(pData, 0, 0);
|
||||
}else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){
|
||||
corruptSchema(pData, argv[0], 0);
|
||||
}else{
|
||||
/* If the SQL column is blank it means this is an index that
|
||||
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
|
||||
|
||||
+54
-52
@@ -138,6 +138,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
||||
** Set the StrAccum object to an error mode.
|
||||
*/
|
||||
static void setStrAccumError(StrAccum *p, u8 eError){
|
||||
assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG );
|
||||
p->accError = eError;
|
||||
p->nAlloc = 0;
|
||||
}
|
||||
@@ -212,13 +213,6 @@ void sqlite3VXPrintf(
|
||||
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 ){
|
||||
@@ -259,7 +253,6 @@ void sqlite3VXPrintf(
|
||||
}
|
||||
}while( !done && (c=(*++fmt))!=0 );
|
||||
/* Get the field width */
|
||||
width = 0;
|
||||
if( c=='*' ){
|
||||
if( bArgList ){
|
||||
width = (int)getIntArg(pArgList);
|
||||
@@ -268,18 +261,21 @@ void sqlite3VXPrintf(
|
||||
}
|
||||
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;
|
||||
c = *++fmt;
|
||||
if( c=='*' ){
|
||||
if( bArgList ){
|
||||
@@ -287,13 +283,18 @@ void sqlite3VXPrintf(
|
||||
}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;
|
||||
@@ -457,7 +458,8 @@ void sqlite3VXPrintf(
|
||||
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;
|
||||
@@ -512,8 +514,9 @@ void sqlite3VXPrintf(
|
||||
}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;
|
||||
@@ -745,13 +748,13 @@ void sqlite3VXPrintf(
|
||||
*/
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
if( !p->useMalloc ){
|
||||
if( p->mxAlloc==0 ){
|
||||
N = p->nAlloc - p->nChar - 1;
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
return N;
|
||||
@@ -771,10 +774,10 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
||||
}else{
|
||||
p->nAlloc = (int)szNew;
|
||||
}
|
||||
if( p->useMalloc==1 ){
|
||||
if( p->db ){
|
||||
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
|
||||
}else{
|
||||
zNew = sqlite3_realloc(zOld, p->nAlloc);
|
||||
zNew = sqlite3_realloc64(zOld, p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
assert( p->zText!=0 || p->nChar==0 );
|
||||
@@ -794,7 +797,10 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
||||
** 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;
|
||||
}
|
||||
|
||||
@@ -819,7 +825,7 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
|
||||
** size of the memory allocation for StrAccum if necessary.
|
||||
*/
|
||||
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
assert( z!=0 );
|
||||
assert( z!=0 || N==0 );
|
||||
assert( p->zText!=0 || p->nChar==0 || p->accError );
|
||||
assert( N>=0 );
|
||||
assert( p->accError==0 || p->nAlloc==0 );
|
||||
@@ -848,12 +854,8 @@ void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
|
||||
char *sqlite3StrAccumFinish(StrAccum *p){
|
||||
if( p->zText ){
|
||||
p->zText[p->nChar] = 0;
|
||||
if( p->useMalloc && p->zText==p->zBase ){
|
||||
if( p->useMalloc==1 ){
|
||||
p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
|
||||
}else{
|
||||
p->zText = sqlite3_malloc(p->nChar+1);
|
||||
}
|
||||
if( p->mxAlloc>0 && p->zText==p->zBase ){
|
||||
p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
|
||||
if( p->zText ){
|
||||
memcpy(p->zText, p->zBase, p->nChar+1);
|
||||
}else{
|
||||
@@ -869,25 +871,31 @@ char *sqlite3StrAccumFinish(StrAccum *p){
|
||||
*/
|
||||
void sqlite3StrAccumReset(StrAccum *p){
|
||||
if( p->zText!=p->zBase ){
|
||||
if( p->useMalloc==1 ){
|
||||
sqlite3DbFree(p->db, p->zText);
|
||||
}else{
|
||||
sqlite3_free(p->zText);
|
||||
}
|
||||
sqlite3DbFree(p->db, p->zText);
|
||||
}
|
||||
p->zText = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a string accumulator
|
||||
** Initialize a string accumulator.
|
||||
**
|
||||
** p: The accumulator to be initialized.
|
||||
** db: Pointer to a database connection. May be NULL. Lookaside
|
||||
** memory is used if not NULL. db->mallocFailed is set appropriately
|
||||
** when not NULL.
|
||||
** zBase: An initial buffer. May be NULL in which case the initial buffer
|
||||
** is malloced.
|
||||
** n: Size of zBase in bytes. If total space requirements never exceed
|
||||
** n then no memory allocations ever occur.
|
||||
** mx: Maximum number of bytes to accumulate. If mx==0 then no memory
|
||||
** allocations will ever occur.
|
||||
*/
|
||||
void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){
|
||||
void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
|
||||
p->zText = p->zBase = zBase;
|
||||
p->db = 0;
|
||||
p->db = db;
|
||||
p->nChar = 0;
|
||||
p->nAlloc = n;
|
||||
p->mxAlloc = mx;
|
||||
p->useMalloc = 1;
|
||||
p->accError = 0;
|
||||
}
|
||||
|
||||
@@ -900,9 +908,8 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
|
||||
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||
StrAccum acc;
|
||||
assert( db!=0 );
|
||||
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase),
|
||||
sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase),
|
||||
db->aLimit[SQLITE_LIMIT_LENGTH]);
|
||||
acc.db = db;
|
||||
sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap);
|
||||
z = sqlite3StrAccumFinish(&acc);
|
||||
if( acc.accError==STRACCUM_NOMEM ){
|
||||
@@ -960,8 +967,7 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
#endif
|
||||
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
|
||||
acc.useMalloc = 2;
|
||||
sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
z = sqlite3StrAccumFinish(&acc);
|
||||
return z;
|
||||
@@ -1002,12 +1008,11 @@ char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
|
||||
#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
|
||||
sqlite3StrAccumInit(&acc, zBuf, n, 0);
|
||||
acc.useMalloc = 0;
|
||||
sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
return sqlite3StrAccumFinish(&acc);
|
||||
}
|
||||
@@ -1033,8 +1038,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
|
||||
StrAccum acc; /* String accumulator */
|
||||
char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
|
||||
|
||||
sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0);
|
||||
acc.useMalloc = 0;
|
||||
sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
|
||||
sqlite3StrAccumFinish(&acc));
|
||||
@@ -1052,7 +1056,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...){
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG)
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
||||
/*
|
||||
** A version of printf() that understands %lld. Used for debugging.
|
||||
** The printf() built into some versions of windows does not understand %lld
|
||||
@@ -1062,8 +1066,7 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
StrAccum acc;
|
||||
char zBuf[500];
|
||||
sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0);
|
||||
acc.useMalloc = 0;
|
||||
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
||||
va_start(ap,zFormat);
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
va_end(ap);
|
||||
@@ -1090,7 +1093,7 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
|
||||
** is not the last item in the tree. */
|
||||
TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
|
||||
if( p==0 ){
|
||||
p = sqlite3_malloc( sizeof(*p) );
|
||||
p = sqlite3_malloc64( sizeof(*p) );
|
||||
if( p==0 ) return 0;
|
||||
memset(p, 0, sizeof(*p));
|
||||
}else{
|
||||
@@ -1113,8 +1116,7 @@ void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
||||
int i;
|
||||
StrAccum acc;
|
||||
char zBuf[500];
|
||||
sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0);
|
||||
acc.useMalloc = 0;
|
||||
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
||||
if( p ){
|
||||
for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){
|
||||
sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4);
|
||||
|
||||
+63
-23
@@ -79,7 +79,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
|
||||
** SELECT a+b, c+d FROM t1 ORDER BY (a+b) COLLATE nocase;
|
||||
**
|
||||
** The nSubquery parameter specifies how many levels of subquery the
|
||||
** alias is removed from the original expression. The usually value is
|
||||
** alias is removed from the original expression. The usual value is
|
||||
** zero but it might be more if the alias is contained within a subquery
|
||||
** of the original expression. The Expr.op2 field of TK_AGG_FUNCTION
|
||||
** structures must be increased by the nSubquery amount.
|
||||
@@ -99,7 +99,6 @@ static void resolveAlias(
|
||||
assert( iCol>=0 && iCol<pEList->nExpr );
|
||||
pOrig = pEList->a[iCol].pExpr;
|
||||
assert( pOrig!=0 );
|
||||
assert( pOrig->flags & EP_Resolved );
|
||||
db = pParse->db;
|
||||
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||
if( pDup==0 ) return;
|
||||
@@ -247,9 +246,10 @@ static int lookupName(
|
||||
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++){
|
||||
@@ -320,7 +320,8 @@ static int lookupName(
|
||||
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);
|
||||
}
|
||||
@@ -641,7 +642,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
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.
|
||||
*/
|
||||
@@ -706,19 +708,20 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
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;
|
||||
}
|
||||
@@ -735,7 +738,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
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);
|
||||
@@ -987,9 +992,11 @@ static int resolveCompoundOrderBy(
|
||||
if( pItem->pExpr==pE ){
|
||||
pItem->pExpr = pNew;
|
||||
}else{
|
||||
assert( pItem->pExpr->op==TK_COLLATE );
|
||||
assert( pItem->pExpr->pLeft==pE );
|
||||
pItem->pExpr->pLeft = pNew;
|
||||
Expr *pParent = pItem->pExpr;
|
||||
assert( pParent->op==TK_COLLATE );
|
||||
while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft;
|
||||
assert( pParent->pLeft==pE );
|
||||
pParent->pLeft = pNew;
|
||||
}
|
||||
sqlite3ExprDelete(db, pE);
|
||||
pItem->u.x.iOrderByCol = (u16)iCol;
|
||||
@@ -1046,7 +1053,8 @@ int sqlite3ResolveOrderGroupBy(
|
||||
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;
|
||||
@@ -1179,6 +1187,20 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
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 && p->pOrderBy );
|
||||
assert( pSub->pPrior && pSub->pOrderBy==0 );
|
||||
pSub->pOrderBy = p->pOrderBy;
|
||||
p->pOrderBy = 0;
|
||||
}
|
||||
|
||||
/* Recursively resolve names in all subqueries
|
||||
*/
|
||||
@@ -1261,12 +1283,30 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
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
|
||||
** the compound have been resolved.
|
||||
**
|
||||
** If there is an ORDER BY clause on a term of a compound-select other
|
||||
** than the right-most term, then that is a syntax error. But the error
|
||||
** is not detected until much later, and so we need to go ahead and
|
||||
** resolve those symbols on the incorrect ORDER BY for consistency.
|
||||
*/
|
||||
if( !isCompound && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") ){
|
||||
if( isCompound<=nCompound /* Defer right-most ORDER BY of a compound */
|
||||
&& resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER")
|
||||
){
|
||||
return WRC_Abort;
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
|
||||
+60
-39
@@ -111,7 +111,6 @@ Select *sqlite3SelectNew(
|
||||
Select standin;
|
||||
sqlite3 *db = pParse->db;
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
|
||||
assert( db->mallocFailed || !pOffset || pLimit ); /* OFFSET implies LIMIT */
|
||||
if( pNew==0 ){
|
||||
assert( db->mallocFailed );
|
||||
pNew = &standin;
|
||||
@@ -131,7 +130,7 @@ Select *sqlite3SelectNew(
|
||||
pNew->op = TK_SELECT;
|
||||
pNew->pLimit = pLimit;
|
||||
pNew->pOffset = pOffset;
|
||||
assert( pOffset==0 || pLimit!=0 );
|
||||
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
if( db->mallocFailed ) {
|
||||
@@ -563,20 +562,17 @@ static void pushOntoSorter(
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -973,7 +969,7 @@ static void selectInnerLoop(
|
||||
** 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1384,7 +1380,7 @@ static const char *columnTypeImpl(
|
||||
** of the SELECT statement. Return the declaration type and origin
|
||||
** data for the result-set column of the sub-select.
|
||||
*/
|
||||
if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
|
||||
if( iCol>=0 && iCol<pS->pEList->nExpr ){
|
||||
/* If iCol is less than zero, then the expression requests the
|
||||
** rowid of the sub-select or view. This expression is legal (see
|
||||
** test case misc2.2.2) - it always evaluates to NULL.
|
||||
@@ -1704,12 +1700,14 @@ static void selectAddColumnTypeAndCollation(
|
||||
a = pSelect->pEList->a;
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
p = a[i].pExpr;
|
||||
pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
|
||||
if( pCol->zType==0 ){
|
||||
pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
|
||||
}
|
||||
szAll += pCol->szEst;
|
||||
pCol->affinity = sqlite3ExprAffinity(p);
|
||||
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE;
|
||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
if( pColl ){
|
||||
if( pColl && pCol->zColl==0 ){
|
||||
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
|
||||
}
|
||||
}
|
||||
@@ -1826,7 +1824,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
||||
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;
|
||||
@@ -2045,7 +2043,7 @@ static void generateWithRecursiveQuery(
|
||||
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);
|
||||
@@ -2111,8 +2109,7 @@ static int multiSelectValues(
|
||||
int nExpr = p->pEList->nExpr;
|
||||
int nRow = 1;
|
||||
int rc = 0;
|
||||
assert( p->pNext==0 );
|
||||
assert( p->selFlags & SF_AllValues );
|
||||
assert( p->selFlags & SF_MultiValue );
|
||||
do{
|
||||
assert( p->selFlags & SF_Values );
|
||||
assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
|
||||
@@ -2221,7 +2218,7 @@ static int multiSelect(
|
||||
|
||||
/* Special handling for a compound-select that originates as a VALUES clause.
|
||||
*/
|
||||
if( p->selFlags & SF_AllValues ){
|
||||
if( p->selFlags & SF_MultiValue ){
|
||||
rc = multiSelectValues(pParse, p, &dest);
|
||||
goto multi_select_end;
|
||||
}
|
||||
@@ -2270,7 +2267,7 @@ static int multiSelect(
|
||||
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);
|
||||
@@ -2606,7 +2603,7 @@ static int generateOutputSubroutine(
|
||||
*/
|
||||
case SRT_Set: {
|
||||
int r1;
|
||||
assert( pIn->nSdst==1 );
|
||||
assert( pIn->nSdst==1 || pParse->nErr>0 );
|
||||
pDest->affSdst =
|
||||
sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
@@ -2632,7 +2629,7 @@ static int generateOutputSubroutine(
|
||||
** of the scan loop.
|
||||
*/
|
||||
case SRT_Mem: {
|
||||
assert( pIn->nSdst==1 );
|
||||
assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 );
|
||||
sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1);
|
||||
/* The LIMIT clause will jump out of the loop for us */
|
||||
break;
|
||||
@@ -2647,7 +2644,7 @@ static int generateOutputSubroutine(
|
||||
pDest->iSdst = sqlite3GetTempRange(pParse, pIn->nSdst);
|
||||
pDest->nSdst = pIn->nSdst;
|
||||
}
|
||||
sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pDest->nSdst);
|
||||
sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pIn->nSdst);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
|
||||
break;
|
||||
}
|
||||
@@ -2671,7 +2668,7 @@ static int generateOutputSubroutine(
|
||||
/* 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
|
||||
@@ -2863,8 +2860,10 @@ static int multiSelectOrderBy(
|
||||
if( aPermute ){
|
||||
struct ExprList_item *pItem;
|
||||
for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
|
||||
assert( pItem->u.x.iOrderByCol>0
|
||||
&& pItem->u.x.iOrderByCol<=p->pEList->nExpr );
|
||||
assert( pItem->u.x.iOrderByCol>0 );
|
||||
/* assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ) is also true
|
||||
** but only for well-formed SELECT statements. */
|
||||
testcase( pItem->u.x.iOrderByCol > p->pEList->nExpr );
|
||||
aPermute[i] = pItem->u.x.iOrderByCol - 1;
|
||||
}
|
||||
pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
|
||||
@@ -3074,7 +3073,7 @@ static int multiSelectOrderBy(
|
||||
/*** TBD: Insert subroutine calls to close cursors on incomplete
|
||||
**** subqueries ****/
|
||||
explainComposite(pParse, p->op, iSub1, iSub2, 0);
|
||||
return SQLITE_OK;
|
||||
return pParse->nErr!=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3194,7 +3193,10 @@ static void substSelect(
|
||||
**
|
||||
** (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)
|
||||
@@ -3331,8 +3333,17 @@ static int flattenSubquery(
|
||||
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,
|
||||
@@ -3874,7 +3885,10 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
||||
pNew->pOrderBy = 0;
|
||||
p->pPrior = 0;
|
||||
p->pNext = 0;
|
||||
p->pWith = 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;
|
||||
@@ -4026,7 +4040,7 @@ static int withExpand(
|
||||
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
|
||||
);
|
||||
@@ -4153,7 +4167,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
/* 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;
|
||||
@@ -4410,7 +4424,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
|
||||
sqlite3WalkSelect(&w, pSelect);
|
||||
}
|
||||
w.xSelectCallback = selectExpander;
|
||||
if( (pSelect->selFlags & SF_AllValues)==0 ){
|
||||
if( (pSelect->selFlags & SF_MultiValue)==0 ){
|
||||
w.xSelectCallback2 = selectPopWith;
|
||||
}
|
||||
sqlite3WalkSelect(&w, pSelect);
|
||||
@@ -4596,7 +4610,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
}
|
||||
if( pF->iDistinct>=0 ){
|
||||
addrNext = sqlite3VdbeMakeLabel(v);
|
||||
assert( nArg==1 );
|
||||
testcase( nArg==0 ); /* Error condition */
|
||||
testcase( nArg>1 ); /* Also an error */
|
||||
codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
|
||||
}
|
||||
if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
||||
@@ -4752,6 +4767,13 @@ int sqlite3Select(
|
||||
}
|
||||
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.
|
||||
*/
|
||||
@@ -5464,10 +5486,9 @@ int sqlite3Select(
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, iEnd);
|
||||
|
||||
/* The SELECT was successfully coded. Set the return code to 0
|
||||
** to indicate no errors.
|
||||
*/
|
||||
rc = 0;
|
||||
/* The SELECT has been coded. If there is an error in the Parse structure,
|
||||
** set the return code to 1. Otherwise 0. */
|
||||
rc = (pParse->nErr>0);
|
||||
|
||||
/* Control jumps to here if an error is encountered above, or upon
|
||||
** successful coding of the SELECT.
|
||||
@@ -5497,9 +5518,9 @@ select_end:
|
||||
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++;
|
||||
@@ -5518,7 +5539,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
struct SrcList_item *pItem = &p->pSrc->a[i];
|
||||
StrAccum x;
|
||||
char zLine[100];
|
||||
sqlite3StrAccumInit(&x, zLine, sizeof(zLine), 0);
|
||||
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
|
||||
sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
|
||||
if( pItem->zDatabase ){
|
||||
sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
|
||||
|
||||
+390
-106
@@ -24,6 +24,13 @@
|
||||
#include "msvc.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** No support for loadable extensions in VxWorks.
|
||||
*/
|
||||
#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
|
||||
# define SQLITE_OMIT_LOAD_EXTENSION 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Enable large-file support for fopen() and friends on unix.
|
||||
*/
|
||||
@@ -107,10 +114,15 @@
|
||||
*/
|
||||
extern int isatty(int);
|
||||
|
||||
/* popen and pclose are not C89 functions and so are sometimes omitted from
|
||||
** the <stdio.h> header */
|
||||
extern FILE *popen(const char*,const char*);
|
||||
extern int pclose(FILE*);
|
||||
#if !defined(__RTP__) && !defined(_WRS_KERNEL)
|
||||
/* popen and pclose are not C89 functions and so are sometimes omitted from
|
||||
** the <stdio.h> header */
|
||||
extern FILE *popen(const char*,const char*);
|
||||
extern int pclose(FILE*);
|
||||
#else
|
||||
# define SQLITE_OMIT_POPEN 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
@@ -126,6 +138,26 @@ extern int pclose(FILE*);
|
||||
#define IsDigit(X) isdigit((unsigned char)X)
|
||||
#define ToLower(X) (char)tolower((unsigned char)X)
|
||||
|
||||
/* On Windows, we normally run with output mode of TEXT so that \n characters
|
||||
** are automatically translated into \r\n. However, this behavior needs
|
||||
** to be disabled in some cases (ex: when generating CSV output and when
|
||||
** rendering quoted strings that contain \n characters). The following
|
||||
** routines take care of that.
|
||||
*/
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
static void setBinaryMode(FILE *out){
|
||||
fflush(out);
|
||||
_setmode(_fileno(out), _O_BINARY);
|
||||
}
|
||||
static void setTextMode(FILE *out){
|
||||
fflush(out);
|
||||
_setmode(_fileno(out), _O_TEXT);
|
||||
}
|
||||
#else
|
||||
# define setBinaryMode(X)
|
||||
# define setTextMode(X)
|
||||
#endif
|
||||
|
||||
|
||||
/* True if the timer is enabled */
|
||||
static int enableTimer = 0;
|
||||
@@ -145,11 +177,19 @@ static sqlite3_int64 timeOfDay(void){
|
||||
return t;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
|
||||
&& !defined(__minux)
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
/* VxWorks does not support getrusage() as far as we can determine */
|
||||
#if defined(_WRS_KERNEL) || defined(__RTP__)
|
||||
struct rusage {
|
||||
struct timeval ru_utime; /* user CPU time used */
|
||||
struct timeval ru_stime; /* system CPU time used */
|
||||
};
|
||||
#define getrusage(A,B) memset(B,0,sizeof(*B))
|
||||
#endif
|
||||
|
||||
/* Saved resource information for the beginning of an operation */
|
||||
static struct rusage sBegin; /* CPU time at start */
|
||||
static sqlite3_int64 iBegin; /* Wall-clock time at start */
|
||||
@@ -175,8 +215,8 @@ static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
|
||||
*/
|
||||
static void endTimer(void){
|
||||
if( enableTimer ){
|
||||
struct rusage sEnd;
|
||||
sqlite3_int64 iEnd = timeOfDay();
|
||||
struct rusage sEnd;
|
||||
getrusage(RUSAGE_SELF, &sEnd);
|
||||
printf("Run Time: real %.3f user %f sys %f\n",
|
||||
(iEnd - iBegin)*0.001,
|
||||
@@ -296,7 +336,7 @@ static int stdin_is_interactive = 1;
|
||||
** to this database a static variable so that it can be accessed
|
||||
** by the SIGINT handler to interrupt database processing.
|
||||
*/
|
||||
static sqlite3 *db = 0;
|
||||
static sqlite3 *globalDb = 0;
|
||||
|
||||
/*
|
||||
** True if an interrupt (Control-C) has been received.
|
||||
@@ -330,7 +370,7 @@ static FILE *iotrace = 0;
|
||||
** is written to iotrace.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_IOTRACE
|
||||
static void iotracePrintf(const char *zFormat, ...){
|
||||
static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *z;
|
||||
if( iotrace==0 ) return;
|
||||
@@ -487,6 +527,7 @@ struct ShellState {
|
||||
int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
|
||||
int statsOn; /* True to display memory stats before each finalize */
|
||||
int scanstatsOn; /* True to display scan stats before each finalize */
|
||||
int backslashOn; /* Resolve C-style \x escapes in SQL input text */
|
||||
int outCount; /* Revert to stdout when reaching zero */
|
||||
int cnt; /* Number of records displayed so far */
|
||||
FILE *out; /* Write results here */
|
||||
@@ -604,6 +645,7 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
|
||||
static void output_quoted_string(FILE *out, const char *z){
|
||||
int i;
|
||||
int nSingle = 0;
|
||||
setBinaryMode(out);
|
||||
for(i=0; z[i]; i++){
|
||||
if( z[i]=='\'' ) nSingle++;
|
||||
}
|
||||
@@ -626,6 +668,7 @@ static void output_quoted_string(FILE *out, const char *z){
|
||||
}
|
||||
fprintf(out,"'");
|
||||
}
|
||||
setTextMode(out);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -762,7 +805,7 @@ static void interrupt_handler(int NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
seenInterrupt++;
|
||||
if( seenInterrupt>2 ) exit(1);
|
||||
if( db ) sqlite3_interrupt(db);
|
||||
if( globalDb ) sqlite3_interrupt(globalDb);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -928,10 +971,7 @@ static int shell_callback(
|
||||
break;
|
||||
}
|
||||
case MODE_Csv: {
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
fflush(p->out);
|
||||
_setmode(_fileno(p->out), _O_BINARY);
|
||||
#endif
|
||||
setBinaryMode(p->out);
|
||||
if( p->cnt++==0 && p->showHeader ){
|
||||
for(i=0; i<nArg; i++){
|
||||
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
|
||||
@@ -944,16 +984,22 @@ static int shell_callback(
|
||||
}
|
||||
fprintf(p->out, "%s", p->rowSeparator);
|
||||
}
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
fflush(p->out);
|
||||
_setmode(_fileno(p->out), _O_TEXT);
|
||||
#endif
|
||||
setTextMode(p->out);
|
||||
break;
|
||||
}
|
||||
case MODE_Insert: {
|
||||
p->cnt++;
|
||||
if( azArg==0 ) break;
|
||||
fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
|
||||
fprintf(p->out,"INSERT INTO %s",p->zDestTable);
|
||||
if( p->showHeader ){
|
||||
fprintf(p->out,"(");
|
||||
for(i=0; i<nArg; i++){
|
||||
char *zSep = i>0 ? ",": "";
|
||||
fprintf(p->out, "%s%s", zSep, azCol[i]);
|
||||
}
|
||||
fprintf(p->out,")");
|
||||
}
|
||||
fprintf(p->out," VALUES(");
|
||||
for(i=0; i<nArg; i++){
|
||||
char *zSep = i>0 ? ",": "";
|
||||
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
|
||||
@@ -1154,7 +1200,7 @@ static char *save_err_msg(
|
||||
sqlite3 *db /* Database to query */
|
||||
){
|
||||
int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
|
||||
char *zErrMsg = sqlite3_malloc(nErrMsg);
|
||||
char *zErrMsg = sqlite3_malloc64(nErrMsg);
|
||||
if( zErrMsg ){
|
||||
memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
|
||||
}
|
||||
@@ -1391,8 +1437,8 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
|
||||
/* Grow the p->aiIndent array as required */
|
||||
if( iOp>=nAlloc ){
|
||||
nAlloc += 100;
|
||||
p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int));
|
||||
abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int));
|
||||
p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
|
||||
abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
|
||||
}
|
||||
abYield[iOp] = str_in_array(zOp, azYield);
|
||||
p->aiIndent[iOp] = 0;
|
||||
@@ -1509,7 +1555,7 @@ static int shell_exec(
|
||||
if( xCallback ){
|
||||
/* allocate space for col name ptr, value ptr, and type */
|
||||
int nCol = sqlite3_column_count(pStmt);
|
||||
void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
|
||||
void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
|
||||
if( !pData ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1735,8 +1781,10 @@ static int run_schema_dump_query(
|
||||
static char zHelp[] =
|
||||
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
|
||||
".bail on|off Stop after hitting an error. Default OFF\n"
|
||||
".binary on|off Turn binary output on or off. Default OFF\n"
|
||||
".clone NEWDB Clone data into NEWDB from the existing database\n"
|
||||
".databases List names and files of attached databases\n"
|
||||
".dbinfo ?DB? Show status information about the database\n"
|
||||
".dump ?TABLE? ... Dump the database in an SQL text format\n"
|
||||
" If TABLE specified, only dump tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
@@ -1749,12 +1797,13 @@ static char zHelp[] =
|
||||
".headers on|off Turn display of headers on or off\n"
|
||||
".help Show this message\n"
|
||||
".import FILE TABLE Import data from FILE into TABLE\n"
|
||||
".indices ?TABLE? Show names of all indices\n"
|
||||
" If TABLE specified, only show indices for tables\n"
|
||||
".indexes ?TABLE? Show names of all indexes\n"
|
||||
" If TABLE specified, only show indexes for tables\n"
|
||||
" matching LIKE pattern TABLE.\n"
|
||||
#ifdef SQLITE_ENABLE_IOTRACE
|
||||
".iotrace FILE Enable I/O diagnostic logging to FILE\n"
|
||||
#endif
|
||||
".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n"
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
".load FILE ?ENTRY? Load an extension library\n"
|
||||
#endif
|
||||
@@ -1824,7 +1873,7 @@ static void readfileFunc(
|
||||
fseek(in, 0, SEEK_END);
|
||||
nIn = ftell(in);
|
||||
rewind(in);
|
||||
pBuf = sqlite3_malloc( nIn );
|
||||
pBuf = sqlite3_malloc64( nIn );
|
||||
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
|
||||
sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
|
||||
}else{
|
||||
@@ -1871,23 +1920,23 @@ static void open_db(ShellState *p, int keepAlive){
|
||||
if( p->db==0 ){
|
||||
sqlite3_initialize();
|
||||
sqlite3_open(p->zDbFilename, &p->db);
|
||||
db = p->db;
|
||||
if( db && sqlite3_errcode(db)==SQLITE_OK ){
|
||||
sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
|
||||
globalDb = p->db;
|
||||
if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){
|
||||
sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0,
|
||||
shellstaticFunc, 0, 0);
|
||||
}
|
||||
if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
|
||||
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
|
||||
fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
|
||||
p->zDbFilename, sqlite3_errmsg(db));
|
||||
p->zDbFilename, sqlite3_errmsg(p->db));
|
||||
if( keepAlive ) return;
|
||||
exit(1);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
sqlite3_enable_load_extension(p->db, 1);
|
||||
#endif
|
||||
sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
|
||||
sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0,
|
||||
readfileFunc, 0, 0);
|
||||
sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
|
||||
sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
|
||||
writefileFunc, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -1895,26 +1944,44 @@ static void open_db(ShellState *p, int keepAlive){
|
||||
/*
|
||||
** Do C-language style dequoting.
|
||||
**
|
||||
** \a -> alarm
|
||||
** \b -> backspace
|
||||
** \t -> tab
|
||||
** \n -> newline
|
||||
** \v -> vertical tab
|
||||
** \f -> form feed
|
||||
** \r -> carriage return
|
||||
** \s -> space
|
||||
** \" -> "
|
||||
** \NNN -> ascii character NNN in octal
|
||||
** \' -> '
|
||||
** \\ -> backslash
|
||||
** \NNN -> ascii character NNN in octal
|
||||
*/
|
||||
static void resolve_backslashes(char *z){
|
||||
int i, j;
|
||||
char c;
|
||||
while( *z && *z!='\\' ) z++;
|
||||
for(i=j=0; (c = z[i])!=0; i++, j++){
|
||||
if( c=='\\' ){
|
||||
if( c=='\\' && z[i+1]!=0 ){
|
||||
c = z[++i];
|
||||
if( c=='n' ){
|
||||
c = '\n';
|
||||
if( c=='a' ){
|
||||
c = '\a';
|
||||
}else if( c=='b' ){
|
||||
c = '\b';
|
||||
}else if( c=='t' ){
|
||||
c = '\t';
|
||||
}else if( c=='n' ){
|
||||
c = '\n';
|
||||
}else if( c=='v' ){
|
||||
c = '\v';
|
||||
}else if( c=='f' ){
|
||||
c = '\f';
|
||||
}else if( c=='r' ){
|
||||
c = '\r';
|
||||
}else if( c=='"' ){
|
||||
c = '"';
|
||||
}else if( c=='\'' ){
|
||||
c = '\'';
|
||||
}else if( c=='\\' ){
|
||||
c = '\\';
|
||||
}else if( c>='0' && c<='7' ){
|
||||
@@ -2084,7 +2151,7 @@ struct ImportCtx {
|
||||
static void import_append_char(ImportCtx *p, int c){
|
||||
if( p->n+1>=p->nAlloc ){
|
||||
p->nAlloc += p->nAlloc + 100;
|
||||
p->z = sqlite3_realloc(p->z, p->nAlloc);
|
||||
p->z = sqlite3_realloc64(p->z, p->nAlloc);
|
||||
if( p->z==0 ){
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
@@ -2098,7 +2165,7 @@ static void import_append_char(ImportCtx *p, int c){
|
||||
**
|
||||
** + Input comes from p->in.
|
||||
** + Store results in p->z of length p->n. Space to hold p->z comes
|
||||
** from sqlite3_malloc().
|
||||
** from sqlite3_malloc64().
|
||||
** + Use p->cSep as the column separator. The default is ",".
|
||||
** + Use p->rSep as the row separator. The default is "\n".
|
||||
** + Keep track of the line number in p->nLine.
|
||||
@@ -2106,7 +2173,7 @@ static void import_append_char(ImportCtx *p, int c){
|
||||
** EOF on end-of-file.
|
||||
** + Report syntax errors on stderr
|
||||
*/
|
||||
static char *csv_read_one_field(ImportCtx *p){
|
||||
static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
|
||||
int c;
|
||||
int cSep = p->cColSep;
|
||||
int rSep = p->cRowSep;
|
||||
@@ -2172,7 +2239,7 @@ static char *csv_read_one_field(ImportCtx *p){
|
||||
**
|
||||
** + Input comes from p->in.
|
||||
** + Store results in p->z of length p->n. Space to hold p->z comes
|
||||
** from sqlite3_malloc().
|
||||
** from sqlite3_malloc64().
|
||||
** + Use p->cSep as the column separator. The default is "\x1F".
|
||||
** + Use p->rSep as the row separator. The default is "\x1E".
|
||||
** + Keep track of the row number in p->nLine.
|
||||
@@ -2180,7 +2247,7 @@ static char *csv_read_one_field(ImportCtx *p){
|
||||
** EOF on end-of-file.
|
||||
** + Report syntax errors on stderr
|
||||
*/
|
||||
static char *ascii_read_one_field(ImportCtx *p){
|
||||
static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
|
||||
int c;
|
||||
int cSep = p->cColSep;
|
||||
int rSep = p->cRowSep;
|
||||
@@ -2232,7 +2299,7 @@ static void tryToCloneData(
|
||||
goto end_data_xfer;
|
||||
}
|
||||
n = sqlite3_column_count(pQuery);
|
||||
zInsert = sqlite3_malloc(200 + nTable + n*3);
|
||||
zInsert = sqlite3_malloc64(200 + nTable + n*3);
|
||||
if( zInsert==0 ){
|
||||
fprintf(stderr, "out of memory\n");
|
||||
goto end_data_xfer;
|
||||
@@ -2422,7 +2489,9 @@ static void tryToClone(ShellState *p, const char *zNewDb){
|
||||
*/
|
||||
static void output_reset(ShellState *p){
|
||||
if( p->outfile[0]=='|' ){
|
||||
#ifndef SQLITE_OMIT_POPEN
|
||||
pclose(p->out);
|
||||
#endif
|
||||
}else{
|
||||
output_file_close(p->out);
|
||||
}
|
||||
@@ -2430,6 +2499,115 @@ static void output_reset(ShellState *p){
|
||||
p->out = stdout;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run an SQL command and return the single integer result.
|
||||
*/
|
||||
static int db_int(ShellState *p, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
int res = 0;
|
||||
sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
res = sqlite3_column_int(pStmt,0);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a 2-byte or 4-byte big-endian integer into a native integer
|
||||
*/
|
||||
unsigned int get2byteInt(unsigned char *a){
|
||||
return (a[0]<<8) + a[1];
|
||||
}
|
||||
unsigned int get4byteInt(unsigned char *a){
|
||||
return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the ".info" command.
|
||||
**
|
||||
** Return 1 on error, 2 to exit, and 0 otherwise.
|
||||
*/
|
||||
static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
||||
static const struct { const char *zName; int ofst; } aField[] = {
|
||||
{ "file change counter:", 24 },
|
||||
{ "database page count:", 28 },
|
||||
{ "freelist page count:", 36 },
|
||||
{ "schema cookie:", 40 },
|
||||
{ "schema format:", 44 },
|
||||
{ "default cache size:", 48 },
|
||||
{ "autovacuum top root:", 52 },
|
||||
{ "incremental vacuum:", 64 },
|
||||
{ "text encoding:", 56 },
|
||||
{ "user version:", 60 },
|
||||
{ "application id:", 68 },
|
||||
{ "software version:", 96 },
|
||||
};
|
||||
static const struct { const char *zName; const char *zSql; } aQuery[] = {
|
||||
{ "number of tables:",
|
||||
"SELECT count(*) FROM %s WHERE type='table'" },
|
||||
{ "number of indexes:",
|
||||
"SELECT count(*) FROM %s WHERE type='index'" },
|
||||
{ "number of triggers:",
|
||||
"SELECT count(*) FROM %s WHERE type='trigger'" },
|
||||
{ "number of views:",
|
||||
"SELECT count(*) FROM %s WHERE type='view'" },
|
||||
{ "schema size:",
|
||||
"SELECT total(length(sql)) FROM %s" },
|
||||
};
|
||||
sqlite3_file *pFile;
|
||||
int i;
|
||||
char *zSchemaTab;
|
||||
char *zDb = nArg>=2 ? azArg[1] : "main";
|
||||
unsigned char aHdr[100];
|
||||
open_db(p, 0);
|
||||
if( p->db==0 ) return 1;
|
||||
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
|
||||
if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
|
||||
return 1;
|
||||
}
|
||||
i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
|
||||
if( i!=SQLITE_OK ){
|
||||
fprintf(stderr, "unable to read database header\n");
|
||||
return 1;
|
||||
}
|
||||
i = get2byteInt(aHdr+16);
|
||||
if( i==1 ) i = 65536;
|
||||
fprintf(p->out, "%-20s %d\n", "database page size:", i);
|
||||
fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
|
||||
fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
|
||||
fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
|
||||
for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){
|
||||
int ofst = aField[i].ofst;
|
||||
unsigned int val = get4byteInt(aHdr + ofst);
|
||||
fprintf(p->out, "%-20s %u", aField[i].zName, val);
|
||||
switch( ofst ){
|
||||
case 56: {
|
||||
if( val==1 ) fprintf(p->out, " (utf8)");
|
||||
if( val==2 ) fprintf(p->out, " (utf16le)");
|
||||
if( val==3 ) fprintf(p->out, " (utf16be)");
|
||||
}
|
||||
}
|
||||
fprintf(p->out, "\n");
|
||||
}
|
||||
if( zDb==0 ){
|
||||
zSchemaTab = sqlite3_mprintf("main.sqlite_master");
|
||||
}else if( strcmp(zDb,"temp")==0 ){
|
||||
zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
|
||||
}else{
|
||||
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
|
||||
}
|
||||
for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){
|
||||
char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
|
||||
int val = db_int(p, zSql);
|
||||
sqlite3_free(zSql);
|
||||
fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
|
||||
}
|
||||
sqlite3_free(zSchemaTab);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** If an input line begins with "." then invoke this routine to
|
||||
** process that line.
|
||||
@@ -2437,7 +2615,7 @@ static void output_reset(ShellState *p){
|
||||
** Return 1 on error, 2 to exit, and 0 otherwise.
|
||||
*/
|
||||
static int do_meta_command(char *zLine, ShellState *p){
|
||||
int i = 1;
|
||||
int h = 1;
|
||||
int nArg = 0;
|
||||
int n, c;
|
||||
int rc = 0;
|
||||
@@ -2445,24 +2623,24 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
/* Parse the input line into tokens.
|
||||
*/
|
||||
while( zLine[i] && nArg<ArraySize(azArg) ){
|
||||
while( IsSpace(zLine[i]) ){ i++; }
|
||||
if( zLine[i]==0 ) break;
|
||||
if( zLine[i]=='\'' || zLine[i]=='"' ){
|
||||
int delim = zLine[i++];
|
||||
azArg[nArg++] = &zLine[i];
|
||||
while( zLine[i] && zLine[i]!=delim ){
|
||||
if( zLine[i]=='\\' && delim=='"' && zLine[i+1]!=0 ) i++;
|
||||
i++;
|
||||
while( zLine[h] && nArg<ArraySize(azArg) ){
|
||||
while( IsSpace(zLine[h]) ){ h++; }
|
||||
if( zLine[h]==0 ) break;
|
||||
if( zLine[h]=='\'' || zLine[h]=='"' ){
|
||||
int delim = zLine[h++];
|
||||
azArg[nArg++] = &zLine[h];
|
||||
while( zLine[h] && zLine[h]!=delim ){
|
||||
if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
|
||||
h++;
|
||||
}
|
||||
if( zLine[i]==delim ){
|
||||
zLine[i++] = 0;
|
||||
if( zLine[h]==delim ){
|
||||
zLine[h++] = 0;
|
||||
}
|
||||
if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
|
||||
}else{
|
||||
azArg[nArg++] = &zLine[i];
|
||||
while( zLine[i] && !IsSpace(zLine[i]) ){ i++; }
|
||||
if( zLine[i] ) zLine[i++] = 0;
|
||||
azArg[nArg++] = &zLine[h];
|
||||
while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
|
||||
if( zLine[h] ) zLine[h++] = 0;
|
||||
resolve_backslashes(azArg[nArg-1]);
|
||||
}
|
||||
}
|
||||
@@ -2537,6 +2715,19 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
if( booleanValue(azArg[1]) ){
|
||||
setBinaryMode(p->out);
|
||||
}else{
|
||||
setTextMode(p->out);
|
||||
}
|
||||
}else{
|
||||
fprintf(stderr, "Usage: .binary on|off\n");
|
||||
rc = 1;
|
||||
}
|
||||
}else
|
||||
|
||||
/* The undocumented ".breakpoint" command causes a call to the no-op
|
||||
** routine named test_breakpoint().
|
||||
*/
|
||||
@@ -2572,6 +2763,10 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
|
||||
rc = shell_dbinfo_command(p, nArg, azArg);
|
||||
}else
|
||||
|
||||
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
|
||||
open_db(p, 0);
|
||||
/* When playing back a "dump", the content might appear in an order
|
||||
@@ -2759,8 +2954,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int nSep; /* Number of bytes in p->colSeparator[] */
|
||||
char *zSql; /* An SQL statement */
|
||||
ImportCtx sCtx; /* Reader context */
|
||||
char *(*xRead)(ImportCtx*); /* Procedure to read one value */
|
||||
int (*xCloser)(FILE*); /* Procedure to close th3 connection */
|
||||
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
|
||||
int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
|
||||
|
||||
if( nArg!=3 ){
|
||||
fprintf(stderr, "Usage: .import FILE TABLE\n");
|
||||
@@ -2802,9 +2997,14 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sCtx.zFile = zFile;
|
||||
sCtx.nLine = 1;
|
||||
if( sCtx.zFile[0]=='|' ){
|
||||
#ifdef SQLITE_OMIT_POPEN
|
||||
fprintf(stderr, "Error: pipes are not supported in this OS\n");
|
||||
return 1;
|
||||
#else
|
||||
sCtx.in = popen(sCtx.zFile+1, "r");
|
||||
sCtx.zFile = "<pipe>";
|
||||
xCloser = pclose;
|
||||
#endif
|
||||
}else{
|
||||
sCtx.in = fopen(sCtx.zFile, "rb");
|
||||
xCloser = fclose;
|
||||
@@ -2829,7 +3029,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
nByte = strlen30(zSql);
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
|
||||
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
|
||||
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
|
||||
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
|
||||
char cSep = '(';
|
||||
while( xRead(&sCtx) ){
|
||||
@@ -2849,7 +3049,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_free(zCreate);
|
||||
if( rc ){
|
||||
fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
|
||||
sqlite3_errmsg(db));
|
||||
sqlite3_errmsg(p->db));
|
||||
sqlite3_free(sCtx.z);
|
||||
xCloser(sCtx.in);
|
||||
return 1;
|
||||
@@ -2859,7 +3059,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
if (pStmt) sqlite3_finalize(pStmt);
|
||||
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
|
||||
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
|
||||
xCloser(sCtx.in);
|
||||
return 1;
|
||||
}
|
||||
@@ -2867,7 +3067,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
if( nCol==0 ) return 0; /* no columns, no error */
|
||||
zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
|
||||
zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
|
||||
if( zSql==0 ){
|
||||
fprintf(stderr, "Error: out of memory\n");
|
||||
xCloser(sCtx.in);
|
||||
@@ -2884,13 +3084,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
|
||||
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
|
||||
if (pStmt) sqlite3_finalize(pStmt);
|
||||
xCloser(sCtx.in);
|
||||
return 1;
|
||||
}
|
||||
needCommit = sqlite3_get_autocommit(db);
|
||||
if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
|
||||
needCommit = sqlite3_get_autocommit(p->db);
|
||||
if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
|
||||
do{
|
||||
int startLine = sCtx.nLine;
|
||||
for(i=0; i<nCol; i++){
|
||||
@@ -2911,7 +3111,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
|
||||
"filling the rest with NULL\n",
|
||||
sCtx.zFile, startLine, nCol, i+1);
|
||||
i++;
|
||||
i += 2;
|
||||
while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
|
||||
}
|
||||
}
|
||||
@@ -2929,7 +3129,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = sqlite3_reset(pStmt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
|
||||
sqlite3_errmsg(db));
|
||||
sqlite3_errmsg(p->db));
|
||||
}
|
||||
}
|
||||
}while( sCtx.cTerm!=EOF );
|
||||
@@ -2937,10 +3137,11 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
xCloser(sCtx.in);
|
||||
sqlite3_free(sCtx.z);
|
||||
sqlite3_finalize(pStmt);
|
||||
if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
|
||||
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
|
||||
}else
|
||||
|
||||
if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
|
||||
if( c=='i' && (strncmp(azArg[0], "indices", n)==0
|
||||
|| strncmp(azArg[0], "indexes", n)==0) ){
|
||||
ShellState data;
|
||||
char *zErrMsg = 0;
|
||||
open_db(p, 0);
|
||||
@@ -2970,7 +3171,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
);
|
||||
zShellStatic = 0;
|
||||
}else{
|
||||
fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n");
|
||||
fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
@@ -2986,7 +3187,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
#ifdef SQLITE_ENABLE_IOTRACE
|
||||
if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
|
||||
extern void (*sqlite3IoTrace)(const char*, ...);
|
||||
SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
|
||||
if( iotrace && iotrace!=stdout ) fclose(iotrace);
|
||||
iotrace = 0;
|
||||
if( nArg<2 ){
|
||||
@@ -3006,6 +3207,64 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
|
||||
static const struct {
|
||||
const char *zLimitName; /* Name of a limit */
|
||||
int limitCode; /* Integer code for that limit */
|
||||
} aLimit[] = {
|
||||
{ "length", SQLITE_LIMIT_LENGTH },
|
||||
{ "sql_length", SQLITE_LIMIT_SQL_LENGTH },
|
||||
{ "column", SQLITE_LIMIT_COLUMN },
|
||||
{ "expr_depth", SQLITE_LIMIT_EXPR_DEPTH },
|
||||
{ "compound_select", SQLITE_LIMIT_COMPOUND_SELECT },
|
||||
{ "vdbe_op", SQLITE_LIMIT_VDBE_OP },
|
||||
{ "function_arg", SQLITE_LIMIT_FUNCTION_ARG },
|
||||
{ "attached", SQLITE_LIMIT_ATTACHED },
|
||||
{ "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH },
|
||||
{ "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER },
|
||||
{ "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH },
|
||||
{ "worker_threads", SQLITE_LIMIT_WORKER_THREADS },
|
||||
};
|
||||
int i, n2;
|
||||
open_db(p, 0);
|
||||
if( nArg==1 ){
|
||||
for(i=0; i<sizeof(aLimit)/sizeof(aLimit[0]); i++){
|
||||
printf("%20s %d\n", aLimit[i].zLimitName,
|
||||
sqlite3_limit(p->db, aLimit[i].limitCode, -1));
|
||||
}
|
||||
}else if( nArg>3 ){
|
||||
fprintf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}else{
|
||||
int iLimit = -1;
|
||||
n2 = strlen30(azArg[1]);
|
||||
for(i=0; i<sizeof(aLimit)/sizeof(aLimit[0]); i++){
|
||||
if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
|
||||
if( iLimit<0 ){
|
||||
iLimit = i;
|
||||
}else{
|
||||
fprintf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( iLimit<0 ){
|
||||
fprintf(stderr, "unknown limit: \"%s\"\n"
|
||||
"enter \".limits\" with no arguments for a list.\n",
|
||||
azArg[1]);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
if( nArg==3 ){
|
||||
sqlite3_limit(p->db, aLimit[iLimit].limitCode,
|
||||
(int)integerValue(azArg[2]));
|
||||
}
|
||||
printf("%20s %d\n", aLimit[iLimit].zLimitName,
|
||||
sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
|
||||
}
|
||||
}else
|
||||
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
|
||||
@@ -3126,6 +3385,11 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
output_reset(p);
|
||||
if( zFile[0]=='|' ){
|
||||
#ifdef SQLITE_OMIT_POPEN
|
||||
fprintf(stderr,"Error: pipes are not supported in this OS\n");
|
||||
rc = 1;
|
||||
p->out = stdout;
|
||||
#else
|
||||
p->out = popen(zFile + 1, "w");
|
||||
if( p->out==0 ){
|
||||
fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
|
||||
@@ -3134,6 +3398,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
|
||||
}
|
||||
#endif
|
||||
}else{
|
||||
p->out = output_file_open(zFile);
|
||||
if( p->out==0 ){
|
||||
@@ -3333,7 +3598,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
|
||||
extern int sqlite3SelectTrace;
|
||||
sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
|
||||
sqlite3SelectTrace = integerValue(azArg[1]);
|
||||
}else
|
||||
#endif
|
||||
|
||||
@@ -3484,13 +3749,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
if( nRow>=nAlloc ){
|
||||
char **azNew;
|
||||
int n = nAlloc*2 + 10;
|
||||
azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n);
|
||||
int n2 = nAlloc*2 + 10;
|
||||
azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
|
||||
if( azNew==0 ){
|
||||
fprintf(stderr, "Error: out of memory\n");
|
||||
break;
|
||||
}
|
||||
nAlloc = n;
|
||||
nAlloc = n2;
|
||||
azResult = azNew;
|
||||
}
|
||||
azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
|
||||
@@ -3539,17 +3804,19 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
|
||||
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
|
||||
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
|
||||
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
|
||||
{ "imposter", SQLITE_TESTCTRL_IMPOSTER },
|
||||
};
|
||||
int testctrl = -1;
|
||||
int rc = 0;
|
||||
int i, n;
|
||||
int rc2 = 0;
|
||||
int i, n2;
|
||||
open_db(p, 0);
|
||||
|
||||
/* convert testctrl text option to value. allow any unique prefix
|
||||
** of the option name, or a numerical value. */
|
||||
n = strlen30(azArg[1]);
|
||||
n2 = strlen30(azArg[1]);
|
||||
for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
|
||||
if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
|
||||
if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
|
||||
if( testctrl<0 ){
|
||||
testctrl = aCtrl[i].ctrlCode;
|
||||
}else{
|
||||
@@ -3570,8 +3837,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
case SQLITE_TESTCTRL_RESERVE:
|
||||
if( nArg==3 ){
|
||||
int opt = (int)strtol(azArg[2], 0, 0);
|
||||
rc = sqlite3_test_control(testctrl, p->db, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
|
||||
rc2 = sqlite3_test_control(testctrl, p->db, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
|
||||
azArg[1]);
|
||||
@@ -3584,8 +3851,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
case SQLITE_TESTCTRL_PRNG_RESET:
|
||||
case SQLITE_TESTCTRL_BYTEORDER:
|
||||
if( nArg==2 ){
|
||||
rc = sqlite3_test_control(testctrl);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
|
||||
rc2 = sqlite3_test_control(testctrl);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
|
||||
}
|
||||
@@ -3595,8 +3862,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
case SQLITE_TESTCTRL_PENDING_BYTE:
|
||||
if( nArg==3 ){
|
||||
unsigned int opt = (unsigned int)integerValue(azArg[2]);
|
||||
rc = sqlite3_test_control(testctrl, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
|
||||
rc2 = sqlite3_test_control(testctrl, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes a single unsigned"
|
||||
" int option\n", azArg[1]);
|
||||
@@ -3605,11 +3872,12 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
/* sqlite3_test_control(int, int) */
|
||||
case SQLITE_TESTCTRL_ASSERT:
|
||||
case SQLITE_TESTCTRL_ALWAYS:
|
||||
case SQLITE_TESTCTRL_ALWAYS:
|
||||
case SQLITE_TESTCTRL_NEVER_CORRUPT:
|
||||
if( nArg==3 ){
|
||||
int opt = booleanValue(azArg[2]);
|
||||
rc = sqlite3_test_control(testctrl, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
|
||||
rc2 = sqlite3_test_control(testctrl, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
|
||||
azArg[1]);
|
||||
@@ -3621,8 +3889,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
case SQLITE_TESTCTRL_ISKEYWORD:
|
||||
if( nArg==3 ){
|
||||
const char *opt = azArg[2];
|
||||
rc = sqlite3_test_control(testctrl, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
|
||||
rc2 = sqlite3_test_control(testctrl, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
|
||||
azArg[1]);
|
||||
@@ -3630,6 +3898,18 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SQLITE_TESTCTRL_IMPOSTER:
|
||||
if( nArg==5 ){
|
||||
rc2 = sqlite3_test_control(testctrl, p->db,
|
||||
azArg[2],
|
||||
integerValue(azArg[3]),
|
||||
integerValue(azArg[4]));
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
|
||||
}else{
|
||||
fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case SQLITE_TESTCTRL_BITVEC_TEST:
|
||||
case SQLITE_TESTCTRL_FAULT_INSTALL:
|
||||
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
|
||||
@@ -3662,12 +3942,12 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
|
||||
open_db(p, 0);
|
||||
output_file_close(p->traceOut);
|
||||
if( nArg!=2 ){
|
||||
fprintf(stderr, "Usage: .trace FILE|off\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
output_file_close(p->traceOut);
|
||||
p->traceOut = output_file_open(azArg[1]);
|
||||
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
|
||||
if( p->traceOut==0 ){
|
||||
@@ -3932,6 +4212,7 @@ static int process_input(ShellState *p, FILE *in){
|
||||
&& sqlite3_complete(zSql) ){
|
||||
p->cnt = 0;
|
||||
open_db(p, 0);
|
||||
if( p->backslashOn ) resolve_backslashes(zSql);
|
||||
BEGIN_TIMER;
|
||||
rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
|
||||
END_TIMER;
|
||||
@@ -4043,7 +4324,7 @@ static char *find_home_dir(void){
|
||||
**
|
||||
** Returns the number of errors.
|
||||
*/
|
||||
static int process_sqliterc(
|
||||
static void process_sqliterc(
|
||||
ShellState *p, /* Configuration data */
|
||||
const char *sqliterc_override /* Name of config file. NULL to use default */
|
||||
){
|
||||
@@ -4051,15 +4332,13 @@ static int process_sqliterc(
|
||||
const char *sqliterc = sqliterc_override;
|
||||
char *zBuf = 0;
|
||||
FILE *in = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (sqliterc == NULL) {
|
||||
home_dir = find_home_dir();
|
||||
if( home_dir==0 ){
|
||||
#if !defined(__RTP__) && !defined(_WRS_KERNEL)
|
||||
fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0);
|
||||
#endif
|
||||
return 1;
|
||||
fprintf(stderr, "-- warning: cannot find home directory;"
|
||||
" cannot read ~/.sqliterc\n");
|
||||
return;
|
||||
}
|
||||
sqlite3_initialize();
|
||||
zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
|
||||
@@ -4070,11 +4349,10 @@ static int process_sqliterc(
|
||||
if( stdin_is_interactive ){
|
||||
fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
|
||||
}
|
||||
rc = process_input(p,in);
|
||||
process_input(p,in);
|
||||
fclose(in);
|
||||
}
|
||||
sqlite3_free(zBuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4178,7 +4456,7 @@ static char *cmdline_option_value(int argc, char **argv, int i){
|
||||
return argv[i];
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int SQLITE_CDECL main(int argc, char **argv){
|
||||
char *zErrMsg = 0;
|
||||
ShellState data;
|
||||
const char *zInitFile = 0;
|
||||
@@ -4196,6 +4474,8 @@ int main(int argc, char **argv){
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
setBinaryMode(stdin);
|
||||
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
|
||||
Argv0 = argv[0];
|
||||
main_init(&data);
|
||||
stdin_is_interactive = isatty(0);
|
||||
@@ -4348,10 +4628,7 @@ int main(int argc, char **argv){
|
||||
** is given on the command line, look for a file named ~/.sqliterc and
|
||||
** try to process it.
|
||||
*/
|
||||
rc = process_sqliterc(&data,zInitFile);
|
||||
if( rc>0 ){
|
||||
return rc;
|
||||
}
|
||||
process_sqliterc(&data,zInitFile);
|
||||
|
||||
/* Make a second pass through the command-line argument and set
|
||||
** options. This second pass is delayed until after the initialization
|
||||
@@ -4402,6 +4679,13 @@ int main(int argc, char **argv){
|
||||
data.statsOn = 1;
|
||||
}else if( strcmp(z,"-scanstats")==0 ){
|
||||
data.scanstatsOn = 1;
|
||||
}else if( strcmp(z,"-backslash")==0 ){
|
||||
/* Undocumented command-line option: -backslash
|
||||
** Causes C-style backslash escapes to be evaluated in SQL statements
|
||||
** prior to sending the SQL into SQLite. Useful for injecting
|
||||
** crazy bytes in the middle of SQL statements for testing and debugging.
|
||||
*/
|
||||
data.backslashOn = 1;
|
||||
}else if( strcmp(z,"-bail")==0 ){
|
||||
bail_on_error = 1;
|
||||
}else if( strcmp(z,"-version")==0 ){
|
||||
|
||||
+184
-63
@@ -43,11 +43,20 @@ extern "C" {
|
||||
|
||||
|
||||
/*
|
||||
** 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
|
||||
@@ -261,6 +270,7 @@ typedef sqlite_uint64 sqlite3_uint64;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Closing A Database Connection
|
||||
** DESTRUCTOR: sqlite3
|
||||
**
|
||||
** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
|
||||
** for the [sqlite3] object.
|
||||
@@ -312,6 +322,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
||||
|
||||
/*
|
||||
** CAPI3REF: One-Step Query Execution Interface
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** The sqlite3_exec() interface is a convenience wrapper around
|
||||
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
|
||||
@@ -751,14 +762,16 @@ struct sqlite3_io_methods {
|
||||
** 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
|
||||
@@ -883,7 +896,9 @@ struct sqlite3_io_methods {
|
||||
** [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]
|
||||
@@ -941,12 +956,19 @@ struct sqlite3_io_methods {
|
||||
** 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
|
||||
@@ -965,6 +987,13 @@ struct sqlite3_io_methods {
|
||||
#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
|
||||
@@ -1351,6 +1380,7 @@ int sqlite3_config(int, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configure database connections
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** The sqlite3_db_config() interface is used to make configuration
|
||||
** changes to a [database connection]. The interface is similar to
|
||||
@@ -1525,7 +1555,7 @@ struct sqlite3_mem_methods {
|
||||
** <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
|
||||
@@ -1736,7 +1766,6 @@ struct sqlite3_mem_methods {
|
||||
** 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
|
||||
@@ -1849,6 +1878,7 @@ struct sqlite3_mem_methods {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Enable Or Disable Extended Result Codes
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_extended_result_codes() routine enables or disables the
|
||||
** [extended result codes] feature of SQLite. ^The extended result
|
||||
@@ -1858,6 +1888,7 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Last Insert Rowid
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables)
|
||||
** has a unique 64-bit signed
|
||||
@@ -1909,6 +1940,7 @@ sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Count The Number Of Rows Modified
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This function returns the number of rows modified, inserted or
|
||||
** deleted by the most recently completed INSERT, UPDATE or DELETE
|
||||
@@ -1961,6 +1993,7 @@ int sqlite3_changes(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Total Number Of Rows Modified
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This function returns the total number of rows inserted, modified or
|
||||
** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
|
||||
@@ -1984,6 +2017,7 @@ int sqlite3_total_changes(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Interrupt A Long-Running Query
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This function causes any pending database operation to abort and
|
||||
** return at its earliest opportunity. This routine is typically
|
||||
@@ -2060,6 +2094,7 @@ int sqlite3_complete16(const void *sql);
|
||||
/*
|
||||
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
|
||||
** KEYWORDS: {busy-handler callback} {busy handler}
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
|
||||
** that might be invoked with argument P whenever
|
||||
@@ -2119,6 +2154,7 @@ int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Set A Busy Timeout
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps
|
||||
** for a specified amount of time when a table is locked. ^The handler
|
||||
@@ -2141,6 +2177,7 @@ int sqlite3_busy_timeout(sqlite3*, int ms);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Convenience Routines For Running Queries
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** This is a legacy interface that is preserved for backwards compatibility.
|
||||
** Use of this interface is not recommended.
|
||||
@@ -2226,6 +2263,10 @@ void sqlite3_free_table(char **result);
|
||||
**
|
||||
** 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()].
|
||||
@@ -2258,7 +2299,7 @@ void sqlite3_free_table(char **result);
|
||||
** 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.
|
||||
@@ -2311,6 +2352,12 @@ void sqlite3_free_table(char **result);
|
||||
** 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.)^
|
||||
@@ -2466,6 +2513,7 @@ void sqlite3_randomness(int N, void *P);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Compile-Time Authorization Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This routine registers an authorizer callback with a particular
|
||||
** [database connection], supplied in the first argument.
|
||||
@@ -2622,6 +2670,7 @@ int sqlite3_set_authorizer(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Tracing And Profiling Functions
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** These routines register callback functions that can be used for
|
||||
** tracing and profiling the execution of SQL statements.
|
||||
@@ -2654,6 +2703,7 @@ SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
|
||||
|
||||
/*
|
||||
** CAPI3REF: Query Progress Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
|
||||
** function X to be invoked periodically during long running calls to
|
||||
@@ -2687,6 +2737,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Opening A New Database Connection
|
||||
** CONSTRUCTOR: sqlite3
|
||||
**
|
||||
** ^These routines open an SQLite database file as specified by the
|
||||
** filename argument. ^The filename argument is interpreted as UTF-8 for
|
||||
@@ -2972,12 +3023,15 @@ sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Error Codes And Messages
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^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.
|
||||
@@ -3015,33 +3069,34 @@ const void *sqlite3_errmsg16(sqlite3*);
|
||||
const char *sqlite3_errstr(int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Statement Object
|
||||
** CAPI3REF: Prepared Statement Object
|
||||
** KEYWORDS: {prepared statement} {prepared statements}
|
||||
**
|
||||
** An instance of this object represents a single SQL statement.
|
||||
** This object is variously known as a "prepared statement" or a
|
||||
** "compiled SQL statement" or simply as a "statement".
|
||||
** An instance of this object represents a single SQL statement that
|
||||
** has been compiled into binary form and is ready to be evaluated.
|
||||
**
|
||||
** The life of a statement object goes something like this:
|
||||
** Think of each SQL statement as a separate computer program. The
|
||||
** original SQL text is source code. A prepared statement object
|
||||
** is the compiled object code. All SQL must be converted into a
|
||||
** prepared statement before it can be run.
|
||||
**
|
||||
** The life-cycle of a prepared statement object usually goes like this:
|
||||
**
|
||||
** <ol>
|
||||
** <li> Create the object using [sqlite3_prepare_v2()] or a related
|
||||
** function.
|
||||
** <li> Bind values to [host parameters] using the sqlite3_bind_*()
|
||||
** <li> Create the prepared statement object using [sqlite3_prepare_v2()].
|
||||
** <li> Bind values to [parameters] using the sqlite3_bind_*()
|
||||
** interfaces.
|
||||
** <li> Run the SQL by calling [sqlite3_step()] one or more times.
|
||||
** <li> Reset the statement using [sqlite3_reset()] then go back
|
||||
** <li> Reset the prepared statement using [sqlite3_reset()] then go back
|
||||
** to step 2. Do this zero or more times.
|
||||
** <li> Destroy the object using [sqlite3_finalize()].
|
||||
** </ol>
|
||||
**
|
||||
** Refer to documentation on individual methods above for additional
|
||||
** information.
|
||||
*/
|
||||
typedef struct sqlite3_stmt sqlite3_stmt;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-time Limits
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(This interface allows the size of various constructs to be limited
|
||||
** on a connection by connection basis. The first parameter is the
|
||||
@@ -3153,6 +3208,8 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
/*
|
||||
** CAPI3REF: Compiling An SQL Statement
|
||||
** KEYWORDS: {SQL statement compiler}
|
||||
** METHOD: sqlite3
|
||||
** CONSTRUCTOR: sqlite3_stmt
|
||||
**
|
||||
** To execute an SQL query, it must first be compiled into a byte-code
|
||||
** program using one of these routines.
|
||||
@@ -3166,16 +3223,14 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
** 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
|
||||
@@ -3262,6 +3317,7 @@ int sqlite3_prepare16_v2(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieving Statement SQL
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^This interface can be used to retrieve a saved copy of the original
|
||||
** SQL text used to create a [prepared statement] if that statement was
|
||||
@@ -3271,6 +3327,7 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
|
||||
** and only if the [prepared statement] X makes no direct changes to
|
||||
@@ -3302,6 +3359,7 @@ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
|
||||
** [prepared statement] S has been stepped at least once using
|
||||
@@ -3376,6 +3434,7 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** CAPI3REF: Binding Values To Prepared Statements
|
||||
** KEYWORDS: {host parameter} {host parameters} {host parameter name}
|
||||
** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding}
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
|
||||
** literals may be replaced by a [parameter] that matches one of following
|
||||
@@ -3494,6 +3553,7 @@ int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Number Of SQL Parameters
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^This routine can be used to find the number of [SQL parameters]
|
||||
** in a [prepared statement]. SQL parameters are tokens of the
|
||||
@@ -3514,6 +3574,7 @@ int sqlite3_bind_parameter_count(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Name Of A Host Parameter
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_bind_parameter_name(P,N) interface returns
|
||||
** the name of the N-th [SQL parameter] in the [prepared statement] P.
|
||||
@@ -3541,6 +3602,7 @@ const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Index Of A Parameter With A Given Name
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^Return the index of an SQL parameter given its name. ^The
|
||||
** index value returned is suitable for use as the second
|
||||
@@ -3557,6 +3619,7 @@ int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Reset All Bindings On A Prepared Statement
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset
|
||||
** the [sqlite3_bind_blob | bindings] on a [prepared statement].
|
||||
@@ -3566,6 +3629,7 @@ int sqlite3_clear_bindings(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Number Of Columns In A Result Set
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^Return the number of columns in the result set returned by the
|
||||
** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
|
||||
@@ -3577,6 +3641,7 @@ int sqlite3_column_count(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Column Names In A Result Set
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^These routines return the name assigned to a particular column
|
||||
** in the result set of a [SELECT] statement. ^The sqlite3_column_name()
|
||||
@@ -3606,6 +3671,7 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Source Of Data In A Query Result
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^These routines provide a means to determine the database, table, and
|
||||
** table column that is the origin of a particular result column in
|
||||
@@ -3658,6 +3724,7 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Declared Datatype Of A Query Result
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^(The first parameter is a [prepared statement].
|
||||
** If this statement is a [SELECT] statement and the Nth column of the
|
||||
@@ -3690,6 +3757,7 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Evaluate An SQL Statement
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** After a [prepared statement] has been prepared using either
|
||||
** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
|
||||
@@ -3769,6 +3837,7 @@ int sqlite3_step(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Number of columns in a result set
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_data_count(P) interface returns the number of columns in the
|
||||
** current row of the result set of [prepared statement] P.
|
||||
@@ -3822,6 +3891,7 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
/*
|
||||
** CAPI3REF: Result Values From A Query
|
||||
** KEYWORDS: {column access functions}
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** These routines form the "result set" interface.
|
||||
**
|
||||
@@ -3994,6 +4064,7 @@ sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Destroy A Prepared Statement Object
|
||||
** DESTRUCTOR: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_finalize() function is called to delete a [prepared statement].
|
||||
** ^If the most recent evaluation of the statement encountered no errors
|
||||
@@ -4021,6 +4092,7 @@ int sqlite3_finalize(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Reset A Prepared Statement Object
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** The sqlite3_reset() function is called to reset a [prepared statement]
|
||||
** object back to its initial state, ready to be re-executed.
|
||||
@@ -4050,6 +4122,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** KEYWORDS: {function creation routines}
|
||||
** KEYWORDS: {application-defined SQL function}
|
||||
** KEYWORDS: {application-defined SQL functions}
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^These functions (collectively known as "function creation routines")
|
||||
** are used to add SQL functions or aggregates or to redefine the behavior
|
||||
@@ -4204,8 +4277,8 @@ int sqlite3_create_function_v2(
|
||||
** 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*);
|
||||
@@ -4219,6 +4292,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
|
||||
|
||||
/*
|
||||
** CAPI3REF: Obtaining SQL Function Parameter Values
|
||||
** METHOD: sqlite3_value
|
||||
**
|
||||
** The C-language implementation of SQL functions and aggregates uses
|
||||
** this set of interface routines to access the parameter values on
|
||||
@@ -4277,6 +4351,7 @@ int sqlite3_value_numeric_type(sqlite3_value*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Obtain Aggregate Function Context
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** Implementations of aggregate SQL functions use this
|
||||
** routine to allocate memory for storing their state.
|
||||
@@ -4321,6 +4396,7 @@ void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
|
||||
|
||||
/*
|
||||
** CAPI3REF: User Data For Functions
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** ^The sqlite3_user_data() interface returns a copy of
|
||||
** the pointer that was the pUserData parameter (the 5th parameter)
|
||||
@@ -4335,6 +4411,7 @@ void *sqlite3_user_data(sqlite3_context*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection For Functions
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** ^The sqlite3_context_db_handle() interface returns a copy of
|
||||
** the pointer to the [database connection] (the 1st parameter)
|
||||
@@ -4346,6 +4423,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Function Auxiliary Data
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** These functions may be used by (non-aggregate) SQL functions to
|
||||
** associate metadata with argument values. If the same value is passed to
|
||||
@@ -4418,6 +4496,7 @@ typedef void (*sqlite3_destructor_type)(void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Setting The Result Of An SQL Function
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** These routines are used by the xFunc or xFinal callbacks that
|
||||
** implement SQL functions and aggregates. See
|
||||
@@ -4553,6 +4632,7 @@ void sqlite3_result_zeroblob(sqlite3_context*, int n);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Define New Collating Sequences
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^These functions add, remove, or modify a [collation] associated
|
||||
** with the [database connection] specified as the first argument.
|
||||
@@ -4655,6 +4735,7 @@ int sqlite3_create_collation16(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Collation Needed Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^To avoid having to register all collation sequences before a database
|
||||
** can be used, a single callback function may be registered with the
|
||||
@@ -4862,6 +4943,7 @@ SQLITE_EXTERN char *sqlite3_data_directory;
|
||||
/*
|
||||
** CAPI3REF: Test For Auto-Commit Mode
|
||||
** KEYWORDS: {autocommit mode}
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_get_autocommit() interface returns non-zero or
|
||||
** zero if the given database connection is or is not in autocommit mode,
|
||||
@@ -4884,6 +4966,7 @@ int sqlite3_get_autocommit(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Find The Database Handle Of A Prepared Statement
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_db_handle interface returns the [database connection] handle
|
||||
** to which a [prepared statement] belongs. ^The [database connection]
|
||||
@@ -4896,6 +4979,7 @@ sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Return The Filename For A Database Connection
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
|
||||
** associated with database N of connection D. ^The main database file
|
||||
@@ -4912,6 +4996,7 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine if a database is read-only
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N
|
||||
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
|
||||
@@ -4921,6 +5006,7 @@ int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Find the next prepared statement
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface returns a pointer to the next [prepared statement] after
|
||||
** pStmt associated with the [database connection] pDb. ^If pStmt is NULL
|
||||
@@ -4936,6 +5022,7 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Commit And Rollback Notification Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_commit_hook() interface registers a callback
|
||||
** function to be invoked whenever a transaction is [COMMIT | committed].
|
||||
@@ -4985,6 +5072,7 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Data Change Notification Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_update_hook() interface registers a callback function
|
||||
** with the [database connection] identified by the first argument
|
||||
@@ -5061,6 +5149,11 @@ void *sqlite3_update_hook(
|
||||
** 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.
|
||||
**
|
||||
@@ -5086,6 +5179,7 @@ int sqlite3_release_memory(int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Free Memory Used By A Database Connection
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
|
||||
** memory as possible from database connection D. Unlike the
|
||||
@@ -5163,6 +5257,7 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Extract Metadata About A Column Of A Table
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
|
||||
** information about column C of table T in database D
|
||||
@@ -5241,6 +5336,7 @@ int sqlite3_table_column_metadata(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Load An Extension
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface loads an SQLite extension library from the named file.
|
||||
**
|
||||
@@ -5282,6 +5378,7 @@ int sqlite3_load_extension(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Enable Or Disable Extension Loading
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^So as not to open security holes in older applications that are
|
||||
** unprepared to deal with [extension loading], and as a means of disabling
|
||||
@@ -5531,6 +5628,7 @@ struct sqlite3_index_info {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Register A Virtual Table Implementation
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^These routines are used to register a new [virtual table module] name.
|
||||
** ^Module names must be registered before
|
||||
@@ -5588,7 +5686,7 @@ int sqlite3_create_module_v2(
|
||||
*/
|
||||
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 */
|
||||
};
|
||||
@@ -5627,6 +5725,7 @@ int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Overload A Function For A Virtual Table
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(Virtual tables can provide alternative implementations of functions
|
||||
** using the [xFindFunction] method of the [virtual table module].
|
||||
@@ -5669,6 +5768,8 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Open A BLOB For Incremental I/O
|
||||
** METHOD: sqlite3
|
||||
** CONSTRUCTOR: sqlite3_blob
|
||||
**
|
||||
** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located
|
||||
** in row iRow, column zColumn, table zTable in database zDb;
|
||||
@@ -5750,6 +5851,7 @@ int sqlite3_blob_open(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Move a BLOB Handle to a New Row
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^This function is used to move an existing blob handle so that it points
|
||||
** to a different row of the same database table. ^The new row is identified
|
||||
@@ -5774,6 +5876,7 @@ SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Close A BLOB Handle
|
||||
** DESTRUCTOR: sqlite3_blob
|
||||
**
|
||||
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
|
||||
** unconditionally. Even if this routine returns an error code, the
|
||||
@@ -5796,6 +5899,7 @@ int sqlite3_blob_close(sqlite3_blob *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Return The Size Of An Open BLOB
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^Returns the size in bytes of the BLOB accessible via the
|
||||
** successfully opened [BLOB handle] in its only argument. ^The
|
||||
@@ -5811,6 +5915,7 @@ int sqlite3_blob_bytes(sqlite3_blob *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Read Data From A BLOB Incrementally
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^(This function is used to read data from an open [BLOB handle] into a
|
||||
** caller-supplied buffer. N bytes of data are copied into buffer Z
|
||||
@@ -5839,6 +5944,7 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Write Data Into A BLOB Incrementally
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^(This function is used to write data into an open [BLOB handle] from a
|
||||
** caller-supplied buffer. N bytes of data are copied from the buffer Z
|
||||
@@ -6166,6 +6272,7 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieve the mutex for a database connection
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface returns a pointer the [sqlite3_mutex] object that
|
||||
** serializes access to the [database connection] given in the argument
|
||||
@@ -6177,6 +6284,7 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Low-Level Control Of Database Files
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The [sqlite3_file_control()] interface makes a direct call to the
|
||||
** xFileControl method for the [sqlite3_io_methods] object associated
|
||||
@@ -6260,12 +6368,13 @@ int sqlite3_test_control(int op, ...);
|
||||
#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
|
||||
@@ -6279,19 +6388,22 @@ int sqlite3_test_control(int op, ...);
|
||||
** ^(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
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
@@ -6389,6 +6501,7 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Status
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface is used to retrieve runtime status information
|
||||
** about a single [database connection]. ^The first argument is the
|
||||
@@ -6517,6 +6630,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Status
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^(Each prepared statement maintains various
|
||||
** [SQLITE_STMTSTATUS counters] that measure the number
|
||||
@@ -6961,20 +7075,20 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** 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>
|
||||
**
|
||||
@@ -7020,6 +7134,7 @@ int sqlite3_backup_pagecount(sqlite3_backup *p);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Unlock Notification
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^When running in shared-cache mode, a database operation may fail with
|
||||
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
|
||||
@@ -7190,6 +7305,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Write-Ahead Log Commit Hook
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The [sqlite3_wal_hook()] function is used to register a callback that
|
||||
** is invoked each time data is committed to a database in wal mode.
|
||||
@@ -7229,6 +7345,7 @@ void *sqlite3_wal_hook(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configure an auto-checkpoint
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
|
||||
** [sqlite3_wal_hook()] that causes any database on [database connection] D
|
||||
@@ -7259,6 +7376,7 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Checkpoint a database
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
|
||||
** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
|
||||
@@ -7280,6 +7398,7 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Checkpoint a database
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint
|
||||
** operation on database X of [database connection] D in mode M. Status
|
||||
@@ -7534,6 +7653,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Scan Status
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** This interface returns information about the predicted and measured
|
||||
** performance for pStmt. Advanced applications can use this
|
||||
@@ -7571,6 +7691,7 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Zero Scan-Status Counters
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
|
||||
**
|
||||
|
||||
+92
-51
@@ -23,6 +23,11 @@
|
||||
*/
|
||||
#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
|
||||
@@ -357,6 +362,32 @@
|
||||
# define NEVER(X) (X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Declarations used for tracing the operating system interfaces.
|
||||
*/
|
||||
#if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \
|
||||
(defined(SQLITE_DEBUG) && SQLITE_OS_WIN)
|
||||
extern int sqlite3OSTrace;
|
||||
# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
|
||||
# define SQLITE_HAVE_OS_TRACE
|
||||
#else
|
||||
# define OSTRACE(X)
|
||||
# undef SQLITE_HAVE_OS_TRACE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Is the sqlite3ErrName() function needed in the build? Currently,
|
||||
** it is needed by "mutex_w32.c" (when debugging), "os_win.c" (when
|
||||
** OSTRACE is enabled), and by several "test*.c" files (which are
|
||||
** compiled using SQLITE_TEST).
|
||||
*/
|
||||
#if defined(SQLITE_HAVE_OS_TRACE) || defined(SQLITE_TEST) || \
|
||||
(defined(SQLITE_DEBUG) && SQLITE_OS_WIN)
|
||||
# define SQLITE_NEED_ERR_NAME
|
||||
#else
|
||||
# undef SQLITE_NEED_ERR_NAME
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if the input is an integer that is too large
|
||||
** to fit in 32-bits. This macro is used inside of various testcase()
|
||||
@@ -589,6 +620,20 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
|
||||
*/
|
||||
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.
|
||||
@@ -1087,11 +1132,13 @@ struct sqlite3 {
|
||||
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 */
|
||||
@@ -1205,6 +1252,7 @@ struct sqlite3 {
|
||||
#define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */
|
||||
#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */
|
||||
#define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */
|
||||
#define SQLITE_Vacuum 0x08000000 /* Currently in a VACUUM */
|
||||
|
||||
|
||||
/*
|
||||
@@ -1535,34 +1583,8 @@ struct VTable {
|
||||
};
|
||||
|
||||
/*
|
||||
** Each SQL table is represented in memory by an instance of the
|
||||
** following structure.
|
||||
**
|
||||
** Table.zName is the name of the table. The case of the original
|
||||
** CREATE TABLE statement is stored, but case is not significant for
|
||||
** comparisons.
|
||||
**
|
||||
** Table.nCol is the number of columns in this table. Table.aCol is a
|
||||
** pointer to an array of Column structures, one for each column.
|
||||
**
|
||||
** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of
|
||||
** the column that is that key. Otherwise Table.iPKey is negative. Note
|
||||
** that the datatype of the PRIMARY KEY must be INTEGER for this field to
|
||||
** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of
|
||||
** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid
|
||||
** is generated for each row of the table. TF_HasPrimaryKey is set if
|
||||
** the table has any PRIMARY KEY, INTEGER or otherwise.
|
||||
**
|
||||
** Table.tnum is the page number for the root BTree page of the table in the
|
||||
** database file. If Table.iDb is the index of the database table backend
|
||||
** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that
|
||||
** holds temporary tables and indices. If TF_Ephemeral is set
|
||||
** then the table is stored in a file that is automatically deleted
|
||||
** when the VDBE cursor to the table is closed. In this case Table.tnum
|
||||
** refers VDBE cursor number that holds the table open, not to the root
|
||||
** page number. Transient tables are used to hold the results of a
|
||||
** sub-query that appears instead of a real table name in the FROM clause
|
||||
** of a SELECT statement.
|
||||
** The schema for each SQL table and view is represented in memory
|
||||
** by an instance of the following structure.
|
||||
*/
|
||||
struct Table {
|
||||
char *zName; /* Name of the table or view */
|
||||
@@ -1574,11 +1596,11 @@ struct Table {
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
ExprList *pCheck; /* All CHECK constraints */
|
||||
#endif
|
||||
LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
|
||||
int tnum; /* Root BTree node for this table (see note above) */
|
||||
i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
|
||||
int tnum; /* Root BTree page for this table */
|
||||
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
|
||||
i16 nCol; /* Number of columns in this table */
|
||||
u16 nRef; /* Number of pointers to this Table */
|
||||
LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
|
||||
LogEst szTabRow; /* Estimated size of each table row in bytes */
|
||||
#ifdef SQLITE_ENABLE_COSTMULT
|
||||
LogEst costMult; /* Cost multiplier for using this table */
|
||||
@@ -1600,6 +1622,12 @@ struct Table {
|
||||
|
||||
/*
|
||||
** Allowed values for Table.tabFlags.
|
||||
**
|
||||
** TF_OOOHidden applies to virtual tables that have hidden columns that are
|
||||
** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING
|
||||
** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden,
|
||||
** the TF_OOOHidden attribute would apply in this case. Such tables require
|
||||
** special handling during INSERT processing.
|
||||
*/
|
||||
#define TF_Readonly 0x01 /* Read-only system table */
|
||||
#define TF_Ephemeral 0x02 /* An ephemeral table */
|
||||
@@ -1607,6 +1635,7 @@ struct Table {
|
||||
#define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */
|
||||
#define TF_Virtual 0x10 /* Is a virtual table */
|
||||
#define TF_WithoutRowid 0x20 /* No rowid used. PRIMARY KEY is the key */
|
||||
#define TF_OOOHidden 0x40 /* Out-of-Order hidden columns */
|
||||
|
||||
|
||||
/*
|
||||
@@ -2043,8 +2072,14 @@ struct Expr {
|
||||
#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
|
||||
@@ -2243,7 +2278,7 @@ struct SrcList {
|
||||
#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 */
|
||||
@@ -2357,11 +2392,12 @@ struct Select {
|
||||
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
||||
#define SF_Compound 0x0040 /* Part of a compound query */
|
||||
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
|
||||
#define SF_AllValues 0x0100 /* All terms of compound are VALUES */
|
||||
#define SF_MultiValue 0x0100 /* Single VALUES term with multiple rows */
|
||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||
#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() */
|
||||
|
||||
|
||||
/*
|
||||
@@ -2680,7 +2716,8 @@ struct AuthContext {
|
||||
#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 */
|
||||
|
||||
/*
|
||||
@@ -2739,7 +2776,7 @@ struct Trigger {
|
||||
* orconf -> stores the ON CONFLICT algorithm
|
||||
* pSelect -> If this is an INSERT INTO ... SELECT ... statement, then
|
||||
* this stores a pointer to the SELECT statement. Otherwise NULL.
|
||||
* target -> A token holding the quoted name of the table to insert into.
|
||||
* zTarget -> Dequoted name of the table to insert into.
|
||||
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
|
||||
* this stores values to be inserted. Otherwise NULL.
|
||||
* pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
|
||||
@@ -2747,12 +2784,12 @@ struct Trigger {
|
||||
* inserted into.
|
||||
*
|
||||
* (op == TK_DELETE)
|
||||
* target -> A token holding the quoted name of the table to delete from.
|
||||
* zTarget -> Dequoted name of the table to delete from.
|
||||
* pWhere -> The WHERE clause of the DELETE statement if one is specified.
|
||||
* Otherwise NULL.
|
||||
*
|
||||
* (op == TK_UPDATE)
|
||||
* target -> A token holding the quoted name of the table to update rows of.
|
||||
* zTarget -> Dequoted name of the table to update.
|
||||
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
|
||||
* Otherwise NULL.
|
||||
* pExprList -> A list of the columns to update and the expressions to update
|
||||
@@ -2764,8 +2801,8 @@ struct TriggerStep {
|
||||
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
|
||||
u8 orconf; /* OE_Rollback etc. */
|
||||
Trigger *pTrig; /* The trigger that this step is a part of */
|
||||
Select *pSelect; /* SELECT statment or RHS of INSERT INTO .. SELECT ... */
|
||||
Token target; /* Target table for DELETE, UPDATE, INSERT */
|
||||
Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */
|
||||
char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
|
||||
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
|
||||
ExprList *pExprList; /* SET clause for UPDATE. */
|
||||
IdList *pIdList; /* Column names for INSERT */
|
||||
@@ -2798,8 +2835,7 @@ struct StrAccum {
|
||||
char *zText; /* The string collected so far */
|
||||
int nChar; /* Length of the string so far */
|
||||
int nAlloc; /* Amount of space allocated in zText */
|
||||
int mxAlloc; /* Maximum allowed string length */
|
||||
u8 useMalloc; /* 0: none, 1: sqlite3DbMalloc, 2: sqlite3_malloc */
|
||||
int mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
|
||||
u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
|
||||
};
|
||||
#define STRACCUM_NOMEM 1
|
||||
@@ -3084,10 +3120,15 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
|
||||
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
|
||||
@@ -3111,7 +3152,7 @@ void sqlite3XPrintf(StrAccum*, u32, const char*, ...);
|
||||
char *sqlite3MPrintf(sqlite3*,const char*, ...);
|
||||
char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
|
||||
char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
||||
void sqlite3DebugPrintf(const char*, ...);
|
||||
#endif
|
||||
#if defined(SQLITE_TEST)
|
||||
@@ -3152,6 +3193,7 @@ ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
|
||||
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);
|
||||
@@ -3457,7 +3499,7 @@ void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
|
||||
u8 sqlite3HexToInt(int h);
|
||||
int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
|
||||
|
||||
#if defined(SQLITE_TEST)
|
||||
#if defined(SQLITE_NEED_ERR_NAME)
|
||||
const char *sqlite3ErrName(int);
|
||||
#endif
|
||||
|
||||
@@ -3466,7 +3508,7 @@ int sqlite3ReadSchema(Parse *pParse);
|
||||
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 *);
|
||||
@@ -3551,7 +3593,7 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
|
||||
int sqlite3ApiExit(sqlite3 *db, int);
|
||||
int sqlite3OpenTempDatabase(Parse *);
|
||||
|
||||
void sqlite3StrAccumInit(StrAccum*, char*, int, int);
|
||||
void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
|
||||
void sqlite3StrAccumAppend(StrAccum*,const char*,int);
|
||||
void sqlite3StrAccumAppendAll(StrAccum*,const char*);
|
||||
void sqlite3AppendChar(StrAccum*,int,char);
|
||||
@@ -3735,12 +3777,11 @@ void sqlite3MemJournalOpen(sqlite3_file *);
|
||||
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
|
||||
@@ -3770,7 +3811,7 @@ void sqlite3Put4byte(u8*, u32);
|
||||
#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)
|
||||
|
||||
+7
-5
@@ -98,15 +98,17 @@
|
||||
#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
|
||||
|
||||
+81
-13
@@ -21,10 +21,32 @@
|
||||
*/
|
||||
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,
|
||||
@@ -41,33 +63,60 @@ static SQLITE_WSD struct sqlite3StatType {
|
||||
#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];
|
||||
@@ -76,12 +125,14 @@ void sqlite3StatusSet(int op, int X){
|
||||
|
||||
/*
|
||||
** 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;
|
||||
@@ -89,13 +140,30 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
|
||||
#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
|
||||
|
||||
+3
-3
@@ -90,7 +90,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
||||
z = 0;
|
||||
}else{
|
||||
int n = sqlite3Strlen30(argv[i])+1;
|
||||
z = sqlite3_malloc( n );
|
||||
z = sqlite3_malloc64( n );
|
||||
if( z==0 ) goto malloc_failed;
|
||||
memcpy(z, argv[i], n);
|
||||
}
|
||||
@@ -139,7 +139,7 @@ int sqlite3_get_table(
|
||||
res.nData = 1;
|
||||
res.nAlloc = 20;
|
||||
res.rc = SQLITE_OK;
|
||||
res.azResult = sqlite3_malloc(sizeof(char*)*res.nAlloc );
|
||||
res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
|
||||
if( res.azResult==0 ){
|
||||
db->errCode = SQLITE_NOMEM;
|
||||
return SQLITE_NOMEM;
|
||||
@@ -167,7 +167,7 @@ int sqlite3_get_table(
|
||||
}
|
||||
if( res.nAlloc>res.nData ){
|
||||
char **azNew;
|
||||
azNew = sqlite3_realloc( res.azResult, sizeof(char*)*res.nData );
|
||||
azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
|
||||
if( azNew==0 ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
db->errCode = SQLITE_NOMEM;
|
||||
|
||||
+76
-25
@@ -661,9 +661,9 @@ static int DbWalHandler(
|
||||
#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
|
||||
@@ -1191,7 +1191,7 @@ static int dbPrepareAndBind(
|
||||
int n;
|
||||
u8 *data;
|
||||
const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
|
||||
char c = zType[0];
|
||||
c = zType[0];
|
||||
if( zVar[0]=='@' ||
|
||||
(c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){
|
||||
/* Load a BLOB type if the Tcl variable is a bytearray and
|
||||
@@ -2298,7 +2298,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
Tcl_DecrRefCount(pRet);
|
||||
}else{
|
||||
ClientData cd[2];
|
||||
ClientData cd2[2];
|
||||
DbEvalContext *p;
|
||||
Tcl_Obj *pArray = 0;
|
||||
Tcl_Obj *pScript;
|
||||
@@ -2312,42 +2312,57 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
|
||||
dbEvalInit(p, pDb, objv[2], pArray);
|
||||
|
||||
cd[0] = (void *)p;
|
||||
cd[1] = (void *)pScript;
|
||||
rc = DbEvalNextCmd(cd, interp, TCL_OK);
|
||||
cd2[0] = (void *)p;
|
||||
cd2[1] = (void *)pScript;
|
||||
rc = DbEvalNextCmd(cd2, interp, TCL_OK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** $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;
|
||||
@@ -2357,7 +2372,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
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;
|
||||
@@ -3429,7 +3444,7 @@ static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
|
||||
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;
|
||||
@@ -3689,7 +3704,44 @@ static int db_last_stmt_ptr(
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_ENABLE_DBSTAT_VTAB)
|
||||
/*
|
||||
** tclcmd: register_dbstat_vtab DB
|
||||
**
|
||||
** Cause the dbstat virtual table to be available on the connection DB
|
||||
*/
|
||||
static int sqlite3RegisterDbstatCmd(
|
||||
void *clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||
Tcl_AppendResult(interp, "dbstat not available because of "
|
||||
"SQLITE_OMIT_VIRTUALTABLE", (void*)0);
|
||||
return TCL_ERROR;
|
||||
#else
|
||||
struct SqliteDb { sqlite3 *db; };
|
||||
char *zDb;
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
zDb = Tcl_GetString(objv[1]);
|
||||
if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
|
||||
int sqlite3_dbstat_register(sqlite3*);
|
||||
sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
|
||||
sqlite3_dbstat_register(db);
|
||||
}
|
||||
return TCL_OK;
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
}
|
||||
#endif /* defined(SQLITE_TEST) || defined(SQLITE_ENABLE_DBSTAT_VTAB) */
|
||||
|
||||
/*
|
||||
** Configure the interpreter passed as the first argument to have access
|
||||
@@ -3713,11 +3765,10 @@ static void init_all(Tcl_Interp *interp){
|
||||
** of virtual table dbstat (source file test_stat.c). This command is
|
||||
** required for testfixture and sqlite3_analyzer, but not by the production
|
||||
** Tcl extension. */
|
||||
#if defined(SQLITE_TEST) || TCLSH==2
|
||||
{
|
||||
extern int SqlitetestStat_Init(Tcl_Interp*);
|
||||
SqlitetestStat_Init(interp);
|
||||
}
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_ENABLE_DBSTAT_VTAB)
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "register_dbstat_vtab", sqlite3RegisterDbstatCmd, 0, 0
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
|
||||
+38
-22
@@ -94,10 +94,7 @@ static int get_sqlite_pointer(
|
||||
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;
|
||||
}
|
||||
@@ -145,7 +142,8 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
|
||||
&& 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);
|
||||
@@ -310,7 +308,7 @@ static int test_exec_printf(
|
||||
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);
|
||||
@@ -357,7 +355,7 @@ static int test_exec_hex(
|
||||
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);
|
||||
@@ -442,7 +440,7 @@ static int test_exec(
|
||||
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);
|
||||
@@ -591,13 +589,13 @@ static int test_get_table_printf(
|
||||
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++){
|
||||
@@ -634,7 +632,7 @@ static int test_last_rowid(
|
||||
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;
|
||||
}
|
||||
@@ -774,7 +772,7 @@ static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){
|
||||
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);
|
||||
@@ -786,7 +784,7 @@ static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){
|
||||
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);
|
||||
@@ -2497,7 +2495,7 @@ static int test_bind(
|
||||
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;
|
||||
}
|
||||
@@ -3611,7 +3609,7 @@ static int test_prepare(
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -3681,7 +3679,7 @@ static int test_prepare_v2(
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -3722,7 +3720,7 @@ static int test_prepare_tkt3134(
|
||||
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;
|
||||
}
|
||||
@@ -4537,7 +4535,7 @@ static int get_autocommit(
|
||||
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;
|
||||
}
|
||||
@@ -5173,7 +5171,7 @@ static int file_control_lockproxy_test(
|
||||
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));
|
||||
@@ -5916,7 +5914,8 @@ static int test_test_control(
|
||||
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;
|
||||
@@ -5957,6 +5956,22 @@ static int test_test_control(
|
||||
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);
|
||||
@@ -5978,7 +5993,8 @@ static int test_getrusage(
|
||||
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
|
||||
|
||||
+10
-5
@@ -445,18 +445,21 @@ static int btree_varint_test(
|
||||
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;
|
||||
}
|
||||
@@ -465,13 +468,15 @@ static int btree_varint_test(
|
||||
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;
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ static int tcl_thread_argc(
|
||||
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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -315,7 +315,7 @@ static int tcl_client_argc(
|
||||
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;
|
||||
}
|
||||
|
||||
+2
-2
@@ -206,8 +206,8 @@ static int getColumnNames(
|
||||
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 );
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "tcl.h"
|
||||
#include <sqlite3.h>
|
||||
#include "sqlite3.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* These functions are implemented in main.c. */
|
||||
|
||||
+4
-1
@@ -16,6 +16,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
|
||||
/* These functions are implemented in main.c. */
|
||||
extern const char *sqlite3ErrName(int);
|
||||
@@ -295,12 +296,13 @@ static int test_blob_write(
|
||||
|
||||
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_INCRBLOB */
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetest_blob_Init(Tcl_Interp *interp){
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_ObjCmdProc *xProc;
|
||||
@@ -315,5 +317,6 @@ int Sqlitetest_blob_Init(Tcl_Interp *interp){
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_INCRBLOB */
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -650,7 +650,6 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
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 );
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@
|
||||
|
||||
#if !defined(SQLITE_TEST) || SQLITE_OS_UNIX
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
+16
-1
@@ -600,12 +600,26 @@ static void test_decode(
|
||||
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 },
|
||||
@@ -626,6 +640,7 @@ static int registerTestFunctions(sqlite3 *db){
|
||||
{ "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;
|
||||
|
||||
|
||||
+4
-4
@@ -85,7 +85,7 @@ static int intarrayCreate(
|
||||
char **pzErr /* Put error message text here */
|
||||
){
|
||||
int rc = SQLITE_NOMEM;
|
||||
intarray_vtab *pVtab = sqlite3_malloc(sizeof(intarray_vtab));
|
||||
intarray_vtab *pVtab = sqlite3_malloc64(sizeof(intarray_vtab));
|
||||
|
||||
if( pVtab ){
|
||||
memset(pVtab, 0, sizeof(intarray_vtab));
|
||||
@@ -102,7 +102,7 @@ static int intarrayCreate(
|
||||
static int intarrayOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
int rc = SQLITE_NOMEM;
|
||||
intarray_cursor *pCur;
|
||||
pCur = sqlite3_malloc(sizeof(intarray_cursor));
|
||||
pCur = sqlite3_malloc64(sizeof(intarray_cursor));
|
||||
if( pCur ){
|
||||
memset(pCur, 0, sizeof(intarray_cursor));
|
||||
*ppCursor = (sqlite3_vtab_cursor *)pCur;
|
||||
@@ -225,7 +225,7 @@ SQLITE_API int sqlite3_intarray_create(
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3_intarray *p;
|
||||
|
||||
*ppReturn = p = sqlite3_malloc( sizeof(*p) );
|
||||
*ppReturn = p = sqlite3_malloc64( sizeof(*p) );
|
||||
if( p==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -340,7 +340,7 @@ static int test_intarray_bind(
|
||||
pArray = (sqlite3_intarray*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
|
||||
n = objc - 2;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
a = sqlite3_malloc( sizeof(a[0])*n );
|
||||
a = sqlite3_malloc64( sizeof(a[0])*n );
|
||||
if( a==0 ){
|
||||
Tcl_AppendResult(interp, "SQLITE_NOMEM", (char*)0);
|
||||
return TCL_ERROR;
|
||||
|
||||
+5
-5
@@ -211,15 +211,15 @@ static int faultsimInstall(int install){
|
||||
faultsimBeginBenign, faultsimEndBenign
|
||||
);
|
||||
}else{
|
||||
sqlite3_mem_methods m;
|
||||
sqlite3_mem_methods m2;
|
||||
assert(memfault.m.xMalloc);
|
||||
|
||||
/* One should be able to reset the default memory allocator by storing
|
||||
** a zeroed allocator then calling GETMALLOC. */
|
||||
memset(&m, 0, sizeof(m));
|
||||
sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
|
||||
sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m);
|
||||
assert( memcmp(&m, &memfault.m, sizeof(m))==0 );
|
||||
memset(&m2, 0, sizeof(m2));
|
||||
sqlite3_config(SQLITE_CONFIG_MALLOC, &m2);
|
||||
sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m2);
|
||||
assert( memcmp(&m2, &memfault.m, sizeof(m2))==0 );
|
||||
|
||||
rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0);
|
||||
|
||||
+28
-12
@@ -286,7 +286,7 @@ static void multiplexFilename(
|
||||
static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
|
||||
if( iChunk>=pGroup->nReal ){
|
||||
struct multiplexReal *p;
|
||||
p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p));
|
||||
p = sqlite3_realloc64(pGroup->aReal, (iChunk+1)*sizeof(*p));
|
||||
if( p==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -297,7 +297,7 @@ static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
|
||||
if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
|
||||
char *z;
|
||||
int n = pGroup->nName;
|
||||
pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+5 );
|
||||
pGroup->aReal[iChunk].z = z = sqlite3_malloc64( n+5 );
|
||||
if( z==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -357,7 +357,7 @@ static sqlite3_file *multiplexSubOpen(
|
||||
}
|
||||
flags &= ~SQLITE_OPEN_CREATE;
|
||||
}
|
||||
pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
|
||||
pSubOpen = sqlite3_malloc64( pOrigVfs->szOsFile );
|
||||
if( pSubOpen==0 ){
|
||||
*rc = SQLITE_IOERR_NOMEM;
|
||||
return 0;
|
||||
@@ -524,7 +524,7 @@ static int multiplexOpen(
|
||||
nName = zName ? multiplexStrlen30(zName) : 0;
|
||||
sz = sizeof(multiplexGroup) /* multiplexGroup */
|
||||
+ nName + 1; /* zName */
|
||||
pGroup = sqlite3_malloc( sz );
|
||||
pGroup = sqlite3_malloc64( sz );
|
||||
if( pGroup==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -568,12 +568,15 @@ static int multiplexOpen(
|
||||
if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_int64 sz;
|
||||
sqlite3_int64 sz64;
|
||||
|
||||
rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
|
||||
rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz64);
|
||||
if( rc==SQLITE_OK && zName ){
|
||||
int bExists;
|
||||
if( sz==0 ){
|
||||
if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
|
||||
pGroup->bEnabled = 0;
|
||||
}else
|
||||
if( sz64==0 ){
|
||||
if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
|
||||
/* If opening a main journal file and the first chunk is zero
|
||||
** bytes in size, delete any subsequent chunks from the
|
||||
@@ -604,10 +607,10 @@ static int multiplexOpen(
|
||||
rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
|
||||
SQLITE_ACCESS_EXISTS, &bExists);
|
||||
bExists = multiplexSubSize(pGroup, 1, &rc)>0;
|
||||
if( rc==SQLITE_OK && bExists && sz==(sz&0xffff0000) && sz>0
|
||||
&& sz!=pGroup->szChunk ){
|
||||
pGroup->szChunk = (int)sz;
|
||||
}else if( rc==SQLITE_OK && !bExists && sz>pGroup->szChunk ){
|
||||
if( rc==SQLITE_OK && bExists && sz64==(sz64&0xffff0000) && sz64>0
|
||||
&& sz64!=pGroup->szChunk ){
|
||||
pGroup->szChunk = (int)sz64;
|
||||
}else if( rc==SQLITE_OK && !bExists && sz64>pGroup->szChunk ){
|
||||
pGroup->bEnabled = 0;
|
||||
}
|
||||
}
|
||||
@@ -652,7 +655,7 @@ static int multiplexDelete(
|
||||
*/
|
||||
int nName = (int)strlen(zName);
|
||||
char *z;
|
||||
z = sqlite3_malloc(nName + 5);
|
||||
z = sqlite3_malloc64(nName + 5);
|
||||
if( z==0 ){
|
||||
rc = SQLITE_IOERR_NOMEM;
|
||||
}else{
|
||||
@@ -1004,6 +1007,13 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
|
||||
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
|
||||
@@ -1015,6 +1025,12 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
|
||||
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;
|
||||
|
||||
+3
-3
@@ -595,9 +595,9 @@ static int fsOpen(
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( 0==(flags&(SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL)) ){
|
||||
tmp_file *p = (tmp_file *)pFile;
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->base.pMethods = &tmp_io_methods;
|
||||
tmp_file *p2 = (tmp_file *)pFile;
|
||||
memset(p2, 0, sizeof(*p2));
|
||||
p2->base.pMethods = &tmp_io_methods;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1131,7 +1131,6 @@ static int test_vfslog(
|
||||
|
||||
switch( (enum VL_enum)iSub ){
|
||||
case VL_ANNOTATE: {
|
||||
int rc;
|
||||
char *zVfs;
|
||||
char *zMsg;
|
||||
if( objc!=4 ){
|
||||
@@ -1148,7 +1147,6 @@ static int test_vfslog(
|
||||
break;
|
||||
}
|
||||
case VL_FINALIZE: {
|
||||
int rc;
|
||||
char *zVfs;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "VFS");
|
||||
@@ -1164,7 +1162,6 @@ static int test_vfslog(
|
||||
};
|
||||
|
||||
case VL_NEW: {
|
||||
int rc;
|
||||
char *zVfs;
|
||||
char *zParent;
|
||||
char *zLog;
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library.
|
||||
*/
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include "sqlite3.h"
|
||||
#include <tcl.h>
|
||||
|
||||
/* Solely for the UNUSED_PARAMETER() macro. */
|
||||
|
||||
+4
-2
@@ -365,8 +365,10 @@ static void sqllogOpenlog(struct SLConn *p){
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
** sqlite3demo_superunlock()
|
||||
*/
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include "sqlite3.h"
|
||||
#include <string.h> /* memset(), strlen() */
|
||||
#include <assert.h> /* assert() */
|
||||
|
||||
|
||||
+1
-1
@@ -608,7 +608,7 @@ static int blocking_prepare_v2_proc(
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
+10
-11
@@ -823,11 +823,12 @@ static int tvfsShmOpen(sqlite3_file *pFile){
|
||||
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;
|
||||
}
|
||||
@@ -966,16 +967,15 @@ static void tvfsShmBarrier(sqlite3_file *pFile){
|
||||
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(
|
||||
@@ -1080,7 +1080,7 @@ static int testvfs_obj_cmd(
|
||||
switch( aSubcmd[i].eCmd ){
|
||||
case CMD_SHM: {
|
||||
Tcl_Obj *pObj;
|
||||
int i, rc;
|
||||
int rc;
|
||||
TestvfsBuffer *pBuffer;
|
||||
char *zName;
|
||||
if( objc!=3 && objc!=4 ){
|
||||
@@ -1160,7 +1160,6 @@ static int testvfs_obj_cmd(
|
||||
};
|
||||
Tcl_Obj **apElem = 0;
|
||||
int nElem = 0;
|
||||
int i;
|
||||
int mask = 0;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "LIST");
|
||||
@@ -1531,7 +1530,7 @@ static int testvfs_cmd(
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -101,7 +101,7 @@ int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
||||
|
||||
|
||||
/********************************* 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>
|
||||
@@ -194,7 +194,7 @@ int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
||||
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 *************************/
|
||||
|
||||
|
||||
|
||||
+10
-12
@@ -390,10 +390,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
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;
|
||||
@@ -433,10 +430,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
break;
|
||||
}
|
||||
case TK_ILLEGAL: {
|
||||
sqlite3DbFree(db, *pzErrMsg);
|
||||
*pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
|
||||
sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"",
|
||||
&pParse->sLastToken);
|
||||
nErr++;
|
||||
goto abort_parse;
|
||||
}
|
||||
case TK_SEMI: {
|
||||
@@ -454,17 +449,22 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
}
|
||||
}
|
||||
abort_parse:
|
||||
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
|
||||
assert( nErr==0 );
|
||||
if( zSql[i]==0 && pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
|
||||
if( lastTokenParsed!=TK_SEMI ){
|
||||
sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
|
||||
pParse->zTail = &zSql[i];
|
||||
}
|
||||
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
|
||||
if( pParse->rc==SQLITE_OK && db->mallocFailed==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;
|
||||
@@ -518,8 +518,6 @@ abort_parse:
|
||||
pParse->pZombieTab = p->pNextZombie;
|
||||
sqlite3DeleteTable(db, p);
|
||||
}
|
||||
if( nErr>0 && pParse->rc==SQLITE_OK ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
assert( nErr==0 || pParse->rc!=SQLITE_OK );
|
||||
return nErr;
|
||||
}
|
||||
|
||||
+10
-10
@@ -193,7 +193,6 @@ void sqlite3BeginTrigger(
|
||||
/* Do not create a trigger on a system table */
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
|
||||
pParse->nErr++;
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
@@ -373,12 +372,12 @@ static TriggerStep *triggerStepAllocate(
|
||||
){
|
||||
TriggerStep *pTriggerStep;
|
||||
|
||||
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n);
|
||||
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
|
||||
if( pTriggerStep ){
|
||||
char *z = (char*)&pTriggerStep[1];
|
||||
memcpy(z, pName->z, pName->n);
|
||||
pTriggerStep->target.z = z;
|
||||
pTriggerStep->target.n = pName->n;
|
||||
sqlite3Dequote(z);
|
||||
pTriggerStep->zTarget = z;
|
||||
pTriggerStep->op = op;
|
||||
}
|
||||
return pTriggerStep;
|
||||
@@ -661,7 +660,7 @@ Trigger *sqlite3TriggersExist(
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert the pStep->target token into a SrcList and return a pointer
|
||||
** Convert the pStep->zTarget string into a SrcList and return a pointer
|
||||
** to that SrcList.
|
||||
**
|
||||
** This routine adds a specific database name, if needed, to the target when
|
||||
@@ -674,17 +673,17 @@ static SrcList *targetSrcList(
|
||||
Parse *pParse, /* The parsing context */
|
||||
TriggerStep *pStep /* The trigger containing the target token */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb; /* Index of the database to use */
|
||||
SrcList *pSrc; /* SrcList to be returned */
|
||||
|
||||
pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0);
|
||||
pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
|
||||
if( pSrc ){
|
||||
assert( pSrc->nSrc>0 );
|
||||
assert( pSrc->a!=0 );
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
|
||||
pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
|
||||
iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
|
||||
if( iDb==0 || iDb>=2 ){
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( iDb<pParse->db->nDb );
|
||||
assert( iDb<db->nDb );
|
||||
pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
|
||||
}
|
||||
}
|
||||
@@ -796,6 +795,7 @@ static void transferParseError(Parse *pTo, Parse *pFrom){
|
||||
if( pTo->nErr==0 ){
|
||||
pTo->zErrMsg = pFrom->zErrMsg;
|
||||
pTo->nErr = pFrom->nErr;
|
||||
pTo->rc = pFrom->rc;
|
||||
}else{
|
||||
sqlite3DbFree(pFrom->db, pFrom->zErrMsg);
|
||||
}
|
||||
|
||||
@@ -655,6 +655,7 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
while( zNum[0]=='0' ) zNum++;
|
||||
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
|
||||
v = v*10 + c;
|
||||
}
|
||||
|
||||
+5
-1
@@ -184,7 +184,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** 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
|
||||
@@ -250,6 +250,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
|
||||
** the contents to the temporary database.
|
||||
*/
|
||||
assert( (db->flags & SQLITE_Vacuum)==0 );
|
||||
db->flags |= SQLITE_Vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';'"
|
||||
@@ -257,6 +259,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
"WHERE type = 'table' AND name!='sqlite_sequence' "
|
||||
" AND coalesce(rootpage,1)>0"
|
||||
);
|
||||
assert( (db->flags & SQLITE_Vacuum)!=0 );
|
||||
db->flags &= ~SQLITE_Vacuum;
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy over the sequence table
|
||||
|
||||
+318
-225
File diff suppressed because it is too large
Load Diff
@@ -213,6 +213,7 @@ int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||
|
||||
void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
|
||||
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
|
||||
|
||||
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
|
||||
|
||||
+3
-9
@@ -313,14 +313,6 @@ struct ScanStatus {
|
||||
**
|
||||
** 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 */
|
||||
@@ -344,11 +336,13 @@ struct Vdbe {
|
||||
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 */
|
||||
|
||||
+38
-8
@@ -170,6 +170,10 @@ const void *sqlite3_value_text16le(sqlite3_value *pVal){
|
||||
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 */
|
||||
@@ -365,6 +369,9 @@ void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
|
||||
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);
|
||||
@@ -445,7 +452,7 @@ static int sqlite3Step(Vdbe *p){
|
||||
** 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;
|
||||
@@ -491,6 +498,9 @@ static int sqlite3Step(Vdbe *p){
|
||||
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);
|
||||
@@ -535,7 +545,7 @@ end_of_step:
|
||||
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
|
||||
@@ -623,16 +633,26 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** 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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -702,6 +722,11 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
||||
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;
|
||||
}
|
||||
@@ -725,6 +750,11 @@ void sqlite3_set_auxdata(
|
||||
|
||||
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;
|
||||
|
||||
+28
-20
@@ -1118,7 +1118,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
#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
|
||||
@@ -1782,13 +1782,29 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
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
|
||||
}
|
||||
|
||||
/*
|
||||
** Close all cursors in the current frame.
|
||||
*/
|
||||
static void closeCursorsInFrame(Vdbe *p){
|
||||
if( p->apCsr ){
|
||||
int i;
|
||||
for(i=0; i<p->nCursor; i++){
|
||||
VdbeCursor *pC = p->apCsr[i];
|
||||
if( pC ){
|
||||
sqlite3VdbeFreeCursor(p, pC);
|
||||
p->apCsr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy the values stored in the VdbeFrame structure to its Vdbe. This
|
||||
** is used, for example, when a trigger sub-program is halted to restore
|
||||
@@ -1796,6 +1812,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
*/
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
||||
Vdbe *v = pFrame->v;
|
||||
closeCursorsInFrame(v);
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
v->anExec = pFrame->anExec;
|
||||
#endif
|
||||
@@ -1830,17 +1847,7 @@ static void closeAllCursors(Vdbe *p){
|
||||
p->nFrame = 0;
|
||||
}
|
||||
assert( p->nFrame==0 );
|
||||
|
||||
if( p->apCsr ){
|
||||
int i;
|
||||
for(i=0; i<p->nCursor; i++){
|
||||
VdbeCursor *pC = p->apCsr[i];
|
||||
if( pC ){
|
||||
sqlite3VdbeFreeCursor(p, pC);
|
||||
p->apCsr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
closeCursorsInFrame(p);
|
||||
if( p->aMem ){
|
||||
releaseMemArray(&p->aMem[1], p->nMem);
|
||||
}
|
||||
@@ -2143,7 +2150,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
** 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 ){
|
||||
@@ -3373,7 +3380,8 @@ static void vdbeAssertFieldCountWithinLimits(
|
||||
|
||||
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++;
|
||||
@@ -3584,7 +3592,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
||||
** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
|
||||
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
|
||||
*/
|
||||
static int vdbeRecordCompareWithSkip(
|
||||
int sqlite3VdbeRecordCompareWithSkip(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* If true, skip the first field */
|
||||
@@ -3770,7 +3778,7 @@ int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2 /* Right key */
|
||||
){
|
||||
return vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
|
||||
return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -3858,7 +3866,7 @@ static int vdbeRecordCompareInt(
|
||||
}else if( pPKey2->nField>1 ){
|
||||
/* The first fields of the two keys are equal. Compare the trailing
|
||||
** fields. */
|
||||
res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
}else{
|
||||
/* The first fields of the two keys are equal and there are no trailing
|
||||
** fields. Return pPKey2->default_rc in this case. */
|
||||
@@ -3906,7 +3914,7 @@ static int vdbeRecordCompareString(
|
||||
res = nStr - pPKey2->aMem[0].n;
|
||||
if( res==0 ){
|
||||
if( pPKey2->nField>1 ){
|
||||
res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
}else{
|
||||
res = pPKey2->default_rc;
|
||||
}
|
||||
|
||||
+8
-3
@@ -154,12 +154,17 @@ int sqlite3_blob_open(
|
||||
Incrblob *pBlob = 0;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) || ppBlob==0 || zTable==0 ){
|
||||
if( ppBlob==0 ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#endif
|
||||
*ppBlob = 0;
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#endif
|
||||
flags = !!flags; /* flags = (flags ? 1 : 0); */
|
||||
*ppBlob = 0;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
@@ -373,7 +378,7 @@ static int blobReadWrite(
|
||||
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 ){
|
||||
|
||||
+125
-5
@@ -200,10 +200,11 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
||||
pMem->z[pMem->n] = 0;
|
||||
pMem->z[pMem->n+1] = 0;
|
||||
pMem->flags |= MEM_Term;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pMem->pScopyFrom = 0;
|
||||
#endif
|
||||
}
|
||||
pMem->flags &= ~MEM_Ephem;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pMem->pScopyFrom = 0;
|
||||
#endif
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -1090,7 +1091,7 @@ struct ValueNewStat4Ctx {
|
||||
** 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){
|
||||
@@ -1134,6 +1135,113 @@ 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
|
||||
@@ -1166,6 +1274,12 @@ static int valueFromExpr(
|
||||
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);
|
||||
@@ -1242,6 +1356,12 @@ static int valueFromExpr(
|
||||
}
|
||||
#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;
|
||||
|
||||
@@ -1528,7 +1648,7 @@ void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
|
||||
Mem *aMem = pRec->aMem;
|
||||
sqlite3 *db = aMem[0].db;
|
||||
for(i=0; i<nCol; i++){
|
||||
if( aMem[i].szMalloc ) sqlite3DbFree(db, aMem[i].zMalloc);
|
||||
sqlite3VdbeMemRelease(&aMem[i]);
|
||||
}
|
||||
sqlite3KeyInfoUnref(pRec->pKeyInfo);
|
||||
sqlite3DbFree(db, pRec);
|
||||
|
||||
+299
-100
@@ -291,6 +291,7 @@ struct MergeEngine {
|
||||
** after the thread has finished are not dire. So we don't worry about
|
||||
** memory barriers and such here.
|
||||
*/
|
||||
typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int);
|
||||
struct SortSubtask {
|
||||
SQLiteThread *pThread; /* Background thread, if any */
|
||||
int bDone; /* Set if thread is finished but not joined */
|
||||
@@ -298,10 +299,12 @@ struct SortSubtask {
|
||||
UnpackedRecord *pUnpacked; /* Space to unpack a record */
|
||||
SorterList list; /* List for thread to write to a PMA */
|
||||
int nPMA; /* Number of PMAs currently in file */
|
||||
SorterCompare xCompare; /* Compare function to use */
|
||||
SorterFile file; /* Temp file for level-0 PMAs */
|
||||
SorterFile file2; /* Space for other PMAs */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Main sorter structure. A single instance of this is allocated for each
|
||||
** sorter cursor created by the VDBE.
|
||||
@@ -328,9 +331,13 @@ struct VdbeSorter {
|
||||
u8 bUseThreads; /* True to use background threads */
|
||||
u8 iPrev; /* Previous thread used to flush PMA */
|
||||
u8 nTask; /* Size of aTask[] array */
|
||||
u8 typeMask;
|
||||
SortSubtask aTask[1]; /* One or more subtasks */
|
||||
};
|
||||
|
||||
#define SORTER_TYPE_INTEGER 0x01
|
||||
#define SORTER_TYPE_TEXT 0x02
|
||||
|
||||
/*
|
||||
** An instance of the following object is used to read records out of a
|
||||
** PMA, in sorted order. The next key to be read is cached in nKey/aKey.
|
||||
@@ -742,32 +749,162 @@ static int vdbePmaReaderInit(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** A version of vdbeSorterCompare() that assumes that it has already been
|
||||
** determined that the first field of key1 is equal to the first field of
|
||||
** key2.
|
||||
*/
|
||||
static int vdbeSorterCompareTail(
|
||||
SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
|
||||
int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
|
||||
const void *pKey1, int nKey1, /* Left side of comparison */
|
||||
const void *pKey2, int nKey2 /* Right side of comparison */
|
||||
){
|
||||
UnpackedRecord *r2 = pTask->pUnpacked;
|
||||
if( *pbKey2Cached==0 ){
|
||||
sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
|
||||
*pbKey2Cached = 1;
|
||||
}
|
||||
return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
|
||||
** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences
|
||||
** used by the comparison. Return the result of the comparison.
|
||||
**
|
||||
** Before returning, object (pTask->pUnpacked) is populated with the
|
||||
** unpacked version of key2. Or, if pKey2 is passed a NULL pointer, then it
|
||||
** is assumed that the (pTask->pUnpacked) structure already contains the
|
||||
** unpacked key to use as key2.
|
||||
** If IN/OUT parameter *pbKey2Cached is true when this function is called,
|
||||
** it is assumed that (pTask->pUnpacked) contains the unpacked version
|
||||
** of key2. If it is false, (pTask->pUnpacked) is populated with the unpacked
|
||||
** version of key2 and *pbKey2Cached set to true before returning.
|
||||
**
|
||||
** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set
|
||||
** to SQLITE_NOMEM.
|
||||
*/
|
||||
static int vdbeSorterCompare(
|
||||
SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
|
||||
int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
|
||||
const void *pKey1, int nKey1, /* Left side of comparison */
|
||||
const void *pKey2, int nKey2 /* Right side of comparison */
|
||||
){
|
||||
UnpackedRecord *r2 = pTask->pUnpacked;
|
||||
if( pKey2 ){
|
||||
if( !*pbKey2Cached ){
|
||||
sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
|
||||
*pbKey2Cached = 1;
|
||||
}
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, r2);
|
||||
}
|
||||
|
||||
/*
|
||||
** A specially optimized version of vdbeSorterCompare() that assumes that
|
||||
** the first field of each key is a TEXT value and that the collation
|
||||
** sequence to compare them with is BINARY.
|
||||
*/
|
||||
static int vdbeSorterCompareText(
|
||||
SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
|
||||
int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
|
||||
const void *pKey1, int nKey1, /* Left side of comparison */
|
||||
const void *pKey2, int nKey2 /* Right side of comparison */
|
||||
){
|
||||
const u8 * const p1 = (const u8 * const)pKey1;
|
||||
const u8 * const p2 = (const u8 * const)pKey2;
|
||||
const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */
|
||||
const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
int res;
|
||||
|
||||
getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2;
|
||||
getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2;
|
||||
res = memcmp(v1, v2, MIN(n1, n2));
|
||||
if( res==0 ){
|
||||
res = n1 - n2;
|
||||
}
|
||||
|
||||
if( res==0 ){
|
||||
if( pTask->pSorter->pKeyInfo->nField>1 ){
|
||||
res = vdbeSorterCompareTail(
|
||||
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
|
||||
);
|
||||
}
|
||||
}else{
|
||||
if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
|
||||
res = res * -1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** A specially optimized version of vdbeSorterCompare() that assumes that
|
||||
** the first field of each key is an INTEGER value.
|
||||
*/
|
||||
static int vdbeSorterCompareInt(
|
||||
SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
|
||||
int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
|
||||
const void *pKey1, int nKey1, /* Left side of comparison */
|
||||
const void *pKey2, int nKey2 /* Right side of comparison */
|
||||
){
|
||||
const u8 * const p1 = (const u8 * const)pKey1;
|
||||
const u8 * const p2 = (const u8 * const)pKey2;
|
||||
const int s1 = p1[1]; /* Left hand serial type */
|
||||
const int s2 = p2[1]; /* Right hand serial type */
|
||||
const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */
|
||||
const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */
|
||||
int res; /* Return value */
|
||||
|
||||
assert( (s1>0 && s1<7) || s1==8 || s1==9 );
|
||||
assert( (s2>0 && s2<7) || s2==8 || s2==9 );
|
||||
|
||||
if( s1>7 && s2>7 ){
|
||||
res = s1 - s2;
|
||||
}else{
|
||||
if( s1==s2 ){
|
||||
if( (*v1 ^ *v2) & 0x80 ){
|
||||
/* The two values have different signs */
|
||||
res = (*v1 & 0x80) ? -1 : +1;
|
||||
}else{
|
||||
/* The two values have the same sign. Compare using memcmp(). */
|
||||
static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
|
||||
int i;
|
||||
res = 0;
|
||||
for(i=0; i<aLen[s1]; i++){
|
||||
if( (res = v1[i] - v2[i]) ) break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( s2>7 ){
|
||||
res = +1;
|
||||
}else if( s1>7 ){
|
||||
res = -1;
|
||||
}else{
|
||||
res = s1 - s2;
|
||||
}
|
||||
assert( res!=0 );
|
||||
|
||||
if( res>0 ){
|
||||
if( *v1 & 0x80 ) res = -1;
|
||||
}else{
|
||||
if( *v2 & 0x80 ) res = +1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( res==0 ){
|
||||
if( pTask->pSorter->pKeyInfo->nField>1 ){
|
||||
res = vdbeSorterCompareTail(
|
||||
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
|
||||
);
|
||||
}
|
||||
}else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
|
||||
res = res * -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the temporary index cursor just opened as a sorter cursor.
|
||||
**
|
||||
@@ -835,9 +972,13 @@ int sqlite3VdbeSorterInit(
|
||||
pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
|
||||
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
|
||||
pKeyInfo->db = 0;
|
||||
if( nField && nWorker==0 ) pKeyInfo->nField = nField;
|
||||
if( nField && nWorker==0 ){
|
||||
pKeyInfo->nXField += (pKeyInfo->nField - nField);
|
||||
pKeyInfo->nField = nField;
|
||||
}
|
||||
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
|
||||
pSorter->nTask = nWorker + 1;
|
||||
pSorter->iPrev = nWorker-1;
|
||||
pSorter->bUseThreads = (pSorter->nTask>1);
|
||||
pSorter->db = db;
|
||||
for(i=0; i<pSorter->nTask; i++){
|
||||
@@ -863,6 +1004,12 @@ int sqlite3VdbeSorterInit(
|
||||
if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if( (pKeyInfo->nField+pKeyInfo->nXField)<13
|
||||
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
|
||||
){
|
||||
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -887,30 +1034,24 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
|
||||
*/
|
||||
static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){
|
||||
sqlite3DbFree(db, pTask->pUnpacked);
|
||||
pTask->pUnpacked = 0;
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
/* pTask->list.aMemory can only be non-zero if it was handed memory
|
||||
** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */
|
||||
if( pTask->list.aMemory ){
|
||||
sqlite3_free(pTask->list.aMemory);
|
||||
pTask->list.aMemory = 0;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
assert( pTask->list.aMemory==0 );
|
||||
vdbeSorterRecordFree(0, pTask->list.pList);
|
||||
}
|
||||
pTask->list.pList = 0;
|
||||
if( pTask->file.pFd ){
|
||||
sqlite3OsCloseFree(pTask->file.pFd);
|
||||
pTask->file.pFd = 0;
|
||||
pTask->file.iEof = 0;
|
||||
}
|
||||
if( pTask->file2.pFd ){
|
||||
sqlite3OsCloseFree(pTask->file2.pFd);
|
||||
pTask->file2.pFd = 0;
|
||||
pTask->file2.iEof = 0;
|
||||
}
|
||||
memset(pTask, 0, sizeof(SortSubtask));
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG_SORTER_THREADS
|
||||
@@ -1090,6 +1231,7 @@ void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
|
||||
for(i=0; i<pSorter->nTask; i++){
|
||||
SortSubtask *pTask = &pSorter->aTask[i];
|
||||
vdbeSortSubtaskCleanup(db, pTask);
|
||||
pTask->pSorter = pSorter;
|
||||
}
|
||||
if( pSorter->list.aMemory==0 ){
|
||||
vdbeSorterRecordFree(0, pSorter->list.pList);
|
||||
@@ -1151,6 +1293,7 @@ static int vdbeSorterOpenTempFile(
|
||||
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 |
|
||||
@@ -1198,28 +1341,42 @@ static void vdbeSorterMerge(
|
||||
){
|
||||
SorterRecord *pFinal = 0;
|
||||
SorterRecord **pp = &pFinal;
|
||||
void *pVal2 = p2 ? SRVAL(p2) : 0;
|
||||
int bCached = 0;
|
||||
|
||||
while( p1 && p2 ){
|
||||
int res;
|
||||
res = vdbeSorterCompare(pTask, SRVAL(p1), p1->nVal, pVal2, p2->nVal);
|
||||
res = pTask->xCompare(
|
||||
pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal
|
||||
);
|
||||
|
||||
if( res<=0 ){
|
||||
*pp = p1;
|
||||
pp = &p1->u.pNext;
|
||||
p1 = p1->u.pNext;
|
||||
pVal2 = 0;
|
||||
}else{
|
||||
*pp = p2;
|
||||
pp = &p2->u.pNext;
|
||||
pp = &p2->u.pNext;
|
||||
p2 = p2->u.pNext;
|
||||
if( p2==0 ) break;
|
||||
pVal2 = SRVAL(p2);
|
||||
bCached = 0;
|
||||
}
|
||||
}
|
||||
*pp = p1 ? p1 : p2;
|
||||
*ppOut = pFinal;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the SorterCompare function to compare values collected by the
|
||||
** sorter object passed as the only argument.
|
||||
*/
|
||||
static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){
|
||||
if( p->typeMask==SORTER_TYPE_INTEGER ){
|
||||
return vdbeSorterCompareInt;
|
||||
}else if( p->typeMask==SORTER_TYPE_TEXT ){
|
||||
return vdbeSorterCompareText;
|
||||
}
|
||||
return vdbeSorterCompare;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sort the linked list of records headed at pTask->pList. Return
|
||||
** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if
|
||||
@@ -1234,12 +1391,14 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
|
||||
rc = vdbeSortAllocUnpacked(pTask);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
p = pList->pList;
|
||||
pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter);
|
||||
|
||||
aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
|
||||
if( !aSlot ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
p = pList->pList;
|
||||
while( p ){
|
||||
SorterRecord *pNext;
|
||||
if( pList->aMemory ){
|
||||
@@ -1453,13 +1612,12 @@ static int vdbeMergeEngineStep(
|
||||
int i; /* Index of aTree[] to recalculate */
|
||||
PmaReader *pReadr1; /* First PmaReader to compare */
|
||||
PmaReader *pReadr2; /* Second PmaReader to compare */
|
||||
u8 *pKey2; /* To pReadr2->aKey, or 0 if record cached */
|
||||
int bCached = 0;
|
||||
|
||||
/* Find the first two PmaReaders to compare. The one that was just
|
||||
** advanced (iPrev) and the one next to it in the array. */
|
||||
pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)];
|
||||
pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)];
|
||||
pKey2 = pReadr2->aKey;
|
||||
|
||||
for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){
|
||||
/* Compare pReadr1 and pReadr2. Store the result in variable iRes. */
|
||||
@@ -1469,8 +1627,8 @@ static int vdbeMergeEngineStep(
|
||||
}else if( pReadr2->pFd==0 ){
|
||||
iRes = -1;
|
||||
}else{
|
||||
iRes = vdbeSorterCompare(pTask,
|
||||
pReadr1->aKey, pReadr1->nKey, pKey2, pReadr2->nKey
|
||||
iRes = pTask->xCompare(pTask, &bCached,
|
||||
pReadr1->aKey, pReadr1->nKey, pReadr2->aKey, pReadr2->nKey
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1492,9 +1650,9 @@ static int vdbeMergeEngineStep(
|
||||
if( iRes<0 || (iRes==0 && pReadr1<pReadr2) ){
|
||||
pMerger->aTree[i] = (int)(pReadr1 - pMerger->aReadr);
|
||||
pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ];
|
||||
pKey2 = pReadr2->aKey;
|
||||
bCached = 0;
|
||||
}else{
|
||||
if( pReadr1->pFd ) pKey2 = 0;
|
||||
if( pReadr1->pFd ) bCached = 0;
|
||||
pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr);
|
||||
pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ];
|
||||
}
|
||||
@@ -1601,6 +1759,16 @@ int sqlite3VdbeSorterWrite(
|
||||
int bFlush; /* True to flush contents of memory to PMA */
|
||||
int nReq; /* Bytes of memory required */
|
||||
int nPMA; /* Bytes of PMA space required */
|
||||
int t; /* serial type of first record field */
|
||||
|
||||
getVarint32((const u8*)&pVal->z[1], t);
|
||||
if( t>0 && t<10 && t!=7 ){
|
||||
pSorter->typeMask &= SORTER_TYPE_INTEGER;
|
||||
}else if( t>10 && (t & 0x01) ){
|
||||
pSorter->typeMask &= SORTER_TYPE_TEXT;
|
||||
}else{
|
||||
pSorter->typeMask = 0;
|
||||
}
|
||||
|
||||
assert( pSorter );
|
||||
|
||||
@@ -1866,10 +2034,12 @@ static void vdbeMergeEngineCompare(
|
||||
}else if( p2->pFd==0 ){
|
||||
iRes = i1;
|
||||
}else{
|
||||
SortSubtask *pTask = pMerger->pTask;
|
||||
int bCached = 0;
|
||||
int res;
|
||||
assert( pMerger->pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */
|
||||
res = vdbeSorterCompare(
|
||||
pMerger->pTask, p1->aKey, p1->nKey, p2->aKey, p2->nKey
|
||||
assert( pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */
|
||||
res = pTask->xCompare(
|
||||
pTask, &bCached, p1->aKey, p1->nKey, p2->aKey, p2->nKey
|
||||
);
|
||||
if( res<=0 ){
|
||||
iRes = i1;
|
||||
@@ -1893,11 +2063,12 @@ static void vdbeMergeEngineCompare(
|
||||
#define INCRINIT_TASK 1
|
||||
#define INCRINIT_ROOT 2
|
||||
|
||||
/* Forward reference.
|
||||
** The vdbeIncrMergeInit() and vdbePmaReaderIncrMergeInit() routines call each
|
||||
** other (when building a merge tree).
|
||||
/*
|
||||
** Forward reference required as the vdbeIncrMergeInit() and
|
||||
** vdbePmaReaderIncrInit() routines are called mutually recursively when
|
||||
** building a merge tree.
|
||||
*/
|
||||
static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode);
|
||||
static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode);
|
||||
|
||||
/*
|
||||
** Initialize the MergeEngine object passed as the second argument. Once this
|
||||
@@ -1944,7 +2115,7 @@ static int vdbeMergeEngineInit(
|
||||
** better advantage of multi-processor hardware. */
|
||||
rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]);
|
||||
}else{
|
||||
rc = vdbePmaReaderIncrMergeInit(&pMerger->aReadr[i], INCRINIT_NORMAL);
|
||||
rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i], INCRINIT_NORMAL);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
@@ -1956,17 +2127,15 @@ static int vdbeMergeEngineInit(
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the IncrMerge field of a PmaReader.
|
||||
**
|
||||
** If the PmaReader passed as the first argument is not an incremental-reader
|
||||
** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it serves
|
||||
** to open and/or initialize the temp file related fields of the IncrMerge
|
||||
** The PmaReader passed as the first argument is guaranteed to be an
|
||||
** incremental-reader (pReadr->pIncr!=0). This function serves to open
|
||||
** and/or initialize the temp file related fields of the IncrMerge
|
||||
** object at (pReadr->pIncr).
|
||||
**
|
||||
** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders
|
||||
** in the sub-tree headed by pReadr are also initialized. Data is then loaded
|
||||
** into the buffers belonging to pReadr and it is set to
|
||||
** point to the first key in its range.
|
||||
** in the sub-tree headed by pReadr are also initialized. Data is then
|
||||
** loaded into the buffers belonging to pReadr and it is set to point to
|
||||
** the first key in its range.
|
||||
**
|
||||
** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed
|
||||
** to be a multi-threaded PmaReader and this function is being called in a
|
||||
@@ -1993,59 +2162,62 @@ static int vdbeMergeEngineInit(
|
||||
static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
|
||||
int rc = SQLITE_OK;
|
||||
IncrMerger *pIncr = pReadr->pIncr;
|
||||
SortSubtask *pTask = pIncr->pTask;
|
||||
sqlite3 *db = pTask->pSorter->db;
|
||||
|
||||
/* eMode is always INCRINIT_NORMAL in single-threaded mode */
|
||||
assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );
|
||||
|
||||
if( pIncr ){
|
||||
SortSubtask *pTask = pIncr->pTask;
|
||||
sqlite3 *db = pTask->pSorter->db;
|
||||
rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
|
||||
|
||||
rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
|
||||
|
||||
/* Set up the required files for pIncr. A multi-theaded IncrMerge object
|
||||
** requires two temp files to itself, whereas a single-threaded object
|
||||
** only requires a region of pTask->file2. */
|
||||
if( rc==SQLITE_OK ){
|
||||
int mxSz = pIncr->mxSz;
|
||||
/* Set up the required files for pIncr. A multi-theaded IncrMerge object
|
||||
** requires two temp files to itself, whereas a single-threaded object
|
||||
** only requires a region of pTask->file2. */
|
||||
if( rc==SQLITE_OK ){
|
||||
int mxSz = pIncr->mxSz;
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
if( pIncr->bUseThread ){
|
||||
rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd);
|
||||
}
|
||||
}else
|
||||
if( pIncr->bUseThread ){
|
||||
rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
/*if( !pIncr->bUseThread )*/{
|
||||
if( pTask->file2.pFd==0 ){
|
||||
assert( pTask->file2.iEof>0 );
|
||||
rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd);
|
||||
pTask->file2.iEof = 0;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pIncr->aFile[1].pFd = pTask->file2.pFd;
|
||||
pIncr->iStartOff = pTask->file2.iEof;
|
||||
pTask->file2.iEof += mxSz;
|
||||
}
|
||||
/*if( !pIncr->bUseThread )*/{
|
||||
if( pTask->file2.pFd==0 ){
|
||||
assert( pTask->file2.iEof>0 );
|
||||
rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd);
|
||||
pTask->file2.iEof = 0;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pIncr->aFile[1].pFd = pTask->file2.pFd;
|
||||
pIncr->iStartOff = pTask->file2.iEof;
|
||||
pTask->file2.iEof += mxSz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
if( rc==SQLITE_OK && pIncr->bUseThread ){
|
||||
/* Use the current thread to populate aFile[1], even though this
|
||||
** PmaReader is multi-threaded. The reason being that this function
|
||||
** is already running in background thread pIncr->pTask->thread. */
|
||||
assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK );
|
||||
rc = vdbeIncrPopulate(pIncr);
|
||||
}
|
||||
if( rc==SQLITE_OK && pIncr->bUseThread ){
|
||||
/* Use the current thread to populate aFile[1], even though this
|
||||
** PmaReader is multi-threaded. If this is an INCRINIT_TASK object,
|
||||
** then this function is already running in background thread
|
||||
** pIncr->pTask->thread.
|
||||
**
|
||||
** If this is the INCRINIT_ROOT object, then it is running in the
|
||||
** main VDBE thread. But that is Ok, as that thread cannot return
|
||||
** control to the VDBE or proceed with anything useful until the
|
||||
** first results are ready from this merger object anyway.
|
||||
*/
|
||||
assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK );
|
||||
rc = vdbeIncrPopulate(pIncr);
|
||||
}
|
||||
#endif
|
||||
|
||||
if( rc==SQLITE_OK
|
||||
&& (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK)
|
||||
){
|
||||
rc = vdbePmaReaderNext(pReadr);
|
||||
}
|
||||
if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){
|
||||
rc = vdbePmaReaderNext(pReadr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2054,7 +2226,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
|
||||
** The main routine for vdbePmaReaderIncrMergeInit() operations run in
|
||||
** background threads.
|
||||
*/
|
||||
static void *vdbePmaReaderBgInit(void *pCtx){
|
||||
static void *vdbePmaReaderBgIncrInit(void *pCtx){
|
||||
PmaReader *pReader = (PmaReader*)pCtx;
|
||||
void *pRet = SQLITE_INT_TO_PTR(
|
||||
vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK)
|
||||
@@ -2062,20 +2234,36 @@ static void *vdbePmaReaderBgInit(void *pCtx){
|
||||
pReader->pIncr->pTask->bDone = 1;
|
||||
return pRet;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Use a background thread to invoke vdbePmaReaderIncrMergeInit(INCRINIT_TASK)
|
||||
** on the PmaReader object passed as the first argument.
|
||||
**
|
||||
** This call will initialize the various fields of the pReadr->pIncr
|
||||
** structure and, if it is a multi-threaded IncrMerger, launch a
|
||||
** background thread to populate aFile[1].
|
||||
** If the PmaReader passed as the first argument is not an incremental-reader
|
||||
** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes
|
||||
** the vdbePmaReaderIncrMergeInit() function with the parameters passed to
|
||||
** this routine to initialize the incremental merge.
|
||||
**
|
||||
** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1),
|
||||
** then a background thread is launched to call vdbePmaReaderIncrMergeInit().
|
||||
** Or, if the IncrMerger is single threaded, the same function is called
|
||||
** using the current thread.
|
||||
*/
|
||||
static int vdbePmaReaderBgIncrInit(PmaReader *pReadr){
|
||||
void *pCtx = (void*)pReadr;
|
||||
return vdbeSorterCreateThread(pReadr->pIncr->pTask, vdbePmaReaderBgInit, pCtx);
|
||||
}
|
||||
static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){
|
||||
IncrMerger *pIncr = pReadr->pIncr; /* Incremental merger */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
if( pIncr ){
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
assert( pIncr->bUseThread==0 || eMode==INCRINIT_TASK );
|
||||
if( pIncr->bUseThread ){
|
||||
void *pCtx = (void*)pReadr;
|
||||
rc = vdbeSorterCreateThread(pIncr->pTask, vdbePmaReaderBgIncrInit, pCtx);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
rc = vdbePmaReaderIncrMergeInit(pReadr, eMode);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate a new MergeEngine object to merge the contents of nPMA level-0
|
||||
@@ -2287,6 +2475,11 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
|
||||
MergeEngine *pMain = 0;
|
||||
#if SQLITE_MAX_WORKER_THREADS
|
||||
sqlite3 *db = pTask0->pSorter->db;
|
||||
int i;
|
||||
SorterCompare xCompare = vdbeSorterGetCompare(pSorter);
|
||||
for(i=0; i<pSorter->nTask; i++){
|
||||
pSorter->aTask[i].xCompare = xCompare;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = vdbeSorterMergeTreeBuild(pSorter, &pMain);
|
||||
@@ -2315,15 +2508,21 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
|
||||
}
|
||||
}
|
||||
for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){
|
||||
/* Check that:
|
||||
**
|
||||
** a) The incremental merge object is configured to use the
|
||||
** right task, and
|
||||
** b) If it is using task (nTask-1), it is configured to run
|
||||
** in single-threaded mode. This is important, as the
|
||||
** root merge (INCRINIT_ROOT) will be using the same task
|
||||
** object.
|
||||
*/
|
||||
PmaReader *p = &pMain->aReadr[iTask];
|
||||
assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] );
|
||||
if( p->pIncr ){
|
||||
if( iTask==pSorter->nTask-1 ){
|
||||
rc = vdbePmaReaderIncrMergeInit(p, INCRINIT_TASK);
|
||||
}else{
|
||||
rc = vdbePmaReaderBgIncrInit(p);
|
||||
}
|
||||
}
|
||||
assert( p->pIncr==0 || (
|
||||
(p->pIncr->pTask==&pSorter->aTask[iTask]) /* a */
|
||||
&& (iTask!=pSorter->nTask-1 || p->pIncr->bUseThread==0) /* b */
|
||||
));
|
||||
rc = vdbePmaReaderIncrInit(p, INCRINIT_TASK);
|
||||
}
|
||||
}
|
||||
pMain = 0;
|
||||
|
||||
+6
-3
@@ -84,9 +84,8 @@ char *sqlite3VdbeExpandSql(
|
||||
char zBase[100]; /* Initial working space */
|
||||
|
||||
db = p->db;
|
||||
sqlite3StrAccumInit(&out, zBase, sizeof(zBase),
|
||||
sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase),
|
||||
db->aLimit[SQLITE_LIMIT_LENGTH]);
|
||||
out.db = db;
|
||||
if( db->nVdbeExec>1 ){
|
||||
while( *zRawSql ){
|
||||
const char *zStart = zRawSql;
|
||||
@@ -95,6 +94,8 @@ char *sqlite3VdbeExpandSql(
|
||||
assert( (zRawSql - zStart) > 0 );
|
||||
sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
|
||||
}
|
||||
}else if( p->nVar==0 ){
|
||||
sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql));
|
||||
}else{
|
||||
while( zRawSql[0] ){
|
||||
n = findNextHostParameter(zRawSql, &nToken);
|
||||
@@ -111,10 +112,12 @@ char *sqlite3VdbeExpandSql(
|
||||
idx = nextIndex;
|
||||
}
|
||||
}else{
|
||||
assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
|
||||
assert( zRawSql[0]==':' || zRawSql[0]=='$' ||
|
||||
zRawSql[0]=='@' || zRawSql[0]=='#' );
|
||||
testcase( zRawSql[0]==':' );
|
||||
testcase( zRawSql[0]=='$' );
|
||||
testcase( zRawSql[0]=='@' );
|
||||
testcase( zRawSql[0]=='#' );
|
||||
idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
|
||||
assert( idx>0 );
|
||||
}
|
||||
|
||||
+53
-19
@@ -24,6 +24,8 @@
|
||||
struct VtabCtx {
|
||||
VTable *pVTable; /* The virtual table being constructed */
|
||||
Table *pTab; /* The Table object to which the virtual table belongs */
|
||||
VtabCtx *pPrior; /* Parent context (if any) */
|
||||
int bDeclared; /* True after sqlite3_declare_vtab() is called */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -389,6 +391,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
char *zStmt;
|
||||
char *zWhere;
|
||||
int iDb;
|
||||
int iReg;
|
||||
Vdbe *v;
|
||||
|
||||
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */
|
||||
@@ -423,8 +426,10 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
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
|
||||
@@ -467,7 +472,7 @@ void sqlite3VtabArgExtend(Parse *pParse, Token *p){
|
||||
pArg->z = p->z;
|
||||
pArg->n = p->n;
|
||||
}else{
|
||||
assert(pArg->z < p->z);
|
||||
assert(pArg->z <= p->z);
|
||||
pArg->n = (int)(&p->z[p->n] - pArg->z);
|
||||
}
|
||||
}
|
||||
@@ -484,15 +489,27 @@ static int vtabCallConstructor(
|
||||
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
||||
char **pzErr
|
||||
){
|
||||
VtabCtx sCtx, *pPriorCtx;
|
||||
VtabCtx sCtx;
|
||||
VTable *pVTable;
|
||||
int rc;
|
||||
const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
||||
int nArg = pTab->nModuleArg;
|
||||
char *zErr = 0;
|
||||
char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
|
||||
char *zModuleName;
|
||||
int iDb;
|
||||
VtabCtx *pCtx;
|
||||
|
||||
/* Check that the virtual-table is not already being initialized */
|
||||
for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
|
||||
if( pCtx->pTab==pTab ){
|
||||
*pzErr = sqlite3MPrintf(db,
|
||||
"vtable constructor called recursively: %s", pTab->zName
|
||||
);
|
||||
return SQLITE_LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
|
||||
if( !zModuleName ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -513,11 +530,13 @@ static int vtabCallConstructor(
|
||||
assert( xConstruct );
|
||||
sCtx.pTab = pTab;
|
||||
sCtx.pVTable = pVTable;
|
||||
pPriorCtx = db->pVtabCtx;
|
||||
sCtx.pPrior = db->pVtabCtx;
|
||||
sCtx.bDeclared = 0;
|
||||
db->pVtabCtx = &sCtx;
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
|
||||
db->pVtabCtx = pPriorCtx;
|
||||
db->pVtabCtx = sCtx.pPrior;
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
assert( sCtx.pTab==pTab );
|
||||
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( zErr==0 ){
|
||||
@@ -533,13 +552,14 @@ static int vtabCallConstructor(
|
||||
memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
|
||||
pVTable->pVtab->pModule = pMod->pModule;
|
||||
pVTable->nRef = 1;
|
||||
if( sCtx.pTab ){
|
||||
if( sCtx.bDeclared==0 ){
|
||||
const char *zFormat = "vtable constructor did not declare schema: %s";
|
||||
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
|
||||
sqlite3VtabUnlock(pVTable);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
int iCol;
|
||||
u8 oooHidden = 0;
|
||||
/* If everything went according to plan, link the new VTable structure
|
||||
** into the linked list headed by pTab->pVTable. Then loop through the
|
||||
** columns of the table to see if any of them contain the token "hidden".
|
||||
@@ -552,7 +572,10 @@ static int vtabCallConstructor(
|
||||
char *zType = pTab->aCol[iCol].zType;
|
||||
int nType;
|
||||
int i = 0;
|
||||
if( !zType ) continue;
|
||||
if( !zType ){
|
||||
pTab->tabFlags |= oooHidden;
|
||||
continue;
|
||||
}
|
||||
nType = sqlite3Strlen30(zType);
|
||||
if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
|
||||
for(i=0; i<nType; i++){
|
||||
@@ -575,6 +598,9 @@ static int vtabCallConstructor(
|
||||
zType[i-1] = '\0';
|
||||
}
|
||||
pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN;
|
||||
oooHidden = TF_OOOHidden;
|
||||
}else{
|
||||
pTab->tabFlags |= oooHidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -703,21 +729,25 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
||||
** virtual table module.
|
||||
*/
|
||||
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
VtabCtx *pCtx;
|
||||
Parse *pParse;
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
Table *pTab;
|
||||
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) ){
|
||||
pCtx = db->pVtabCtx;
|
||||
if( !pCtx || pCtx->bDeclared ){
|
||||
sqlite3Error(db, SQLITE_MISUSE);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
pTab = pCtx->pTab;
|
||||
assert( (pTab->tabFlags & TF_Virtual)!=0 );
|
||||
|
||||
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
|
||||
@@ -740,7 +770,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
pParse->pNewTable->nCol = 0;
|
||||
pParse->pNewTable->aCol = 0;
|
||||
}
|
||||
db->pVtabCtx->pTab = 0;
|
||||
pCtx->bDeclared = 1;
|
||||
}else{
|
||||
sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
@@ -775,11 +805,15 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
|
||||
|
||||
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 );
|
||||
@@ -930,7 +964,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN );
|
||||
assert( iSavepoint>=0 );
|
||||
assert( iSavepoint>=-1 );
|
||||
if( db->aVTrans ){
|
||||
int i;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
|
||||
@@ -1048,7 +1082,7 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
|
||||
if( pTab==pToplevel->apVtabLock[i] ) return;
|
||||
}
|
||||
n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
|
||||
apVtabLock = sqlite3_realloc(pToplevel->apVtabLock, n);
|
||||
apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
|
||||
if( apVtabLock ){
|
||||
pToplevel->apVtabLock = apVtabLock;
|
||||
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
** 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) */
|
||||
@@ -522,7 +522,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
|
||||
if( pWal->nWiData<=iPage ){
|
||||
int nByte = sizeof(u32*)*(iPage+1);
|
||||
volatile u32 **apNew;
|
||||
apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
|
||||
apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
|
||||
if( !apNew ){
|
||||
*ppPage = 0;
|
||||
return SQLITE_NOMEM;
|
||||
@@ -788,9 +788,10 @@ static void walUnlockShared(Wal *pWal, int lockIdx){
|
||||
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,
|
||||
@@ -1076,7 +1077,7 @@ static int walIndexRecover(Wal *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;
|
||||
}
|
||||
@@ -1146,7 +1147,7 @@ static int walIndexRecover(Wal *pWal){
|
||||
|
||||
/* Malloc a buffer to read frames into. */
|
||||
szFrame = szPage + WAL_FRAME_HDRSIZE;
|
||||
aFrame = (u8 *)sqlite3_malloc(szFrame);
|
||||
aFrame = (u8 *)sqlite3_malloc64(szFrame);
|
||||
if( !aFrame ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto recovery_error;
|
||||
@@ -1539,7 +1540,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
|
||||
nByte = sizeof(WalIterator)
|
||||
+ (nSegment-1)*sizeof(struct WalSegment)
|
||||
+ iLast*sizeof(ht_slot);
|
||||
p = (WalIterator *)sqlite3_malloc(nByte);
|
||||
p = (WalIterator *)sqlite3_malloc64(nByte);
|
||||
if( !p ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -1549,7 +1550,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
|
||||
/* Allocate temporary space used by the merge-sort routine. This block
|
||||
** of memory will be freed before this function returns.
|
||||
*/
|
||||
aTmp = (ht_slot *)sqlite3_malloc(
|
||||
aTmp = (ht_slot *)sqlite3_malloc64(
|
||||
sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
|
||||
);
|
||||
if( !aTmp ){
|
||||
@@ -1610,7 +1611,7 @@ static int walBusyLock(
|
||||
){
|
||||
int rc;
|
||||
do {
|
||||
rc = walLockExclusive(pWal, lockIdx, n);
|
||||
rc = walLockExclusive(pWal, lockIdx, n, 0);
|
||||
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
|
||||
return rc;
|
||||
}
|
||||
@@ -1729,6 +1730,14 @@ static int walCheckpoint(
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
/* Thread-sanitizer reports that the following is an unsafe read,
|
||||
** as some other thread may be in the process of updating the value
|
||||
** of the aReadMark[] slot. The assumption here is that if that is
|
||||
** happening, the other client may only be increasing the value,
|
||||
** not decreasing it. So assuming either that either the "old" or
|
||||
** "new" version of the value is read, and not some arbitrary value
|
||||
** that would never be written by a real client, things are still
|
||||
** safe. */
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
if( mxSafeFrame>y ){
|
||||
assert( y<=pWal->hdr.mxFrame );
|
||||
@@ -2043,7 +2052,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
||||
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);
|
||||
@@ -2249,7 +2258,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
&& (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;
|
||||
@@ -2505,7 +2514,7 @@ int sqlite3WalBeginWriteTransaction(Wal *pWal){
|
||||
/* 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;
|
||||
}
|
||||
@@ -2650,7 +2659,7 @@ static int walRestartLog(Wal *pWal){
|
||||
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
|
||||
@@ -2975,7 +2984,7 @@ int sqlite3WalCheckpoint(
|
||||
|
||||
/* 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
|
||||
|
||||
+419
-84
@@ -202,7 +202,7 @@ static void whereClauseClear(WhereClause *pWC){
|
||||
** 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 );
|
||||
@@ -255,13 +255,14 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
|
||||
** all terms of the WHERE clause.
|
||||
*/
|
||||
static void whereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
|
||||
Expr *pE2 = sqlite3ExprSkipCollate(pExpr);
|
||||
pWC->op = op;
|
||||
if( pExpr==0 ) return;
|
||||
if( pExpr->op!=op ){
|
||||
if( pE2==0 ) return;
|
||||
if( pE2->op!=op ){
|
||||
whereClauseInsert(pWC, pExpr, 0);
|
||||
}else{
|
||||
whereSplit(pWC, pExpr->pLeft, op);
|
||||
whereSplit(pWC, pExpr->pRight, op);
|
||||
whereSplit(pWC, pE2->pLeft, op);
|
||||
whereSplit(pWC, pE2->pRight, op);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,7 +628,11 @@ static void exprAnalyzeAll(
|
||||
** 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 */
|
||||
@@ -656,7 +661,7 @@ static int isLikeOrGlob(
|
||||
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. */
|
||||
@@ -766,6 +771,79 @@ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){
|
||||
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
|
||||
@@ -790,6 +868,7 @@ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){
|
||||
** (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:
|
||||
**
|
||||
@@ -806,6 +885,16 @@ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){
|
||||
**
|
||||
** 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
|
||||
@@ -932,12 +1021,26 @@ static void exprAnalyzeOrTerm(
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
@@ -1067,7 +1170,7 @@ static void exprAnalyzeOrTerm(
|
||||
}else{
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
}
|
||||
pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
|
||||
pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1105,7 +1208,7 @@ static void exprAnalyze(
|
||||
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 */
|
||||
@@ -1243,12 +1346,15 @@ static void exprAnalyze(
|
||||
/* 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)
|
||||
@@ -1259,10 +1365,26 @@ static void exprAnalyze(
|
||||
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];
|
||||
@@ -1279,22 +1401,21 @@ static void exprAnalyze(
|
||||
}
|
||||
*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];
|
||||
@@ -1412,7 +1533,7 @@ static int findIndexCol(
|
||||
&& p->iTable==iBase
|
||||
){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
|
||||
if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){
|
||||
if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -1612,12 +1733,16 @@ static void constructAutomaticIndex(
|
||||
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;
|
||||
@@ -1682,7 +1807,7 @@ static void constructAutomaticIndex(
|
||||
idxCols |= cMask;
|
||||
pIdx->aiColumn[n] = pTerm->u.leftColumn;
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
|
||||
pIdx->azColl[n] = ALWAYS(pColl) ? pColl->zName : "BINARY";
|
||||
pIdx->azColl[n] = pColl ? pColl->zName : "BINARY";
|
||||
n++;
|
||||
}
|
||||
}
|
||||
@@ -1904,11 +2029,14 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
** 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 */
|
||||
@@ -1919,67 +2047,158 @@ static int whereKeyStats(
|
||||
){
|
||||
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);
|
||||
if( res<0 ){
|
||||
iMin = iTest+1;
|
||||
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{
|
||||
i = iTest;
|
||||
n = iTest + 1;
|
||||
}
|
||||
}while( res && iMin<i );
|
||||
|
||||
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{
|
||||
iSample = iTest;
|
||||
iCol = n-1;
|
||||
}
|
||||
}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{
|
||||
@@ -1991,7 +2210,11 @@ static int whereKeyStats(
|
||||
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 */
|
||||
@@ -2465,20 +2688,43 @@ static int whereInScanEst(
|
||||
** 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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2857,8 +3103,7 @@ static int explainOneScan(
|
||||
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
|
||||
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
|
||||
|
||||
sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
|
||||
str.db = db;
|
||||
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
|
||||
sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
|
||||
if( pItem->pSelect ){
|
||||
sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
|
||||
@@ -2962,7 +3207,34 @@ static void addScanStatus(
|
||||
# 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
|
||||
@@ -3292,10 +3564,25 @@ static Bitmask codeOneLoopStart(
|
||||
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
|
||||
@@ -3338,6 +3625,7 @@ static Bitmask codeOneLoopStart(
|
||||
if( pRangeStart ){
|
||||
Expr *pRight = pRangeStart->pExpr->pRight;
|
||||
sqlite3ExprCode(pParse, pRight, regBase+nEq);
|
||||
whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
|
||||
if( (pRangeStart->wtFlags & TERM_VNULL)==0
|
||||
&& sqlite3ExprCanBeNull(pRight)
|
||||
){
|
||||
@@ -3383,6 +3671,7 @@ static Bitmask codeOneLoopStart(
|
||||
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)
|
||||
){
|
||||
@@ -3610,7 +3899,8 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
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 ){
|
||||
@@ -3772,6 +4062,7 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
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;
|
||||
@@ -3786,7 +4077,13 @@ static Bitmask codeOneLoopStart(
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -4005,6 +4302,13 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
|
||||
*/
|
||||
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
if( ALWAYS(pWInfo) ){
|
||||
int i;
|
||||
for(i=0; i<pWInfo->nLevel; i++){
|
||||
WhereLevel *pLevel = &pWInfo->a[i];
|
||||
if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
|
||||
sqlite3DbFree(db, pLevel->u.in.aInLoop);
|
||||
}
|
||||
}
|
||||
whereClauseClear(&pWInfo->sWC);
|
||||
while( pWInfo->pLoops ){
|
||||
WhereLoop *p = pWInfo->pLoops;
|
||||
@@ -4451,6 +4755,10 @@ static int whereLoopAddBtreeIndex(
|
||||
}
|
||||
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;
|
||||
@@ -4480,7 +4788,7 @@ static int whereLoopAddBtreeIndex(
|
||||
}else if( eOp & (WO_EQ) ){
|
||||
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
||||
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
|
||||
if( iCol>=0 && !IsUniqueIndex(pProbe) ){
|
||||
if( iCol>=0 && pProbe->uniqNotNull==0 ){
|
||||
pNew->wsFlags |= WHERE_UNQ_WANTED;
|
||||
}else{
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
@@ -4494,6 +4802,17 @@ static int whereLoopAddBtreeIndex(
|
||||
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 );
|
||||
@@ -4695,8 +5014,9 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
|
||||
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;
|
||||
}
|
||||
@@ -4803,6 +5123,7 @@ static int whereLoopAddBtree(
|
||||
#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
|
||||
@@ -5686,10 +6007,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
|
||||
/* 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 ){
|
||||
@@ -5927,7 +6248,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
pWInfo->revMask = pFrom->revLoop;
|
||||
}
|
||||
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
|
||||
&& pWInfo->nOBSat==pWInfo->pOrderBy->nExpr
|
||||
&& pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
|
||||
){
|
||||
Bitmask revMask = 0;
|
||||
int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy,
|
||||
@@ -6332,7 +6653,6 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
#ifdef WHERETRACE_ENABLED /* !=0 */
|
||||
if( sqlite3WhereTrace ){
|
||||
int ii;
|
||||
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
|
||||
if( pWInfo->nOBSat>0 ){
|
||||
sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
|
||||
@@ -6487,6 +6807,12 @@ WhereInfo *sqlite3WhereBegin(
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -6579,7 +6905,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
|
||||
sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
|
||||
}
|
||||
sqlite3DbFree(db, pLevel->u.in.aInLoop);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
|
||||
if( pLevel->addrSkip ){
|
||||
@@ -6588,6 +6913,16 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
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
|
||||
|
||||
+6
-1
@@ -69,6 +69,8 @@ struct WhereLevel {
|
||||
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 */
|
||||
@@ -253,7 +255,7 @@ struct WhereTerm {
|
||||
} 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 */
|
||||
@@ -275,6 +277,9 @@ struct WhereTerm {
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user