|
@@ -137,7 +137,7 @@ extern "C" {
|
|
|
*/
|
|
*/
|
|
|
#define SQLITE_VERSION "3.8.3"
|
|
#define SQLITE_VERSION "3.8.3"
|
|
|
#define SQLITE_VERSION_NUMBER 3008003
|
|
#define SQLITE_VERSION_NUMBER 3008003
|
|
|
-#define SQLITE_SOURCE_ID "2014-01-31 11:50:20 21ce9e3a53aed62fbe075b0dbed9faa00218aadc"
|
|
|
|
|
|
|
+#define SQLITE_SOURCE_ID "2014-02-03 17:04:29 b60cc11ef775c23a2245d9e7a00dab34013f3ccb"
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
@@ -37317,7 +37317,8 @@ struct PCache {
|
|
|
int szCache; /* Configured cache size */
|
|
int szCache; /* Configured cache size */
|
|
|
int szPage; /* Size of every page in this cache */
|
|
int szPage; /* Size of every page in this cache */
|
|
|
int szExtra; /* Size of extra space for each page */
|
|
int szExtra; /* Size of extra space for each page */
|
|
|
- int bPurgeable; /* True if pages are on backing store */
|
|
|
|
|
|
|
+ u8 bPurgeable; /* True if pages are on backing store */
|
|
|
|
|
+ u8 eCreate; /* eCreate value for for xFetch() */
|
|
|
int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
|
|
int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
|
|
|
void *pStress; /* Argument to xStress */
|
|
void *pStress; /* Argument to xStress */
|
|
|
sqlite3_pcache *pCache; /* Pluggable cache module */
|
|
sqlite3_pcache *pCache; /* Pluggable cache module */
|
|
@@ -37384,6 +37385,10 @@ static void pcacheRemoveFromDirtyList(PgHdr *pPage){
|
|
|
}else{
|
|
}else{
|
|
|
assert( pPage==p->pDirty );
|
|
assert( pPage==p->pDirty );
|
|
|
p->pDirty = pPage->pDirtyNext;
|
|
p->pDirty = pPage->pDirtyNext;
|
|
|
|
|
+ if( p->pDirty==0 && p->bPurgeable ){
|
|
|
|
|
+ assert( p->eCreate==1 );
|
|
|
|
|
+ p->eCreate = 2;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
pPage->pDirtyNext = 0;
|
|
pPage->pDirtyNext = 0;
|
|
|
pPage->pDirtyPrev = 0;
|
|
pPage->pDirtyPrev = 0;
|
|
@@ -37404,6 +37409,9 @@ static void pcacheAddToDirtyList(PgHdr *pPage){
|
|
|
if( pPage->pDirtyNext ){
|
|
if( pPage->pDirtyNext ){
|
|
|
assert( pPage->pDirtyNext->pDirtyPrev==0 );
|
|
assert( pPage->pDirtyNext->pDirtyPrev==0 );
|
|
|
pPage->pDirtyNext->pDirtyPrev = pPage;
|
|
pPage->pDirtyNext->pDirtyPrev = pPage;
|
|
|
|
|
+ }else if( p->bPurgeable ){
|
|
|
|
|
+ assert( p->eCreate==2 );
|
|
|
|
|
+ p->eCreate = 1;
|
|
|
}
|
|
}
|
|
|
p->pDirty = pPage;
|
|
p->pDirty = pPage;
|
|
|
if( !p->pDirtyTail ){
|
|
if( !p->pDirtyTail ){
|
|
@@ -37473,6 +37481,7 @@ SQLITE_PRIVATE void sqlite3PcacheOpen(
|
|
|
p->szPage = szPage;
|
|
p->szPage = szPage;
|
|
|
p->szExtra = szExtra;
|
|
p->szExtra = szExtra;
|
|
|
p->bPurgeable = bPurgeable;
|
|
p->bPurgeable = bPurgeable;
|
|
|
|
|
+ p->eCreate = 2;
|
|
|
p->xStress = xStress;
|
|
p->xStress = xStress;
|
|
|
p->pStress = pStress;
|
|
p->pStress = pStress;
|
|
|
p->szCache = 100;
|
|
p->szCache = 100;
|
|
@@ -37512,7 +37521,7 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
|
|
|
int createFlag, /* If true, create page if it does not exist already */
|
|
int createFlag, /* If true, create page if it does not exist already */
|
|
|
PgHdr **ppPage /* Write the page here */
|
|
PgHdr **ppPage /* Write the page here */
|
|
|
){
|
|
){
|
|
|
- sqlite3_pcache_page *pPage = 0;
|
|
|
|
|
|
|
+ sqlite3_pcache_page *pPage;
|
|
|
PgHdr *pPgHdr = 0;
|
|
PgHdr *pPgHdr = 0;
|
|
|
int eCreate;
|
|
int eCreate;
|
|
|
|
|
|
|
@@ -37523,8 +37532,12 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
|
|
|
/* If the pluggable cache (sqlite3_pcache*) has not been allocated,
|
|
/* If the pluggable cache (sqlite3_pcache*) has not been allocated,
|
|
|
** allocate it now.
|
|
** allocate it now.
|
|
|
*/
|
|
*/
|
|
|
- if( !pCache->pCache && createFlag ){
|
|
|
|
|
|
|
+ if( !pCache->pCache ){
|
|
|
sqlite3_pcache *p;
|
|
sqlite3_pcache *p;
|
|
|
|
|
+ if( !createFlag ){
|
|
|
|
|
+ *ppPage = 0;
|
|
|
|
|
+ return SQLITE_OK;
|
|
|
|
|
+ }
|
|
|
p = sqlite3GlobalConfig.pcache2.xCreate(
|
|
p = sqlite3GlobalConfig.pcache2.xCreate(
|
|
|
pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
|
|
pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
|
|
|
);
|
|
);
|
|
@@ -37535,11 +37548,16 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
|
|
|
pCache->pCache = p;
|
|
pCache->pCache = p;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
|
|
|
|
|
- if( pCache->pCache ){
|
|
|
|
|
- pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ /* eCreate defines what to do if the page does not exist.
|
|
|
|
|
+ ** 0 Do not allocate a new page. (createFlag==0)
|
|
|
|
|
+ ** 1 Allocate a new page if doing so is inexpensive.
|
|
|
|
|
+ ** (createFlag==1 AND bPurgeable AND pDirty)
|
|
|
|
|
+ ** 2 Allocate a new page even it doing so is difficult.
|
|
|
|
|
+ ** (createFlag==1 AND !(bPurgeable AND pDirty)
|
|
|
|
|
+ */
|
|
|
|
|
+ eCreate = createFlag==0 ? 0 : pCache->eCreate;
|
|
|
|
|
+ assert( (createFlag*(1+(!pCache->bPurgeable||!pCache->pDirty)))==eCreate );
|
|
|
|
|
+ pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
|
|
if( !pPage && eCreate==1 ){
|
|
if( !pPage && eCreate==1 ){
|
|
|
PgHdr *pPg;
|
|
PgHdr *pPg;
|
|
|
|
|
|
|
@@ -55655,6 +55673,15 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
|
|
|
** successful then set *pRes=0. If the cursor
|
|
** successful then set *pRes=0. If the cursor
|
|
|
** was already pointing to the last entry in the database before
|
|
** was already pointing to the last entry in the database before
|
|
|
** this routine was called, then set *pRes=1.
|
|
** this routine was called, then set *pRes=1.
|
|
|
|
|
+**
|
|
|
|
|
+** The calling function will set *pRes to 0 or 1. The initial *pRes value
|
|
|
|
|
+** will be 1 if the cursor being stepped corresponds to an SQL index and
|
|
|
|
|
+** if this routine could have been skipped if that SQL index had been
|
|
|
|
|
+** a unique index. Otherwise the caller will have set *pRes to zero.
|
|
|
|
|
+** Zero is the common case. The btree implementation is free to use the
|
|
|
|
|
+** initial *pRes value as a hint to improve performance, but the current
|
|
|
|
|
+** SQLite btree implementation does not. (Note that the comdb2 btree
|
|
|
|
|
+** implementation does use this hint, however.)
|
|
|
*/
|
|
*/
|
|
|
SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
|
SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
|
|
int rc;
|
|
int rc;
|
|
@@ -55663,6 +55690,7 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
|
|
|
|
|
|
|
assert( cursorHoldsMutex(pCur) );
|
|
assert( cursorHoldsMutex(pCur) );
|
|
|
assert( pRes!=0 );
|
|
assert( pRes!=0 );
|
|
|
|
|
+ assert( *pRes==0 || *pRes==1 );
|
|
|
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
|
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
|
|
if( pCur->eState!=CURSOR_VALID ){
|
|
if( pCur->eState!=CURSOR_VALID ){
|
|
|
rc = restoreCursorPosition(pCur);
|
|
rc = restoreCursorPosition(pCur);
|
|
@@ -55741,6 +55769,15 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
|
|
** successful then set *pRes=0. If the cursor
|
|
** successful then set *pRes=0. If the cursor
|
|
|
** was already pointing to the first entry in the database before
|
|
** was already pointing to the first entry in the database before
|
|
|
** this routine was called, then set *pRes=1.
|
|
** this routine was called, then set *pRes=1.
|
|
|
|
|
+**
|
|
|
|
|
+** The calling function will set *pRes to 0 or 1. The initial *pRes value
|
|
|
|
|
+** will be 1 if the cursor being stepped corresponds to an SQL index and
|
|
|
|
|
+** if this routine could have been skipped if that SQL index had been
|
|
|
|
|
+** a unique index. Otherwise the caller will have set *pRes to zero.
|
|
|
|
|
+** Zero is the common case. The btree implementation is free to use the
|
|
|
|
|
+** initial *pRes value as a hint to improve performance, but the current
|
|
|
|
|
+** SQLite btree implementation does not. (Note that the comdb2 btree
|
|
|
|
|
+** implementation does use this hint, however.)
|
|
|
*/
|
|
*/
|
|
|
SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
|
SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
|
|
int rc;
|
|
int rc;
|
|
@@ -55748,6 +55785,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
|
|
|
|
|
|
|
assert( cursorHoldsMutex(pCur) );
|
|
assert( cursorHoldsMutex(pCur) );
|
|
|
assert( pRes!=0 );
|
|
assert( pRes!=0 );
|
|
|
|
|
+ assert( *pRes==0 || *pRes==1 );
|
|
|
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
|
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
|
|
pCur->atLast = 0;
|
|
pCur->atLast = 0;
|
|
|
if( pCur->eState!=CURSOR_VALID ){
|
|
if( pCur->eState!=CURSOR_VALID ){
|
|
@@ -57974,7 +58012,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
|
|
|
** sub-tree headed by the child page of the cell being deleted. This makes
|
|
** sub-tree headed by the child page of the cell being deleted. This makes
|
|
|
** balancing the tree following the delete operation easier. */
|
|
** balancing the tree following the delete operation easier. */
|
|
|
if( !pPage->leaf ){
|
|
if( !pPage->leaf ){
|
|
|
- int notUsed;
|
|
|
|
|
|
|
+ int notUsed = 0;
|
|
|
rc = sqlite3BtreePrevious(pCur, ¬Used);
|
|
rc = sqlite3BtreePrevious(pCur, ¬Used);
|
|
|
if( rc ) return rc;
|
|
if( rc ) return rc;
|
|
|
}
|
|
}
|
|
@@ -70239,6 +70277,7 @@ case OP_SeekGt: { /* jump, in3 */
|
|
|
#endif
|
|
#endif
|
|
|
if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt );
|
|
if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt );
|
|
|
if( res<0 || (res==0 && oc==OP_SeekGt) ){
|
|
if( res<0 || (res==0 && oc==OP_SeekGt) ){
|
|
|
|
|
+ res = 0;
|
|
|
rc = sqlite3BtreeNext(pC->pCursor, &res);
|
|
rc = sqlite3BtreeNext(pC->pCursor, &res);
|
|
|
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
|
pC->rowidIsValid = 0;
|
|
pC->rowidIsValid = 0;
|
|
@@ -70248,6 +70287,7 @@ case OP_SeekGt: { /* jump, in3 */
|
|
|
}else{
|
|
}else{
|
|
|
assert( oc==OP_SeekLt || oc==OP_SeekLe );
|
|
assert( oc==OP_SeekLt || oc==OP_SeekLe );
|
|
|
if( res>0 || (res==0 && oc==OP_SeekLt) ){
|
|
if( res>0 || (res==0 && oc==OP_SeekLt) ){
|
|
|
|
|
+ res = 0;
|
|
|
rc = sqlite3BtreePrevious(pC->pCursor, &res);
|
|
rc = sqlite3BtreePrevious(pC->pCursor, &res);
|
|
|
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
|
pC->rowidIsValid = 0;
|
|
pC->rowidIsValid = 0;
|
|
@@ -71100,7 +71140,7 @@ case OP_Rewind: { /* jump */
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* Opcode: Next P1 P2 * * P5
|
|
|
|
|
|
|
+/* Opcode: Next P1 P2 P3 * P5
|
|
|
**
|
|
**
|
|
|
** Advance cursor P1 so that it points to the next key/data pair in its
|
|
** Advance cursor P1 so that it points to the next key/data pair in its
|
|
|
** table or index. If there are no more key/value pairs then fall through
|
|
** table or index. If there are no more key/value pairs then fall through
|
|
@@ -71110,6 +71150,11 @@ case OP_Rewind: { /* jump */
|
|
|
** The P1 cursor must be for a real table, not a pseudo-table. P1 must have
|
|
** The P1 cursor must be for a real table, not a pseudo-table. P1 must have
|
|
|
** been opened prior to this opcode or the program will segfault.
|
|
** been opened prior to this opcode or the program will segfault.
|
|
|
**
|
|
**
|
|
|
|
|
+** The P3 value is a hint to the btree implementation. If P3==1, that
|
|
|
|
|
+** means P1 is an SQL index and that this instruction could have been
|
|
|
|
|
+** omitted if that index had been unique. P3 is usually 0. P3 is
|
|
|
|
|
+** always either 0 or 1.
|
|
|
|
|
+**
|
|
|
** P4 is always of type P4_ADVANCE. The function pointer points to
|
|
** P4 is always of type P4_ADVANCE. The function pointer points to
|
|
|
** sqlite3BtreeNext().
|
|
** sqlite3BtreeNext().
|
|
|
**
|
|
**
|
|
@@ -71118,12 +71163,12 @@ case OP_Rewind: { /* jump */
|
|
|
**
|
|
**
|
|
|
** See also: Prev, NextIfOpen
|
|
** See also: Prev, NextIfOpen
|
|
|
*/
|
|
*/
|
|
|
-/* Opcode: NextIfOpen P1 P2 * * P5
|
|
|
|
|
|
|
+/* Opcode: NextIfOpen P1 P2 P3 * P5
|
|
|
**
|
|
**
|
|
|
** This opcode works just like OP_Next except that if cursor P1 is not
|
|
** This opcode works just like OP_Next except that if cursor P1 is not
|
|
|
** open it behaves a no-op.
|
|
** open it behaves a no-op.
|
|
|
*/
|
|
*/
|
|
|
-/* Opcode: Prev P1 P2 * * P5
|
|
|
|
|
|
|
+/* Opcode: Prev P1 P2 P3 * P5
|
|
|
**
|
|
**
|
|
|
** Back up cursor P1 so that it points to the previous key/data pair in its
|
|
** Back up cursor P1 so that it points to the previous key/data pair in its
|
|
|
** table or index. If there is no previous key/value pairs then fall through
|
|
** table or index. If there is no previous key/value pairs then fall through
|
|
@@ -71133,13 +71178,18 @@ case OP_Rewind: { /* jump */
|
|
|
** The P1 cursor must be for a real table, not a pseudo-table. If P1 is
|
|
** The P1 cursor must be for a real table, not a pseudo-table. If P1 is
|
|
|
** not open then the behavior is undefined.
|
|
** not open then the behavior is undefined.
|
|
|
**
|
|
**
|
|
|
|
|
+** The P3 value is a hint to the btree implementation. If P3==1, that
|
|
|
|
|
+** means P1 is an SQL index and that this instruction could have been
|
|
|
|
|
+** omitted if that index had been unique. P3 is usually 0. P3 is
|
|
|
|
|
+** always either 0 or 1.
|
|
|
|
|
+**
|
|
|
** P4 is always of type P4_ADVANCE. The function pointer points to
|
|
** P4 is always of type P4_ADVANCE. The function pointer points to
|
|
|
** sqlite3BtreePrevious().
|
|
** sqlite3BtreePrevious().
|
|
|
**
|
|
**
|
|
|
** If P5 is positive and the jump is taken, then event counter
|
|
** If P5 is positive and the jump is taken, then event counter
|
|
|
** number P5-1 in the prepared statement is incremented.
|
|
** number P5-1 in the prepared statement is incremented.
|
|
|
*/
|
|
*/
|
|
|
-/* Opcode: PrevIfOpen P1 P2 * * P5
|
|
|
|
|
|
|
+/* Opcode: PrevIfOpen P1 P2 P3 * P5
|
|
|
**
|
|
**
|
|
|
** This opcode works just like OP_Prev except that if cursor P1 is not
|
|
** This opcode works just like OP_Prev except that if cursor P1 is not
|
|
|
** open it behaves a no-op.
|
|
** open it behaves a no-op.
|
|
@@ -71161,9 +71211,12 @@ case OP_Next: /* jump */
|
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
|
assert( pOp->p5<ArraySize(p->aCounter) );
|
|
assert( pOp->p5<ArraySize(p->aCounter) );
|
|
|
pC = p->apCsr[pOp->p1];
|
|
pC = p->apCsr[pOp->p1];
|
|
|
|
|
+ res = pOp->p3;
|
|
|
assert( pC!=0 );
|
|
assert( pC!=0 );
|
|
|
assert( pC->deferredMoveto==0 );
|
|
assert( pC->deferredMoveto==0 );
|
|
|
assert( pC->pCursor );
|
|
assert( pC->pCursor );
|
|
|
|
|
+ assert( res==0 || (res==1 && pC->isTable==0) );
|
|
|
|
|
+ testcase( res==1 );
|
|
|
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
|
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
|
|
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
|
|
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
|
|
|
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
|
|
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
|
|
@@ -108708,7 +108761,7 @@ struct WhereLevel {
|
|
|
int addrFirst; /* First instruction of interior of the loop */
|
|
int addrFirst; /* First instruction of interior of the loop */
|
|
|
int addrBody; /* Beginning of the body of this loop */
|
|
int addrBody; /* Beginning of the body of this loop */
|
|
|
u8 iFrom; /* Which entry in the FROM clause */
|
|
u8 iFrom; /* Which entry in the FROM clause */
|
|
|
- u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */
|
|
|
|
|
|
|
+ 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 */
|
|
int p1, p2; /* Operands of the opcode used to ends the loop */
|
|
|
union { /* Information that depends on pWLoop->wsFlags */
|
|
union { /* Information that depends on pWLoop->wsFlags */
|
|
|
struct {
|
|
struct {
|
|
@@ -109095,6 +109148,7 @@ struct WhereInfo {
|
|
|
#define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */
|
|
#define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */
|
|
|
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
|
|
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
|
|
|
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
|
|
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
|
|
|
|
|
+#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
|
|
|
|
|
|
|
|
/************** End of whereInt.h ********************************************/
|
|
/************** End of whereInt.h ********************************************/
|
|
|
/************** Continuing where we left off in where.c **********************/
|
|
/************** Continuing where we left off in where.c **********************/
|
|
@@ -112263,6 +112317,8 @@ static Bitmask codeOneLoopStart(
|
|
|
pLevel->op = OP_Next;
|
|
pLevel->op = OP_Next;
|
|
|
}
|
|
}
|
|
|
pLevel->p1 = iIdxCur;
|
|
pLevel->p1 = iIdxCur;
|
|
|
|
|
+ assert( (WHERE_UNQ_WANTED>>16)==1 );
|
|
|
|
|
+ pLevel->p3 = (pLoop->wsFlags>>16)&1;
|
|
|
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
|
|
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
|
|
|
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
|
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
|
|
}else{
|
|
}else{
|
|
@@ -113065,12 +113121,13 @@ static int whereLoopAddBtreeIndex(
|
|
|
|| nInMul==0
|
|
|| nInMul==0
|
|
|
);
|
|
);
|
|
|
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
|
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
|
|
- if( iCol<0
|
|
|
|
|
- || (pProbe->onError!=OE_None && nInMul==0
|
|
|
|
|
- && pNew->u.btree.nEq==pProbe->nKeyCol-1)
|
|
|
|
|
- ){
|
|
|
|
|
|
|
+ if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1)){
|
|
|
assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 );
|
|
assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 );
|
|
|
- pNew->wsFlags |= WHERE_ONEROW;
|
|
|
|
|
|
|
+ if( iCol>=0 && pProbe->onError==OE_None ){
|
|
|
|
|
+ pNew->wsFlags |= WHERE_UNQ_WANTED;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ pNew->wsFlags |= WHERE_ONEROW;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
pNew->u.btree.nEq++;
|
|
pNew->u.btree.nEq++;
|
|
|
pNew->nOut = nRowEst + nInMul;
|
|
pNew->nOut = nRowEst + nInMul;
|
|
@@ -114864,7 +114921,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
|
pLoop = pLevel->pWLoop;
|
|
pLoop = pLevel->pWLoop;
|
|
|
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
|
if( pLevel->op!=OP_Noop ){
|
|
if( pLevel->op!=OP_Noop ){
|
|
|
- sqlite3VdbeAddOp2(v, pLevel->op, pLevel->p1, pLevel->p2);
|
|
|
|
|
|
|
+ sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
|
|
|
sqlite3VdbeChangeP5(v, pLevel->p5);
|
|
sqlite3VdbeChangeP5(v, pLevel->p5);
|
|
|
}
|
|
}
|
|
|
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
|
|
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
|