diff options
Diffstat (limited to 'src/select.c')
-rw-r--r-- | src/select.c | 98 |
1 files changed, 61 insertions, 37 deletions
diff --git a/src/select.c b/src/select.c index 3b99cf408..fde787d87 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.276 2005/09/20 18:13:24 drh Exp $ +** $Id: select.c,v 1.277 2005/10/06 16:53:15 drh Exp $ */ #include "sqliteInt.h" @@ -360,13 +360,12 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){ } /* -** Add code to implement the OFFSET and LIMIT +** Add code to implement the OFFSET */ -static void codeLimiter( +static void codeOffset( Vdbe *v, /* Generate code into this VM */ Select *p, /* The SELECT statement being coded */ int iContinue, /* Jump here to skip the current record */ - int iBreak, /* Jump here to end the loop */ int nPop /* Number of times to pop stack when jumping */ ){ if( p->iOffset>=0 && iContinue!=0 ){ @@ -380,10 +379,6 @@ static void codeLimiter( sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue); VdbeComment((v, "# skip OFFSET records")); } - if( p->iLimit>=0 && iBreak!=0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak); - VdbeComment((v, "# exit when LIMIT reached")); - } } /* @@ -449,7 +444,7 @@ static int selectInnerLoop( */ hasDistinct = distinct>=0 && pEList && pEList->nExpr>0; if( pOrderBy==0 && !hasDistinct ){ - codeLimiter(v, p, iContinue, iBreak, 0); + codeOffset(v, p, iContinue, 0); } /* Pull the requested columns. @@ -471,7 +466,7 @@ static int selectInnerLoop( int n = pEList->nExpr; codeDistinct(v, distinct, iContinue, n, n+1); if( pOrderBy==0 ){ - codeLimiter(v, p, iContinue, iBreak, nColumn); + codeOffset(v, p, iContinue, nColumn); } } @@ -547,18 +542,26 @@ static int selectInnerLoop( break; } + /* If any row exists in the result set, record that fact and abort. + */ + case SRT_Exists: { + sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm); + sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); + /* The LIMIT clause will terminate the loop for us */ + break; + } + /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ - case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); if( pOrderBy ){ pushOntoSorter(pParse, v, pOrderBy); }else{ sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); - sqlite3VdbeAddOp(v, OP_Goto, 0, iBreak); + /* The LIMIT clause will jump out of the loop for us */ } break; } @@ -594,6 +597,13 @@ static int selectInnerLoop( } #endif } + + /* 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_IfMemZero, p->iLimit, iBreak); + } return 0; } @@ -661,7 +671,7 @@ static void generateSortTail( iTab = pOrderBy->iECursor; addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk); - codeLimiter(v, p, cont, brk, 0); + codeOffset(v, p, cont, 0); sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); switch( eDest ){ case SRT_Table: @@ -681,11 +691,10 @@ static void generateSortTail( sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); break; } - case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); - sqlite3VdbeAddOp(v, OP_Goto, 0, brk); + /* The LIMIT clause will terminate the loop for us */ break; } #endif @@ -710,6 +719,16 @@ static void generateSortTail( break; } } + + /* 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_IfMemZero, p->iLimit, brk); + } + + /* The bottom of the loop + */ sqlite3VdbeResolveLabel(v, cont); sqlite3VdbeAddOp(v, OP_Next, iTab, addr); sqlite3VdbeResolveLabel(v, brk); @@ -1328,7 +1347,7 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){ /* ** Compute the iLimit and iOffset fields of the SELECT based on the -** pLimit and pOffset expressions. nLimit and nOffset hold the expressions +** pLimit and pOffset expressions. pLimit and pOffset hold the expressions ** that appear in the original SQL statement after the LIMIT and OFFSET ** keywords. Or NULL if those keywords are omitted. iLimit and iOffset ** are the integer memory register numbers for counters used to compute @@ -1336,15 +1355,15 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){ ** iLimit and iOffset are negative. ** ** This routine changes the values if iLimit and iOffset only if -** a limit or offset is defined by nLimit and nOffset. iLimit and +** a limit or offset is defined by pLimit and pOffset. iLimit and ** iOffset should have been preset to appropriate default values ** (usually but not always -1) prior to calling this routine. -** Only if nLimit>=0 or nOffset>0 do the limit registers get +** Only if pLimit!=0 or pOffset!=0 do the limit registers get ** redefined. The UNION ALL operator uses this property to force ** the reuse of the same limit and offset registers across multiple ** SELECT statements. */ -static void computeLimitRegisters(Parse *pParse, Select *p){ +static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ /* ** "LIMIT -1" always shows all rows. There is some ** contraversy about what the correct behavior should be. @@ -1360,6 +1379,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p){ sqlite3VdbeAddOp(v, OP_Negative, 0, 0); sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); VdbeComment((v, "# LIMIT counter")); + sqlite3VdbeAddOp(v, OP_IfMemZero, iMem, iBreak); p->iLimit = iMem; } if( p->pOffset ){ @@ -1519,6 +1539,7 @@ static int multiSelect( switch( p->op ){ case TK_ALL: { if( pOrderBy==0 ){ + int addr = 0; assert( !pPrior->pLimit ); pPrior->pLimit = p->pLimit; pPrior->pOffset = p->pOffset; @@ -1531,11 +1552,18 @@ static int multiSelect( p->iOffset = pPrior->iOffset; p->pLimit = 0; p->pOffset = 0; + if( p->iLimit>=0 ){ + addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0); + VdbeComment((v, "# Jump ahead if LIMIT reached")); + } rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff); p->pPrior = pPrior; if( rc ){ goto multi_select_end; } + if( addr ){ + sqlite3VdbeJumpHere(v, addr); + } break; } /* For UNION ALL ... ORDER BY fall through to the next case */ @@ -1622,8 +1650,8 @@ static int multiSelect( } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak); - computeLimitRegisters(pParse, p); iStart = sqlite3VdbeCurrentAddr(v); rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, pOrderBy, -1, eDest, iParm, @@ -1698,8 +1726,8 @@ static int multiSelect( } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak); - computeLimitRegisters(pParse, p); iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0); sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont); rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, @@ -2166,10 +2194,10 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ int base; Vdbe *v; int seekOp; - int cont; ExprList *pEList, *pList, eList; struct ExprList_item eListItem; SrcList *pSrc; + int brk; /* Check to see if this query is a simple min() or max() query. Return ** zero if it is not. @@ -2233,11 +2261,11 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ */ sqlite3CodeVerifySchema(pParse, pTab->iDb); base = pSrc->a[0].iCursor; - computeLimitRegisters(pParse, p); + brk = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, brk); if( pSrc->a[0].pSelect==0 ){ sqlite3OpenTableForReading(v, base, pTab); } - cont = sqlite3VdbeMakeLabel(v); if( pIdx==0 ){ sqlite3VdbeAddOp(v, seekOp, base, 0); }else{ @@ -2266,8 +2294,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ memset(&eListItem, 0, sizeof(eListItem)); eList.a = &eListItem; eList.a[0].pExpr = pExpr; - selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0); - sqlite3VdbeResolveLabel(v, cont); + selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0); + sqlite3VdbeResolveLabel(v, brk); sqlite3VdbeAddOp(v, OP_Close, base, 0); return 1; @@ -2615,6 +2643,7 @@ int sqlite3Select( int rc = 1; /* Value to return from this function */ int addrSortIndex; /* Address of an OP_OpenVirtual instruction */ AggInfo sAggInfo; /* Information used by aggregate queries */ + int iEnd; /* Address of the end of the query */ if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1; if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; @@ -2663,7 +2692,6 @@ int sqlite3Select( /* If writing to memory or generating a set ** only a single column may be output. */ - assert( eDest!=SRT_Exists || pEList->nExpr==1 ); #ifndef SQLITE_OMIT_SUBQUERY if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){ sqlite3ErrorMsg(pParse, "only a single result allowed for " @@ -2772,7 +2800,8 @@ int sqlite3Select( /* Set the limiter. */ - computeLimitRegisters(pParse, p); + iEnd = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iEnd); /* If the output is destined for a temporary table, open that table. */ @@ -2780,15 +2809,6 @@ int sqlite3Select( sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr); } - - /* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists - */ - if( eDest==SRT_Mem ){ - sqlite3VdbeAddOp(v, OP_MemNull, iParm, 0); - }else if( eDest==SRT_Exists ){ - sqlite3VdbeAddOp(v, OP_MemInt, 0, iParm); - } - /* Open a virtual index to use for the distinct set. */ if( isDistinct ){ @@ -3112,6 +3132,10 @@ int sqlite3Select( } #endif + /* Jump here to skip this query + */ + sqlite3VdbeResolveLabel(v, iEnd); + /* The SELECT was successfully coded. Set the return code to 0 ** to indicate no errors. */ |