From: drh Date: Thu, 6 Oct 2005 16:53:14 +0000 (+0000) Subject: More efficient handling of the LIMIT clause. Scalar subqueries and EXISTS X-Git-Tag: version-3.6.10~3413 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ec7429ae275e752c8fe65e93aa5815e98edf7e17;p=thirdparty%2Fsqlite.git More efficient handling of the LIMIT clause. Scalar subqueries and EXISTS on compound SELECT statements now working properly. Ticket #1473. (CVS 2747) FossilOrigin-Name: edca8913ca012fc0c17343a27f819de95147b1bd --- diff --git a/manifest b/manifest index cdf00ff68d..e53c53ae5a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Check-in\s(2744)\sas\sincomplete\sand\sbroke\spragma\sintegrity_check.\s\sThis\ncompletes\sthe\schange\sand\sfixes\sthe\sproblem.\s(CVS\s2746) -D 2005-10-06T13:59:27 +C More\sefficient\shandling\sof\sthe\sLIMIT\sclause.\s\sScalar\ssubqueries\sand\sEXISTS\non\scompound\sSELECT\sstatements\snow\sworking\sproperly.\s\sTicket\s#1473.\s(CVS\s2747) +D 2005-10-06T16:53:15 F Makefile.in 12784cdce5ffc8dfb707300c34e4f1eb3b8a14f1 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -41,7 +41,7 @@ F src/complete.c 4de937dfdd4c79a501772ab2035b26082f337a79 F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940 F src/delete.c 29dac493f4d83b05f91233b116827c133bcdab72 F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d -F src/expr.c bb2cf5d5b065eaa23d5ae2620f6de0568768147d +F src/expr.c 6881c8dfe363c1ee5a5dcb463b880704acb77709 F src/func.c f63d417248808ff2632a3b576536abffcc21d858 F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 @@ -64,11 +64,11 @@ F src/pragma.c 9ec219dc4ee2d4e78f4ec5c9d1422089758af13f F src/prepare.c fc098db25d2a121affb08686cf04833fd50452d4 F src/printf.c bd421c1ad5e01013c89af63c60eab02852ccd15e F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4 -F src/select.c 034c7f7447b8711f85bef578a437ea12ca7cac53 +F src/select.c 80c95f3cebd6f7096cdcad1968316e4bb96b18b2 F src/shell.c 3596c1e559b82663057940d19ba533ad421c7dd3 F src/sqlite.h.in 461b2535550cf77aedfd44385da11ef7d63e57a2 -F src/sqliteInt.h 53daa72541b4336c5e89773cf39717ed695bd523 -F src/table.c abc7b6946a2c2ee0603f067f8210ed004ea9a9ac +F src/sqliteInt.h c9afda257c9649aef17f9ddb67ae443b800e2bae +F src/table.c e03b60eaabaeb54a00d7e931566d77302dfc19b0 F src/tclsqlite.c 4f274fae3d4a1863451a553dd8e5015747a5d91d F src/test1.c 0f1a66f65a54fba029f7e93b7500d49443dc959b F src/test2.c 4196848c845626e7df894470f27329e80bfe92aa @@ -81,7 +81,7 @@ F src/update.c ac506fb7400158f826ec6c3a0dbe65e7ed3928d5 F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c F src/util.c 55caaffbb2716f9928ab452d20f3e9cbbeab872d F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c -F src/vdbe.c 3f1adcf4535dd35e4244d19d332fb6b515491c0d +F src/vdbe.c c9aca7cc6dc381c4ce5a59c97ac148ed0659fb3c F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13 F src/vdbeInt.h 7bedbb9553a10e86b53f75d99e197f3f00a732bf F src/vdbeapi.c 85bbe1d0243a89655433d60711b4bd71979b59cd @@ -224,6 +224,7 @@ F test/tkt1435.test f768e5415d102fa1d8de3f548469d8fd1b79abd8 F test/tkt1443.test 1e83b6a1e7f6e261682e67106ab3bc05f6c70e90 F test/tkt1444.test 0f0fc1f277691f904dea2abece6db919dcae2351 F test/tkt1449.test f8de8a84ec12ee805ed80055e1209560f8bee4d8 +F test/tkt1473.test e4637c27d606fd002de78113a8e1a142e48ffb18 F test/trace.test 9fd28695c463b90c2d32c387a432e01eb26e8ccf F test/trans.test 10506dc30305cfb8c4098359f7f6f64786f69c5e F test/trigger1.test 152aed5a1fa90709fe171f2ca501a6b7f7901479 @@ -243,7 +244,7 @@ F test/vacuum.test 5d4857ae2afc9c20d0edb8acc58bdc8d630126a9 F test/vacuum2.test 5d77e98c458bcdbeecc6327de5107179ba1aa095 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/view.test ce0f0ad39fa4a3572acffcf1e634850ee151aae0 -F test/where.test ce21f4910ef6a0c08f8172857baecefca20a3b0c +F test/where.test 752728413eab42e5854690d84c7319cdf7edc515 F test/where2.test 503e2e2b6abe14c5c10222e72d08ef84c1bf1ffb F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/lemon.c c88936c67f6411608db8fa4254d254f509fa40f6 @@ -314,7 +315,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 9709f0f6bcb2a1ed07e678b73cb518488b8ff333 -R 4e003316fcdb49418371e800e7deae56 +P 4862eaafd875eb1069076864c7cad600a76620c7 +R 24aa61823d2322d621f097e15a448b5d U drh -Z 348c11fe0babe3db160a693e1bb13ff7 +Z e25e42a04ed4277adccd254634ad3dc4 diff --git a/manifest.uuid b/manifest.uuid index 4de4a4c7bb..0598cb0fe5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4862eaafd875eb1069076864c7cad600a76620c7 \ No newline at end of file +edca8913ca012fc0c17343a27f819de95147b1bd \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index c415e7ab55..f1eae86d64 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.230 2005/09/23 21:11:54 drh Exp $ +** $Id: expr.c,v 1.231 2005/10/06 16:53:15 drh Exp $ */ #include "sqliteInt.h" #include @@ -1390,21 +1390,25 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ ** value of this select in a memory cell and record the number ** of the memory cell in iColumn. */ - int sop; + static const Token one = { "1", 0, 1 }; Select *pSel; + int iMem; + int sop; - pExpr->iColumn = pParse->nMem++; + pExpr->iColumn = iMem = pParse->nMem++; pSel = pExpr->pSelect; if( pExpr->op==TK_SELECT ){ sop = SRT_Mem; + sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0); + VdbeComment((v, "# Init subquery result")); }else{ - static const Token one = { "1", 0, 1 }; sop = SRT_Exists; - sqlite3ExprListDelete(pSel->pEList); - pSel->pEList = sqlite3ExprListAppend(0, - sqlite3Expr(TK_INTEGER, 0, 0, &one), 0); + sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem); + VdbeComment((v, "# Init EXISTS result")); } - sqlite3Select(pParse, pSel, sop, pExpr->iColumn, 0, 0, 0, 0); + sqlite3ExprDelete(pSel->pLimit); + pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one); + sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0); break; } } diff --git a/src/select.c b/src/select.c index 3b99cf408c..fde787d872 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. */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index beb198f087..9d172a227a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.421 2005/09/19 21:05:49 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.422 2005/10/06 16:53:15 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1149,7 +1149,7 @@ struct Select { #define SRT_Table 7 /* Store result as data with an automatic rowid */ #define SRT_VirtualTab 8 /* Create virtual table and store like SRT_Table */ #define SRT_Subroutine 9 /* Call a subroutine to handle results */ -#define SRT_Exists 10 /* Put 0 or 1 in a memory cell */ +#define SRT_Exists 10 /* Store 1 if the result is not empty */ /* ** An SQL parser context. A copy of this structure is passed through diff --git a/src/table.c b/src/table.c index a04b822764..2e1b7b42d4 100644 --- a/src/table.c +++ b/src/table.c @@ -196,4 +196,4 @@ void sqlite3_free_table( } } -#endif SQLITE_OMIT_GET_TABLE +#endif /* SQLITE_OMIT_GET_TABLE */ diff --git a/src/vdbe.c b/src/vdbe.c index d7af8f0210..a10f1a2485 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.491 2005/09/20 17:42:23 drh Exp $ +** $Id: vdbe.c,v 1.492 2005/10/06 16:53:16 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -4141,7 +4141,7 @@ case OP_MemMax: { /* no-push */ /* Opcode: MemIncr P1 P2 * ** ** Increment the integer valued memory cell P1 by 1. If P2 is not zero -** and the result after the increment is exactly 1, then jump +** and the result after the increment is exactly 0, then jump ** to P2. ** ** This instruction throws an error if the memory cell is not initially @@ -4154,7 +4154,7 @@ case OP_MemIncr: { /* no-push */ pMem = &p->aMem[i]; assert( pMem->flags==MEM_Int ); pMem->i++; - if( pOp->p2>0 && pMem->i==1 ){ + if( pOp->p2>0 && pMem->i==0 ){ pc = pOp->p2 - 1; } break; @@ -4162,16 +4162,31 @@ case OP_MemIncr: { /* no-push */ /* Opcode: IfMemPos P1 P2 * ** -** If the value of memory cell P1 is 1 or greater, jump to P2. This -** opcode assumes that memory cell P1 holds an integer value. +** 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 or if it holds something +** that is not an integer, then fall thru. */ case OP_IfMemPos: { /* no-push */ int i = pOp->p1; Mem *pMem; assert( i>=0 && inMem ); pMem = &p->aMem[i]; - assert( pMem->flags==MEM_Int ); - if( pMem->i>0 ){ + if( pMem->flags==MEM_Int && 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. +*/ +case OP_IfMemZero: { /* no-push */ + int i = pOp->p1; + Mem *pMem; + assert( i>=0 && inMem ); + pMem = &p->aMem[i]; + if( pMem->flags==MEM_Int && pMem->i==0 ){ pc = pOp->p2 - 1; } break; diff --git a/test/tkt1473.test b/test/tkt1473.test new file mode 100644 index 0000000000..bc53de3a8e --- /dev/null +++ b/test/tkt1473.test @@ -0,0 +1,716 @@ +# 2005 September 19 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests to verify that ticket #1473 has been +# fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_test tkt1473-1.1 { + execsql { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(3,4); + SELECT * FROM t1 + } +} {1 2 3 4} + +do_test tkt1473-1.2 { + execsql { + SELECT 1 FROM t1 WHERE a=1 UNION ALL SELECT 2 FROM t1 WHERE b=0 + } +} {1} +do_test tkt1473-1.3 { + execsql { + SELECT 1 FROM t1 WHERE a=1 UNION SELECT 2 FROM t1 WHERE b=0 + } +} {1} +do_test tkt1473-1.4 { + execsql { + SELECT 1 FROM t1 WHERE a=1 UNION ALL SELECT 2 FROM t1 WHERE b=4 + } +} {1 2} +do_test tkt1473-1.5 { + execsql { + SELECT 1 FROM t1 WHERE a=1 UNION SELECT 2 FROM t1 WHERE b=4 + } +} {1 2} +do_test tkt1473-1.6 { + execsql { + SELECT 1 FROM t1 WHERE a=0 UNION ALL SELECT 2 FROM t1 WHERE b=4 + } +} {2} +do_test tkt1473-1.7 { + execsql { + SELECT 1 FROM t1 WHERE a=0 UNION SELECT 2 FROM t1 WHERE b=4 + } +} {2} +do_test tkt1473-1.8 { + execsql { + SELECT 1 FROM t1 WHERE a=0 UNION ALL SELECT 2 FROM t1 WHERE b=0 + } +} {} +do_test tkt1473-1.9 { + execsql { + SELECT 1 FROM t1 WHERE a=0 UNION SELECT 2 FROM t1 WHERE b=0 + } +} {} + +do_test tkt1473-2.2 { + execsql { + SELECT (SELECT 1 FROM t1 WHERE a=1 UNION ALL SELECT 2 FROM t1 WHERE b=0) + } +} {1} +do_test tkt1473-2.3 { + execsql { + SELECT (SELECT 1 FROM t1 WHERE a=1 UNION SELECT 2 FROM t1 WHERE b=0) + } +} {1} +do_test tkt1473-2.4 { + execsql { + SELECT (SELECT 1 FROM t1 WHERE a=1 UNION ALL SELECT 2 FROM t1 WHERE b=4) + } +} {1} +do_test tkt1473-2.5 { + execsql { + SELECT (SELECT 1 FROM t1 WHERE a=1 UNION SELECT 2 FROM t1 WHERE b=4) + } +} {1} +do_test tkt1473-2.6 { + execsql { + SELECT (SELECT 1 FROM t1 WHERE a=0 UNION ALL SELECT 2 FROM t1 WHERE b=4) + } +} {2} +do_test tkt1473-2.7 { + execsql { + SELECT (SELECT 1 FROM t1 WHERE a=0 UNION SELECT 2 FROM t1 WHERE b=4) + } +} {2} +do_test tkt1473-2.8 { + execsql { + SELECT (SELECT 1 FROM t1 WHERE a=0 UNION ALL SELECT 2 FROM t1 WHERE b=0) + } +} {{}} +do_test tkt1473-2.9 { + execsql { + SELECT (SELECT 1 FROM t1 WHERE a=0 UNION SELECT 2 FROM t1 WHERE b=0) + } +} {{}} + +do_test tkt1473-3.2 { + execsql { + SELECT EXISTS + (SELECT 1 FROM t1 WHERE a=1 UNION ALL SELECT 2 FROM t1 WHERE b=0) + } +} {1} +do_test tkt1473-3.3 { + execsql { + SELECT EXISTS + (SELECT 1 FROM t1 WHERE a=1 UNION SELECT 2 FROM t1 WHERE b=0) + } +} {1} +do_test tkt1473-3.4 { + execsql { + SELECT EXISTS + (SELECT 1 FROM t1 WHERE a=1 UNION ALL SELECT 2 FROM t1 WHERE b=4) + } +} {1} +do_test tkt1473-3.5 { + execsql { + SELECT EXISTS + (SELECT 1 FROM t1 WHERE a=1 UNION SELECT 2 FROM t1 WHERE b=4) + } +} {1} +do_test tkt1473-3.6 { + execsql { + SELECT EXISTS + (SELECT 1 FROM t1 WHERE a=0 UNION ALL SELECT 2 FROM t1 WHERE b=4) + } +} {1} +do_test tkt1473-3.7 { + execsql { + SELECT EXISTS + (SELECT 1 FROM t1 WHERE a=0 UNION SELECT 2 FROM t1 WHERE b=4) + } +} {1} +do_test tkt1473-3.8 { + execsql { + SELECT EXISTS + (SELECT 1 FROM t1 WHERE a=0 UNION ALL SELECT 2 FROM t1 WHERE b=0) + } +} {0} +do_test tkt1473-3.9 { + execsql { + SELECT EXISTS + (SELECT 1 FROM t1 WHERE a=0 UNION SELECT 2 FROM t1 WHERE b=0) + } +} {0} + +do_test tkt1473-4.1 { + execsql { + CREATE TABLE t2(x,y); + INSERT INTO t2 VALUES(1,2); + INSERT INTO t2 SELECT x+2, y+2 FROM t2; + INSERT INTO t2 SELECT x+4, y+4 FROM t2; + INSERT INTO t2 SELECT x+8, y+8 FROM t2; + INSERT INTO t2 SELECT x+16, y+16 FROM t2; + INSERT INTO t2 SELECT x+32, y+32 FROM t2; + INSERT INTO t2 SELECT x+64, y+64 FROM t2; + SELECT count(*), sum(x), sum(y) FROM t2; + } +} {64 4096 4160} +do_test tkt1473-4.2 { + execsql { + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=3 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=2 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=4 + } +} {2 4 8 10} +do_test tkt1473-4.3 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=3 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=2 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {2} +do_test tkt1473-4.4 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=-1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=3 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=2 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {4} +do_test tkt1473-4.5 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=-1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=-1 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=2 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=-4 + ) + } +} {8} +do_test tkt1473-4.6 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=-1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=-2 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=-3 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {10} +do_test tkt1473-4.7 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=-1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=-2 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=-3 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=-4 + ) + } +} {{}} + +do_test tkt1473-5.3 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=3 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=2 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {1} +do_test tkt1473-5.4 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=-1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=3 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=2 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {1} + +do_test tkt1473-5.5 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=-1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=-1 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=2 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=-4 + ) + } +} {1} +do_test tkt1473-5.6 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=-1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=-2 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=-3 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {1} +do_test tkt1473-5.7 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION ALL + SELECT 2 FROM t2 WHERE x=-1 + UNION ALL + SELECT 3 FROM t2 WHERE x=2 + UNION ALL + SELECT 4 FROM t2 WHERE x=-2 + UNION ALL + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION ALL + SELECT 7 FROM t2 WHERE y=1 + UNION ALL + SELECT 8 FROM t2 WHERE y=-3 + UNION ALL + SELECT 9 FROM t2 WHERE y=3 + UNION ALL + SELECT 10 FROM t2 WHERE y=-4 + ) + } +} {0} + +do_test tkt1473-6.3 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION + SELECT 2 FROM t2 WHERE x=1 + UNION + SELECT 3 FROM t2 WHERE x=2 + UNION + SELECT 4 FROM t2 WHERE x=3 + UNION + SELECT 5 FROM t2 WHERE x=4 + UNION + SELECT 6 FROM t2 WHERE y=0 + UNION + SELECT 7 FROM t2 WHERE y=1 + UNION + SELECT 8 FROM t2 WHERE y=2 + UNION + SELECT 9 FROM t2 WHERE y=3 + UNION + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {1} +do_test tkt1473-6.4 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION + SELECT 2 FROM t2 WHERE x=-1 + UNION + SELECT 3 FROM t2 WHERE x=2 + UNION + SELECT 4 FROM t2 WHERE x=3 + UNION + SELECT 5 FROM t2 WHERE x=4 + UNION + SELECT 6 FROM t2 WHERE y=0 + UNION + SELECT 7 FROM t2 WHERE y=1 + UNION + SELECT 8 FROM t2 WHERE y=2 + UNION + SELECT 9 FROM t2 WHERE y=3 + UNION + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {1} + +do_test tkt1473-6.5 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION + SELECT 2 FROM t2 WHERE x=-1 + UNION + SELECT 3 FROM t2 WHERE x=2 + UNION + SELECT 4 FROM t2 WHERE x=-1 + UNION + SELECT 5 FROM t2 WHERE x=4 + UNION + SELECT 6 FROM t2 WHERE y=0 + UNION + SELECT 7 FROM t2 WHERE y=1 + UNION + SELECT 8 FROM t2 WHERE y=2 + UNION + SELECT 9 FROM t2 WHERE y=3 + UNION + SELECT 10 FROM t2 WHERE y=-4 + ) + } +} {1} +do_test tkt1473-6.6 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION + SELECT 2 FROM t2 WHERE x=-1 + UNION + SELECT 3 FROM t2 WHERE x=2 + UNION + SELECT 4 FROM t2 WHERE x=-2 + UNION + SELECT 5 FROM t2 WHERE x=4 + UNION + SELECT 6 FROM t2 WHERE y=0 + UNION + SELECT 7 FROM t2 WHERE y=1 + UNION + SELECT 8 FROM t2 WHERE y=-3 + UNION + SELECT 9 FROM t2 WHERE y=3 + UNION + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {1} +do_test tkt1473-6.7 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION + SELECT 2 FROM t2 WHERE x=-1 + UNION + SELECT 3 FROM t2 WHERE x=2 + UNION + SELECT 4 FROM t2 WHERE x=-2 + UNION + SELECT 5 FROM t2 WHERE x=4 + UNION + SELECT 6 FROM t2 WHERE y=0 + UNION + SELECT 7 FROM t2 WHERE y=1 + UNION + SELECT 8 FROM t2 WHERE y=-3 + UNION + SELECT 9 FROM t2 WHERE y=3 + UNION + SELECT 10 FROM t2 WHERE y=-4 + ) + } +} {0} +do_test tkt1473-6.8 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION + SELECT 2 FROM t2 WHERE x=-1 + UNION + SELECT 3 FROM t2 WHERE x=2 + UNION + SELECT 4 FROM t2 WHERE x=-2 + UNION + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION + SELECT 7 FROM t2 WHERE y=1 + UNION + SELECT 8 FROM t2 WHERE y=-3 + UNION + SELECT 9 FROM t2 WHERE y=3 + UNION + SELECT 10 FROM t2 WHERE y=4 + ) + } +} {1} +do_test tkt1473-6.9 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 + UNION + SELECT 2 FROM t2 WHERE x=-1 + UNION + SELECT 3 FROM t2 WHERE x=2 + UNION + SELECT 4 FROM t2 WHERE x=-2 + UNION + SELECT 5 FROM t2 WHERE x=4 + UNION ALL + SELECT 6 FROM t2 WHERE y=0 + UNION + SELECT 7 FROM t2 WHERE y=1 + UNION + SELECT 8 FROM t2 WHERE y=-3 + UNION + SELECT 9 FROM t2 WHERE y=3 + UNION + SELECT 10 FROM t2 WHERE y=-4 + ) + } +} {0} + +do_test tkt1473-7.1 { + execsql { + SELECT 1 FROM t2 WHERE x=1 EXCEPT SELECT 2 FROM t2 WHERE y=2 + } +} {1} +do_test tkt1473-7.2 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=1 EXCEPT SELECT 2 FROM t2 WHERE y=2 + ) + } +} {1} +do_test tkt1473-7.3 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=1 EXCEPT SELECT 2 FROM t2 WHERE y=2 + ) + } +} {1} +do_test tkt1473-7.4 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=0 EXCEPT SELECT 2 FROM t2 WHERE y=2 + ) + } +} {{}} +do_test tkt1473-7.5 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=0 EXCEPT SELECT 2 FROM t2 WHERE y=2 + ) + } +} {0} + +do_test tkt1473-8.1 { + execsql { + SELECT 1 FROM t2 WHERE x=1 INTERSECT SELECT 2 FROM t2 WHERE y=2 + } +} {} +do_test tkt1473-8.1 { + execsql { + SELECT 1 FROM t2 WHERE x=1 INTERSECT SELECT 1 FROM t2 WHERE y=2 + } +} {1} +do_test tkt1473-8.3 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=1 INTERSECT SELECT 2 FROM t2 WHERE y=2 + ) + } +} {{}} +do_test tkt1473-8.4 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=1 INTERSECT SELECT 1 FROM t2 WHERE y=2 + ) + } +} {1} +do_test tkt1473-8.5 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=1 INTERSECT SELECT 2 FROM t2 WHERE y=2 + ) + } +} {0} +do_test tkt1473-8.6 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=1 INTERSECT SELECT 1 FROM t2 WHERE y=2 + ) + } +} {1} +do_test tkt1473-8.7 { + execsql { + SELECT ( + SELECT 1 FROM t2 WHERE x=0 INTERSECT SELECT 1 FROM t2 WHERE y=2 + ) + } +} {{}} +do_test tkt1473-8.8 { + execsql { + SELECT EXISTS ( + SELECT 1 FROM t2 WHERE x=1 INTERSECT SELECT 1 FROM t2 WHERE y=0 + ) + } +} {0} + + + + +finish_test diff --git a/test/where.test b/test/where.test index b946684fae..dcceb8e0d3 100644 --- a/test/where.test +++ b/test/where.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the use of indices in WHERE clases. # -# $Id: where.test,v 1.36 2005/09/08 10:37:02 drh Exp $ +# $Id: where.test,v 1.37 2005/10/06 16:53:17 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -306,7 +306,7 @@ do_test where-4.2 { count { SELECT * FROM t1 WHERE 1 LIMIT 1 } -} {1 0 4 1} +} {1 0 4 0} do_test where-4.3 { execsql { SELECT 99 WHERE 0