-C Improvements\sto\scomments.\s\sNo\scode\schanges.\s(CVS\s618)
-D 2002-06-14T20:58:45
+C Make\sthe\sLIMIT\sclause\swork\seven\sif\sthe\sdestination\sof\sthe\sSELECT\sis\nsomething\sother\sthan\sa\scallback.\s\s(Ticket\s#66)\s(CVS\s619)
+D 2002-06-14T22:38:42
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
F src/parse.y 42920305d49666419358b469e4ec522ac867a39f
F src/printf.c d8032ee18b860c812eeff596c9bebfdacb7930fd
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c 1d5cb1ae0bb3376bedfde7ae22e6e927e4d0b5e2
+F src/select.c 6c3a92d7a0bdf3448265d530cc0e6f6e5a764997
F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b
F src/trigger.c 21342af6ac031fece39c8fc6eabd1739ca5327c1
F src/update.c 05431e23a9c83502fd7911e771c8366fc2b90b4c
F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95
-F src/vdbe.c 836f2c4f823c94c3c3454125d9ba9283e8b22dda
-F src/vdbe.h 1742d6f8b40f40879475b4c41cf4f9980ceb0e21
-F src/where.c bd25559800ba1fbe1fd596eaec14c417aa1e1b46
+F src/vdbe.c 7d9bb3701ea00576c5d5fb3f3de63af7b7304241
+F src/vdbe.h fba15f3280688f6f32f11d1042078e3c557bac43
+F src/where.c aa5d9d83abf0f7dda06fdd4235020f2b72d58dec
F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
F test/intpkey.test 31b5f28b2c44273e6695cf36ab2e4133aee7753c
F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
F test/join.test ea6a4097e4fcebbb16eac7ec819569e759336a74
-F test/limit.test 6f98bcefc92209103bb3764c81975a6ec21d6702
+F test/limit.test 96b33e108e134b5cc674a660064229d15fa278b9
F test/lock.test 3fcfd46a73119f6a18094673328a32c7b3047a8f
F test/main.test c66b564554b770ee7fdbf6a66c0cd90329bc2c85
F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd
F test/update.test a0aa0bf83e6fad8407d0e4ad25ebb09b513f5bf4
F test/vacuum.test 059871b312eb910bbe49dafde1d01490cc2c6bbe
F test/view.test b9851e9142de5e5831fdf18f125cbe1256cb550a
-F test/where.test fe33c2f92de1da8192abf763a2852a4ba270fefe
+F test/where.test 367d7911ee0522f1bb8a2daf17fb985e06cfe8bb
F tool/lemon.c 459cb2bb3738a1ad5cb0ad8b805587a88a885d95
F tool/lempar.c 73a991cc3017fb34804250fa901488b5147b3717
F tool/memleak.awk 296dfbce7a9ca499b95ce04e30334e64a50052e0
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P e67ac0fec51788aca0429d04310f86c9c1cf9d13
-R c5c72185b42e3894c8a67dc4dc44e497
+P 7e10e60bb78b680bb822908a0b7763f8f5e3ee5a
+R 93cd20298bab2e582d79237e05fbb947
U drh
-Z ec1b6ad2227bde141b128cfba4f6e91b
+Z 34cf64c3405f1f55004d8bc22fcb2d56
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.92 2002/06/06 23:42:28 drh Exp $
+** $Id: select.c,v 1.93 2002/06/14 22:38:42 drh Exp $
*/
#include "sqliteInt.h"
*/
static int selectInnerLoop(
Parse *pParse, /* The parser context */
+ Select *p, /* The complete select statement being coded */
ExprList *pEList, /* List of values being extracted */
int srcTab, /* Pull data from this table */
int nColumn, /* Number of columns in the source table */
int i;
if( v==0 ) return 0;
+ /* If there was a LIMIT clause on the SELECT statement, then do the check
+ ** to see if this row should be output.
+ */
+ if( pOrderBy==0 ){
+ if( p->nOffset>0 ){
+ sqliteVdbeAddOp(v, OP_LimitCk, 1, iContinue);
+ }
+ if( p->nLimit>0 ){
+ sqliteVdbeAddOp(v, OP_LimitCk, 0, iBreak);
+ }
+ }
+
/* Pull the requested columns.
*/
if( pEList ){
/* If none of the above, send the data to the callback function.
*/
{
- sqliteVdbeAddOp(v, OP_Callback, nColumn, iBreak);
+ assert( eDest==SRT_Callback );
+ sqliteVdbeAddOp(v, OP_Callback, nColumn, 0);
}
return 0;
}
** we need to run the sorter and output the results. The following
** routine generates the code needed to do that.
*/
-static void generateSortTail(Vdbe *v, int nColumn){
+static void generateSortTail(Select *p, Vdbe *v, int nColumn){
int end = sqliteVdbeMakeLabel(v);
int addr;
sqliteVdbeAddOp(v, OP_Sort, 0, 0);
addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end);
- sqliteVdbeAddOp(v, OP_SortCallback, nColumn, end);
+ if( p->nOffset>0 ){
+ sqliteVdbeAddOp(v, OP_LimitCk, 1, addr);
+ }
+ if( p->nLimit>0 ){
+ sqliteVdbeAddOp(v, OP_LimitCk, 0, end);
+ }
+ sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
sqliteVdbeResolveLabel(v, end);
sqliteVdbeAddOp(v, OP_SortReset, 0, 0);
iCont = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Rewind, unionTab, iBreak);
iStart = sqliteVdbeCurrentAddr(v);
- rc = selectInnerLoop(pParse, 0, unionTab, p->pEList->nExpr,
+ rc = selectInnerLoop(pParse, p, 0, unionTab, p->pEList->nExpr,
p->pOrderBy, -1, eDest, iParm,
iCont, iBreak);
if( rc ) return 1;
sqliteVdbeResolveLabel(v, iBreak);
sqliteVdbeAddOp(v, OP_Close, unionTab, 0);
if( p->pOrderBy ){
- generateSortTail(v, p->pEList->nExpr);
+ generateSortTail(p, v, p->pEList->nExpr);
}
}
break;
sqliteVdbeAddOp(v, OP_Rewind, tab1, iBreak);
iStart = sqliteVdbeAddOp(v, OP_FullKey, tab1, 0);
sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont);
- rc = selectInnerLoop(pParse, 0, tab1, p->pEList->nExpr,
+ rc = selectInnerLoop(pParse, p, 0, tab1, p->pEList->nExpr,
p->pOrderBy, -1, eDest, iParm,
iCont, iBreak);
if( rc ) return 1;
sqliteVdbeAddOp(v, OP_Close, tab2, 0);
sqliteVdbeAddOp(v, OP_Close, tab1, 0);
if( p->pOrderBy ){
- generateSortTail(v, p->pEList->nExpr);
+ generateSortTail(p, v, p->pEList->nExpr);
}
break;
}
**
** (7) The subquery has a FROM clause.
**
+** (8) The subquery does not use LIMIT or the outer query is not a join.
+**
+** (9) The subquery does not use LIMIT or the outer query does not use
+** aggregates.
+**
+** (10) The subquery does not use aggregates or the outer query does not
+** use LIMIT.
+**
** In this routine, the "p" parameter is a pointer to the outer query.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
pSubSrc = pSub->pSrc;
assert( pSubSrc );
if( pSubSrc->nSrc!=1 ) return 0;
- if( pSub->isDistinct && pSrc->nSrc>1 ) return 0;
- if( pSub->isDistinct && isAgg ) return 0;
- if( p->isDistinct && subqueryIsAgg ) return 0;
+ if( (pSub->isDistinct || pSub->nLimit>=0) && (pSrc->nSrc>1 || isAgg) ){
+ return 0;
+ }
+ if( (p->isDistinct || p->nLimit) && subqueryIsAgg ) return 0;
/* If we reach this point, it means flattening is permitted for the
** i-th entry of the FROM clause in the outer query.
}
}
p->isDistinct = p->isDistinct || pSub->isDistinct;
+ if( pSub->nLimit>=0 ){
+ if( p->nLimit<0 ){
+ p->nLimit = pSub->nLimit;
+ }else if( p->nLimit+p->nOffset > pSub->nLimit+pSub->nOffset ){
+ p->nLimit = pSub->nLimit + pSub->nOffset - p->nOffset;
+ }
+ }
+ p->nOffset += pSub->nOffset;
if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
}
eList.a = &eListItem;
eList.a[0].pExpr = pExpr;
cont = sqliteVdbeMakeLabel(v);
- selectInnerLoop(pParse, &eList, base, 1, 0, -1, eDest, iParm, cont, cont);
+ selectInnerLoop(pParse, p, &eList, base, 1, 0, -1, eDest, iParm, cont, cont);
sqliteVdbeResolveLabel(v, cont);
sqliteVdbeAddOp(v, OP_Close, base, 0);
return 1;
** aggregates
*/
if( !isAgg ){
- if( selectInnerLoop(pParse, pEList, 0, 0, pOrderBy, distinct, eDest, iParm,
- pWInfo->iContinue, pWInfo->iBreak) ){
+ if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
+ iParm, pWInfo->iContinue, pWInfo->iBreak) ){
goto select_end;
}
}
if( pHaving ){
sqliteExprIfFalse(pParse, pHaving, startagg, 1);
}
- if( selectInnerLoop(pParse, pEList, 0, 0, pOrderBy, distinct, eDest, iParm,
- startagg, endagg) ){
+ if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
+ iParm, startagg, endagg) ){
goto select_end;
}
sqliteVdbeAddOp(v, OP_Goto, 0, startagg);
** and send them to the callback one by one.
*/
if( pOrderBy ){
- generateSortTail(v, pEList->nExpr);
+ generateSortTail(p, v, pEList->nExpr);
}
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.155 2002/06/11 02:25:42 danielk1977 Exp $
+** $Id: vdbe.c,v 1.156 2002/06/14 22:38:43 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
"Gt", "Ge", "IsNull", "NotNull",
"Negative", "And", "Or", "Not",
"Concat", "Noop", "Function", "Limit",
+ "LimitCk",
};
/*
break;
}
-/* Opcode: Callback P1 P2 *
+/* Opcode: Callback P1 * *
**
** Pop P1 values off the stack and form them into an array. Then
** invoke the callback function using the newly formed array as the
** 3rd parameter.
-**
-** If the offset counter (set by the OP_Limit opcode) is positive,
-** then decrement the counter and do not invoke the callback.
-**
-** If the callback is invoked, then after the callback returns
-** decrement the limit counter. When the limit counter reaches
-** zero, jump to address P2.
*/
case OP_Callback: {
int i = p->tos - pOp->p1 + 1;
}
zStack[p->tos+1] = 0;
if( xCallback!=0 ){
- if( p->iOffset>0 ){
- p->iOffset--;
- }else{
- if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
- if( xCallback(pArg, pOp->p1, &zStack[i], p->azColName)!=0 ){
- rc = SQLITE_ABORT;
- }
- if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
- p->nCallback++;
- if( p->iLimit>0 ){
- p->iLimit--;
- if( p->iLimit==0 ){
- pc = pOp->p2 - 1;
- }
- }
+ if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
+ if( xCallback(pArg, pOp->p1, &zStack[i], p->azColName)!=0 ){
+ rc = SQLITE_ABORT;
}
+ if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
+ p->nCallback++;
}
PopStack(p, pOp->p1);
if( sqlite_malloc_failed ) goto no_mem;
break;
}
+/* Opcode: LimitCk P1 P2 *
+**
+** If P1 is 1, then check to see if the offset counter (set by the
+** P2 argument of OP_Limit) is positive. If the offset counter is
+** positive then decrement the counter and jump immediately to P2.
+** Otherwise fall straight through.
+**
+** If P1 is 0, then check the value of the limit counter (set by the
+** P1 argument of OP_Limit). If the limit counter is negative or
+** zero then jump immedately to P2. Otherwise decrement the limit
+** counter and fall through.
+*/
+case OP_LimitCk: {
+ if( pOp->p1 ){
+ if( p->iOffset ){
+ p->iOffset--;
+ pc = pOp->p2 - 1;
+ }
+ }else{
+ if( p->iLimit>0 ){
+ p->iLimit--;
+ }else{
+ pc = pOp->p2 - 1;
+ }
+ }
+ break;
+}
+
+
/* Opcode: ListWrite * * *
**
** Write the integer on the top of the stack
break;
}
-/* Opcode: SortCallback P1 P2 *
+/* Opcode: SortCallback P1 * *
**
** The top of the stack contains a callback record built using
** the SortMakeRec operation with the same P1 value as this
** instruction. Pop this record from the stack and invoke the
** callback on it.
-**
-** If the offset counter (set by the OP_Limit opcode) is positive,
-** then decrement the counter and do not invoke the callback.
-**
-** If the callback is invoked, then after the callback returns
-** decrement the limit counter. When the limit counter reaches
-** zero, jump to address P2.
*/
case OP_SortCallback: {
int i = p->tos;
VERIFY( if( i<0 ) goto not_enough_stack; )
if( xCallback!=0 ){
- if( p->iOffset>0 ){
- p->iOffset--;
- }else{
- if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
- if( xCallback(pArg, pOp->p1, (char**)zStack[i], p->azColName)!=0 ){
- rc = SQLITE_ABORT;
- }
- if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
- p->nCallback++;
- if( p->iLimit>0 ){
- p->iLimit--;
- if( p->iLimit==0 ){
- pc = pOp->p2 - 1;
- }
- }
+ if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
+ if( xCallback(pArg, pOp->p1, (char**)zStack[i], p->azColName)!=0 ){
+ rc = SQLITE_ABORT;
}
+ if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
p->nCallback++;
}
POPSTACK;