diff options
author | drh <drh@noemail.net> | 2006-01-08 18:10:17 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2006-01-08 18:10:17 +0000 |
commit | 15007a99e4ba8f5601ed9a431a05c3ee503c2bfa (patch) | |
tree | 44b031bdc4ff766a48e561579e346dda7e46dda6 /src | |
parent | 6f58f7069ba7c2cb5844893ad4a511524261e7ef (diff) | |
download | sqlite-15007a99e4ba8f5601ed9a431a05c3ee503c2bfa.tar.gz sqlite-15007a99e4ba8f5601ed9a431a05c3ee503c2bfa.zip |
Get LIMIT and OFFSET working again for negative limits and offsets.
Ticket #1586. (CVS 2889)
FossilOrigin-Name: b2ac0be07ec76ab23b7e5b800c0bc62d0bc97f4b
Diffstat (limited to 'src')
-rw-r--r-- | src/analyze.c | 6 | ||||
-rw-r--r-- | src/insert.c | 4 | ||||
-rw-r--r-- | src/pragma.c | 12 | ||||
-rw-r--r-- | src/select.c | 61 | ||||
-rw-r--r-- | src/vdbe.c | 33 |
5 files changed, 72 insertions, 44 deletions
diff --git a/src/analyze.c b/src/analyze.c index 4669c733b..acd812b27 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.13 2006/01/07 13:21:04 danielk1977 Exp $ +** @(#) $Id: analyze.c,v 1.14 2006/01/08 18:10:18 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -152,7 +152,7 @@ static void analyzeOneTable( endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop); topOfLoop = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp(v, OP_MemIncr, iMem, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i); sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0); @@ -160,7 +160,7 @@ static void analyzeOneTable( } sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop); for(i=0; i<nCol; i++){ - addr = sqlite3VdbeAddOp(v, OP_MemIncr, iMem+i+1, 0); + addr = sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem+i+1); sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr); sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i); sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, 1); diff --git a/src/insert.c b/src/insert.c index dea6c6fc1..3de2c4250 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.153 2006/01/07 13:21:04 danielk1977 Exp $ +** $Id: insert.c,v 1.154 2006/01/08 18:10:18 drh Exp $ */ #include "sqliteInt.h" @@ -636,7 +636,7 @@ void sqlite3Insert( /* Update the count of rows that are inserted */ if( (db->flags & SQLITE_CountRows)!=0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, iCntMem); } if( triggers_exist ){ diff --git a/src/pragma.c b/src/pragma.c index a869657ae..ac08d2ff1 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.109 2006/01/06 14:32:20 drh Exp $ +** $Id: pragma.c,v 1.110 2006/01/08 18:10:18 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -686,7 +686,7 @@ void sqlite3Pragma( sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Concat, 0, 1); sqlite3VdbeAddOp(v, OP_Callback, 1, 0); - sqlite3VdbeAddOp(v, OP_MemIncr, 0, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); /* Make sure all the indices are constructed correctly. */ @@ -700,11 +700,11 @@ void sqlite3Pragma( sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); sqlite3VdbeAddOp(v, OP_MemInt, 0, 1); loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0); - sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2; static const VdbeOpList idxErr[] = { - { OP_MemIncr, 0, 0, 0}, + { OP_MemIncr, 1, 0, 0}, { OP_String8, 0, 0, "rowid "}, { OP_Rowid, 1, 0, 0}, { OP_String8, 0, 0, " missing from index "}, @@ -724,12 +724,12 @@ void sqlite3Pragma( static const VdbeOpList cntIdx[] = { { OP_MemInt, 0, 2, 0}, { OP_Rewind, 0, 0, 0}, /* 1 */ - { OP_MemIncr, 2, 0, 0}, + { OP_MemIncr, 1, 2, 0}, { OP_Next, 0, 0, 0}, /* 3 */ { OP_MemLoad, 1, 0, 0}, { OP_MemLoad, 2, 0, 0}, { OP_Eq, 0, 0, 0}, /* 6 */ - { OP_MemIncr, 0, 0, 0}, + { OP_MemIncr, 1, 0, 0}, { OP_String8, 0, 0, "wrong # of entries in index "}, { OP_String8, 0, 0, 0}, /* 9 */ { OP_Concat, 0, 0, 0}, diff --git a/src/select.c b/src/select.c index b482de90d..9b0be55ec 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.287 2006/01/08 05:02:55 drh Exp $ +** $Id: select.c,v 1.288 2006/01/08 18:10:18 drh Exp $ */ #include "sqliteInt.h" @@ -363,14 +363,14 @@ static void pushOntoSorter( sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0); sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0); if( pSelect->iLimit>=0 ){ - int addr1; - sqlite3VdbeAddOp(v, OP_MemIncr, pSelect->iLimit+1, 0); - addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, pSelect->iLimit+1, 0); - sqlite3VdbeAddOp(v, OP_Goto, 0, 0); + int addr1, addr2; + addr1 = sqlite3VdbeAddOp(v, OP_IfMemZero, pSelect->iLimit+1, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, -1, pSelect->iLimit+1); + addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0); sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0); - sqlite3VdbeJumpHere(v, addr1+1); + sqlite3VdbeJumpHere(v, addr2); pSelect->iLimit = -1; } } @@ -385,15 +385,15 @@ static void codeOffset( int nPop /* Number of times to pop stack when jumping */ ){ if( p->iOffset>=0 && iContinue!=0 ){ - int addr = sqlite3VdbeCurrentAddr(v) + 3; - if( nPop>0 ) addr++; - sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, 0); - sqlite3VdbeAddOp(v, OP_IfMemPos, p->iOffset, addr); + int addr; + sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset); + addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, addr); if( nPop>0 ){ sqlite3VdbeAddOp(v, OP_Pop, nPop, 0); } sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue); VdbeComment((v, "# skip OFFSET records")); + sqlite3VdbeJumpHere(v, addr); } } @@ -617,7 +617,7 @@ static int selectInnerLoop( /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit>=0 && pOrderBy==0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak); } return 0; @@ -739,7 +739,7 @@ static void generateSortTail( /* Jump to the end of the loop when the LIMIT is reached */ if( p->iLimit>=0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, brk); } @@ -1365,6 +1365,7 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){ return v; } + /* ** Compute the iLimit and iOffset fields of the SELECT based on the ** pLimit and pOffset expressions. pLimit and pOffset hold the expressions @@ -1384,6 +1385,11 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){ ** SELECT statements. */ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ + Vdbe *v; + int iLimit; + int iOffset; + int addr1, addr2; + /* ** "LIMIT -1" always shows all rows. There is some ** contraversy about what the correct behavior should be. @@ -1391,36 +1397,41 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ ** no rows. */ if( p->pLimit ){ - int iMem = pParse->nMem; + p->iLimit = iLimit = pParse->nMem; pParse->nMem += 2; - Vdbe *v = sqlite3GetVdbe(pParse); + v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pLimit); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); - sqlite3VdbeAddOp(v, OP_Negative, 0, 0); - sqlite3VdbeAddOp(v, OP_MemStore, iMem, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 0); VdbeComment((v, "# LIMIT counter")); - sqlite3VdbeAddOp(v, OP_IfMemZero, iMem, iBreak); - p->iLimit = iMem; + sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak); } if( p->pOffset ){ - int iMem = pParse->nMem++; - Vdbe *v = sqlite3GetVdbe(pParse); + p->iOffset = iOffset = pParse->nMem++; + v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pOffset); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); - sqlite3VdbeAddOp(v, OP_Negative, 0, 0); - sqlite3VdbeAddOp(v, OP_MemStore, iMem, p->pLimit==0); + sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0); VdbeComment((v, "# OFFSET counter")); + addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0); + sqlite3VdbeAddOp(v, OP_Pop, 1, 0); + sqlite3VdbeAddOp(v, OP_Integer, 0, 0); + sqlite3VdbeJumpHere(v, addr1); if( p->pLimit ){ sqlite3VdbeAddOp(v, OP_Add, 0, 0); } - p->iOffset = iMem; } if( p->pLimit ){ - Vdbe *v = pParse->pVdbe; - sqlite3VdbeAddOp(v, OP_MemStore, p->iLimit+1, 1); + addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iLimit, 0); + sqlite3VdbeAddOp(v, OP_Pop, 1, 0); + sqlite3VdbeAddOp(v, OP_MemInt, -1, iLimit+1); + addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); + sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeAddOp(v, OP_MemStore, iLimit+1, 1); VdbeComment((v, "# LIMIT+OFFSET")); + sqlite3VdbeJumpHere(v, addr2); } } diff --git a/src/vdbe.c b/src/vdbe.c index 22e939353..53cf82f77 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.517 2006/01/08 05:26:41 drh Exp $ +** $Id: vdbe.c,v 1.518 2006/01/08 18:10:18 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -4277,28 +4277,26 @@ case OP_MemMax: { /* no-push */ } #endif /* SQLITE_OMIT_AUTOINCREMENT */ -/* Opcode: MemIncr P1 * * +/* Opcode: MemIncr P1 P2 * ** -** Increment the integer valued memory cell P1 by 1. +** Increment the integer valued memory cell P2 by the value in P1. ** ** It is illegal to use this instruction on a memory cell that does ** not contain an integer. An assertion fault will result if you try. */ case OP_MemIncr: { /* no-push */ - int i = pOp->p1; + int i = pOp->p2; Mem *pMem; assert( i>=0 && i<p->nMem ); pMem = &p->aMem[i]; assert( pMem->flags==MEM_Int ); - pMem->i++; - assert( pOp->p2==0 ); + pMem->i += pOp->p1; break; } /* Opcode: IfMemPos P1 P2 * ** -** If the value of memory cell P1 is 1 or greater, jump to P2. If -** the memory cell holds an integer of 0 or less. +** If the value of memory cell P1 is 1 or greater, jump to P2. ** ** It is illegal to use this instruction on a memory cell that does ** not contain an integer. An assertion fault will result if you try. @@ -4315,6 +4313,25 @@ case OP_IfMemPos: { /* no-push */ break; } +/* Opcode: IfMemNeg P1 P2 * +** +** If the value of memory cell P1 is less than zero, jump to P2. +** +** It is illegal to use this instruction on a memory cell that does +** not contain an integer. An assertion fault will result if you try. +*/ +case OP_IfMemNeg: { /* no-push */ + int i = pOp->p1; + Mem *pMem; + assert( i>=0 && i<p->nMem ); + pMem = &p->aMem[i]; + assert( pMem->flags==MEM_Int ); + if( pMem->i<0 ){ + pc = pOp->p2 - 1; + } + break; +} + /* Opcode: IfMemZero P1 P2 * ** ** If the value of memory cell P1 is exactly 0, jump to P2. |