aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2006-01-08 18:10:17 +0000
committerdrh <drh@noemail.net>2006-01-08 18:10:17 +0000
commit15007a99e4ba8f5601ed9a431a05c3ee503c2bfa (patch)
tree44b031bdc4ff766a48e561579e346dda7e46dda6 /src
parent6f58f7069ba7c2cb5844893ad4a511524261e7ef (diff)
downloadsqlite-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.c6
-rw-r--r--src/insert.c4
-rw-r--r--src/pragma.c12
-rw-r--r--src/select.c61
-rw-r--r--src/vdbe.c33
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.