From c5499bef4b1a45596a5e1a4efdf208ff793c07b8 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 1 Apr 2008 15:06:33 +0000 Subject: [PATCH] Add the testcase() macro. Additional CSE test coverage. (CVS 4951) FossilOrigin-Name: 492490f9c86e52c7a706d9e1bf0ba216d5bb8aba --- manifest | 18 +++---- manifest.uuid | 2 +- src/expr.c | 132 +++++++++++++++++++++++++++++++++++++++++++----- src/main.c | 12 ++++- src/sqliteInt.h | 17 ++++++- test/cse.test | 35 +++++++++++-- 6 files changed, 185 insertions(+), 31 deletions(-) diff --git a/manifest b/manifest index 9bec6ebae7..33ab66fec1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\sCASTs\sand\sthe\snew\sCSE\smechanism.\s(CVS\s4950) -D 2008-04-01T12:24:11 +C Add\sthe\stestcase()\smacro.\s\sAdditional\sCSE\stest\scoverage.\s(CVS\s4951) +D 2008-04-01T15:06:34 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in b861627d91df5ee422c54237aa38296954dc0151 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -95,7 +95,7 @@ F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c e41ce4513fb0e359dc678d6bddb4ace135fe365d F src/delete.c 74d5c9c824848a14d7dee37264ec302b168c4ddb F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c 64843f848a36edf1fe4d95bfd3e7a9090580c4a3 +F src/expr.c bc7ab980abcc211083148eeaea571c4511f41238 F src/fault.c 83057e86815d473e526f7df0b0108dfdd022ff23 F src/func.c c9e8c7ff4c45027edee89bde7adbf86a3a3b2afe F src/hash.c 53655c312280211444bfe23af6490a460aec2980 @@ -104,7 +104,7 @@ F src/insert.c 6974a1d02f2dcd616d00eef4996d4872495fad0f F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 8267890e6a0a71f13b680794520999c642299081 F src/loadext.c f26b22f7c84153c9d5dbd7c240848823c6e6b6dc -F src/main.c 7d22155e35094bc5d368202c3db8a3fc429548af +F src/main.c b499fa9fa2551d0963404e1b582747ef92754dd0 F src/malloc.c 12c1ae98ef1eff34b13c9eb526e0b7b479e1e820 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/mem1.c fc716ff521b6dd3e43eaa211967383308800e70a @@ -140,7 +140,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 22297fffa6f00a6c6d44020fa13b1184a1bb372d F src/sqlite.h.in b1ac824d9fc163a5d2226ebf5990b09a02a11117 F src/sqlite3ext.h faacd0e6a81aabee0861c6d7883c9172e74ef5b3 -F src/sqliteInt.h 1b7ad8791bf441901914734fb1f9735b58adfb37 +F src/sqliteInt.h 3b9a1f2338d6b0d4361b1901543c830a45a45637 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/table.c 2c48c575dd59b3a6c5c306bc55f51a9402cf429a F src/tclsqlite.c 1367762764772a233643524c3585b4711a9adcda @@ -248,7 +248,7 @@ F test/crash5.test c7ddcf7ca83abc19901b977732144234ac72a938 F test/crash6.test 873d851c5ba2a46e0f9974c54e1d4a77d9a587d5 F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272 -F test/cse.test 36b0079f67f187e4dffe8f3047e04cf10f5f75f9 +F test/cse.test cb548fa3000a246c80fde7adaa0ee4bd85cbc5e9 F test/date.test 8db95a0ba2c8f4c8762ce66859a036c51959a6be F test/default.test 252298e42a680146b1dd64f563b95bdf088d94fb F test/delete.test 57533e88e886608bf5ae0f394e14c2eb1b1f7754 @@ -621,7 +621,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 91cc646e2b0c1d62a1989405cc9384a2c22d98d0 -R 0b78187a1b465d3d8c93c57ba92e771e +P e25939fb25ec8bde8500a672ca5be3cbb514ac3a +R 739e5874578bdbb30904d6eb328630e7 U drh -Z ed15e3f8ef7420ee4fecf6ce237f8aee +Z 3436b9a596d9596333afb3b553896141 diff --git a/manifest.uuid b/manifest.uuid index fb6db5fc8f..66aa29daea 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e25939fb25ec8bde8500a672ca5be3cbb514ac3a \ No newline at end of file +492490f9c86e52c7a706d9e1bf0ba216d5bb8aba \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index ec9f7d554a..aa01fb9a39 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.363 2008/04/01 12:24:11 drh Exp $ +** $Id: expr.c,v 1.364 2008/04/01 15:06:34 drh Exp $ */ #include "sqliteInt.h" #include @@ -428,6 +428,10 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ ** use it as the variable number */ int i; pExpr->iTable = i = atoi((char*)&pToken->z[1]); + testcase( i==0 ); + testcase( i==1 ); + testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); + testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); if( i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); @@ -727,6 +731,8 @@ void sqlite3ExprListCheckLength( const char *zObject ){ int mx = pParse->db->aLimit[SQLITE_LIMIT_COLUMN]; + testcase( pEList && pEList->nExpr==mx ); + testcase( pEList && pEList->nExpr==mx+1 ); if( pEList && pEList->nExpr>mx ){ sqlite3ErrorMsg(pParse, "too many columns in %s", zObject); } @@ -909,7 +915,14 @@ static int exprNodeIsConstant(void *pArg, Expr *pExpr){ #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: case TK_EXISTS: + testcase( pExpr->op==TK_SELECT ); + testcase( pExpr->op==TK_EXISTS ); #endif + testcase( pExpr->op==TK_ID ); + testcase( pExpr->op==TK_COLUMN ); + testcase( pExpr->op==TK_DOT ); + testcase( pExpr->op==TK_AGG_FUNCTION ); + testcase( pExpr->op==TK_AGG_COLUMN ); *pN = 0; return 2; case TK_IN: @@ -1165,6 +1178,8 @@ static int lookupName( } pExpr->pTab = pTab; if( iCol>=0 ){ + testcase( iCol==31 ); + testcase( iCol==32 ); *piColMask |= ((u32)1<=32?0xffffffff:0); } break; @@ -1274,6 +1289,7 @@ static int lookupName( */ if( pExpr->iColumn>=0 && pMatch!=0 ){ int n = pExpr->iColumn; + testcase( n==sizeof(Bitmask)*8-1 ); if( n>=sizeof(Bitmask)*8 ){ n = sizeof(Bitmask)*8-1; } @@ -1809,6 +1825,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ /* Evaluate the expression and insert it into the temp table */ pParse->disableColCache++; sqlite3ExprCode(pParse, pE2, r1); + assert( pParse->disableColCache>0 ); pParse->disableColCache--; sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); sqlite3ExprCacheAffinityChange(pParse, r1, 1); @@ -1982,6 +1999,7 @@ int sqlite3ExprCodeGetColumn( p->iTable = iTable; p->iColumn = iColumn; p->iReg = iReg; + p->affChange = 0; i++; if( i>=ArraySize(pParse->aColCache) ) i = 0; if( i>pParse->nColCache ) pParse->nColCache = i; @@ -1990,15 +2008,6 @@ int sqlite3ExprCodeGetColumn( return iReg; } -/* -** Disable (+1) or enable (-1) the adding of new column cache entries. -*/ -void sqlite3ExprColumnCacheDisable(Parse *pParse, int disable){ - assert( disable==-1 || disable==+1 ); - assert( pParse->disableColCache>0 || disable==1 ); - pParse->disableColCache += disable; -} - /* ** Clear all column cache entries associated with the vdbe ** cursor with cursor number iTable. @@ -2011,6 +2020,7 @@ void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){ int i; for(i=0; inColCache; i++){ if( pParse->aColCache[i].iTable==iTable ){ + testcase( i==pParse->nColCache-1 ); pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache]; pParse->iColCache = pParse->nColCache; } @@ -2140,6 +2150,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ assert( pParse->ckBase>0 ); inReg = pExpr->iColumn + pParse->ckBase; }else{ + testcase( (pExpr->flags & EP_AnyAff)!=0 ); inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, pExpr->iColumn, pExpr->iTable, target, pExpr->flags & EP_AnyAff); @@ -2203,7 +2214,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); + testcase( to_op==OP_ToText ); + testcase( to_op==OP_ToBlob ); + testcase( to_op==OP_ToNumeric ); + testcase( to_op==OP_ToInt ); + testcase( to_op==OP_ToReal ); sqlite3VdbeAddOp1(v, to_op, inReg); + testcase( usedAsColumnCache(pParse, inReg, inReg) ); sqlite3ExprCacheAffinityChange(pParse, inReg, 1); break; } @@ -2220,10 +2237,18 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ assert( TK_GE==OP_Ge ); assert( TK_EQ==OP_Eq ); assert( TK_NE==OP_Ne ); + testcase( op==TK_LT ); + testcase( op==TK_LE ); + testcase( op==TK_GT ); + testcase( op==TK_GE ); + testcase( op==TK_EQ ); + testcase( op==TK_NE ); codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2); + testcase( regFree1==0 ); + testcase( regFree2==0 ); break; } case TK_AND: @@ -2249,9 +2274,22 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ assert( TK_LSHIFT==OP_ShiftLeft ); assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_CONCAT==OP_Concat ); + testcase( op==TK_AND ); + testcase( op==TK_OR ); + testcase( op==TK_PLUS ); + testcase( op==TK_MINUS ); + testcase( op==TK_REM ); + testcase( op==TK_BITAND ); + testcase( op==TK_BITOR ); + testcase( op==TK_SLASH ); + testcase( op==TK_LSHIFT ); + testcase( op==TK_RSHIFT ); + testcase( op==TK_CONCAT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); sqlite3VdbeAddOp3(v, op, r2, r1, target); + testcase( regFree1==0 ); + testcase( regFree2==0 ); break; } case TK_UMINUS: { @@ -2269,6 +2307,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ sqlite3VdbeAddOp2(v, OP_Integer, 0, r1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); + testcase( regFree2==0 ); } inReg = target; break; @@ -2277,7 +2316,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); assert( TK_NOT==OP_Not ); + testcase( op==TK_BITNOT ); + testcase( op==TK_NOT ); inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + testcase( inReg==target ); + testcase( usedAsColumnCache(pParse, inReg, inReg) ); inReg = sqlite3ExprWritableRegister(pParse, inReg, target); sqlite3VdbeAddOp1(v, op, inReg); break; @@ -2287,8 +2330,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ int addr; assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); + testcase( op==TK_ISNULL ); + testcase( op==TK_NOTNULL ); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + testcase( regFree1==0 ); addr = sqlite3VdbeAddOp1(v, op, r1); sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeJumpHere(v, addr); @@ -2317,6 +2363,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ u8 enc = ENC(db); CollSeq *pColl = 0; + testcase( op==TK_CONST_FUNC ); + testcase( op==TK_FUNCTION ); zId = (char*)pExpr->token.z; nId = pExpr->token.n; pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0); @@ -2371,6 +2419,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { + testcase( op==TK_EXISTS ); + testcase( op==TK_SELECT ); if( pExpr->iColumn==0 ){ sqlite3CodeSubselect(pParse, pExpr); } @@ -2396,6 +2446,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ ** pExpr->iTable contains the values that make up the (...) set. */ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + testcase( regFree1==0 ); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); sqlite3VdbeAddOp2(v, OP_Null, 0, target); j2 = sqlite3VdbeAddOp0(v, OP_Goto); @@ -2436,6 +2487,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ codeCompareOperands(pParse, pLeft, &r1, ®Free1, pRight, &r2, ®Free2); + testcase( regFree1==0 ); + testcase( regFree2==0 ); r3 = sqlite3GetTempReg(pParse); r4 = sqlite3GetTempReg(pParse); codeCompare(pParse, pLeft, pRight, OP_Ge, @@ -2444,6 +2497,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ pRight = pLItem->pExpr; sqlite3ReleaseTempReg(pParse, regFree2); r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2); + testcase( regFree2==0 ); codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2); sqlite3VdbeAddOp3(v, OP_And, r3, r4, target); sqlite3ReleaseTempReg(pParse, r3); @@ -2497,14 +2551,16 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ endLabel = sqlite3VdbeMakeLabel(v); if( (pX = pExpr->pLeft)!=0 ){ cacheX = *pX; + testcase( pX->op==TK_COLUMN || pX->op==TK_REGISTER ); cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, ®Free1); + testcase( regFree1==0 ); cacheX.op = TK_REGISTER; cacheX.iColumn = 0; opCompare.op = TK_EQ; opCompare.pLeft = &cacheX; pTest = &opCompare; } - sqlite3ExprColumnCacheDisable(pParse, 1); + pParse->disableColCache++; for(i=0; iop==TK_COLUMN || pTest->op==TK_REGISTER ); sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); + testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); + testcase( aListelem[i+1].pExpr->op==TK_REGISTER ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel); sqlite3VdbeResolveLabel(v, nextCase); @@ -2523,7 +2582,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } sqlite3VdbeResolveLabel(v, endLabel); - sqlite3ExprColumnCacheDisable(pParse, -1); + assert( pParse->disableColCache>0 ); + pParse->disableColCache--; break; } #ifndef SQLITE_OMIT_TRIGGER @@ -2635,7 +2695,7 @@ static int evalConstExpr(void *pArg, Expr *pExpr){ int r1 = ++pParse->nMem; int r2; r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); - if( r1!=r2 ) pParse->nMem--; + if( r1!=r2 ) sqlite3ReleaseTempReg(pParse, r1); pExpr->iColumn = pExpr->op; pExpr->op = TK_REGISTER; pExpr->iTable = r2; @@ -2707,21 +2767,28 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); + testcase( jumpIfNull==0 ); + testcase( pParse->disableColCache==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); pParse->disableColCache++; sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + assert( pParse->disableColCache>0 ); pParse->disableColCache--; sqlite3VdbeResolveLabel(v, d2); break; } case TK_OR: { + testcase( jumpIfNull==0 ); + testcase( pParse->disableColCache==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); pParse->disableColCache++; sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + assert( pParse->disableColCache>0 ); pParse->disableColCache--; break; } case TK_NOT: { + testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } @@ -2737,18 +2804,30 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ assert( TK_GE==OP_Ge ); assert( TK_EQ==OP_Eq ); assert( TK_NE==OP_Ne ); + testcase( op==TK_LT ); + testcase( op==TK_LE ); + testcase( op==TK_GT ); + testcase( op==TK_GE ); + testcase( op==TK_EQ ); + testcase( op==TK_NE ); + testcase( jumpIfNull==0 ); codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull); + testcase( regFree1==0 ); + testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); + testcase( op==TK_ISNULL ); + testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeAddOp2(v, op, r1, dest); + testcase( regFree1==0 ); break; } case TK_BETWEEN: { @@ -2777,13 +2856,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ compRight.pLeft = &exprX; compRight.pRight = pExpr->pList->a[1].pExpr; exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1); + testcase( regFree1==0 ); exprX.op = TK_REGISTER; + testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull); break; } default: { r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); + testcase( regFree1==0 ); + testcase( jumpIfNull==0 ); break; } } @@ -2843,17 +2926,23 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ switch( pExpr->op ){ case TK_AND: { + testcase( jumpIfNull==0 ); + testcase( pParse->disableColCache==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); pParse->disableColCache++; sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + assert( pParse->disableColCache>0 ); pParse->disableColCache--; break; } case TK_OR: { int d2 = sqlite3VdbeMakeLabel(v); + testcase( jumpIfNull==0 ); + testcase( pParse->disableColCache==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); pParse->disableColCache++; sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + assert( pParse->disableColCache>0 ); pParse->disableColCache--; sqlite3VdbeResolveLabel(v, d2); break; @@ -2868,16 +2957,28 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ case TK_GE: case TK_NE: case TK_EQ: { + testcase( op==TK_LT ); + testcase( op==TK_LE ); + testcase( op==TK_GT ); + testcase( op==TK_GE ); + testcase( op==TK_EQ ); + testcase( op==TK_NE ); + testcase( jumpIfNull==0 ); codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull); + testcase( regFree1==0 ); + testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { + testcase( op==TK_ISNULL ); + testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeAddOp2(v, op, r1, dest); + testcase( regFree1==0 ); break; } case TK_BETWEEN: { @@ -2906,13 +3007,17 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ compRight.pLeft = &exprX; compRight.pRight = pExpr->pList->a[1].pExpr; exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1); + testcase( regFree1==0 ); exprX.op = TK_REGISTER; + testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull); break; } default: { r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); + testcase( regFree1==0 ); + testcase( jumpIfNull==0 ); break; } } @@ -3187,7 +3292,6 @@ int sqlite3GetTempReg(Parse *pParse){ } void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg && pParse->nTempRegaTempReg) ){ - assert( iReg>0 ); pParse->aTempReg[pParse->nTempReg++] = iReg; } } diff --git a/src/main.c b/src/main.c index 41b84c0948..68eb1c0505 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.429 2008/03/21 16:45:47 drh Exp $ +** $Id: main.c,v 1.430 2008/04/01 15:06:34 drh Exp $ */ #include "sqliteInt.h" #include @@ -47,6 +47,16 @@ void (*sqlite3IoTrace)(const char*, ...) = 0; */ char *sqlite3_temp_directory = 0; +/* +** Routine needed to support the testcase() macro. +*/ +#ifdef SQLITE_COVERAGE_TEST +void sqlite3Coverage(int x){ + static int dummy = 0; + dummy += x; +} +#endif + /* ** Return true if the buffer z[0..n-1] contains all spaces. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b6bb441513..de3a46a231 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.686 2008/04/01 05:07:15 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.687 2008/04/01 15:06:34 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -48,6 +48,20 @@ typedef int sqlite3_intptr_t; #endif +/* +** A macro used to aid in coverage testing. When doing coverage +** testing, the condition inside the argument must be evaluated +** both true and false in order to get full branch coverage. +** This macro can be inserted to ensure adequate test coverage +** in places where simple condition/decision coverage is inadequate. +*/ +#ifdef SQLITE_COVERAGE_TEST + void sqlite3Coverage(int); +# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); } +#else +# define testcase(X) +#endif + /* ** The macro unlikely() is a hint that surrounds a boolean @@ -1841,7 +1855,6 @@ void sqlite3WhereEnd(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int); void sqlite3ExprClearColumnCache(Parse*, int); -void sqlite3ExprColumnCacheDisable(Parse*, int); void sqlite3ExprCacheAffinityChange(Parse*, int, int); int sqlite3ExprWritableRegister(Parse*,int,int); int sqlite3ExprCode(Parse*, Expr*, int); diff --git a/test/cse.test b/test/cse.test index ce16d791ca..836e15aba9 100644 --- a/test/cse.test +++ b/test/cse.test @@ -13,7 +13,7 @@ # factoring constant expressions out of loops and for # common subexpression eliminations. # -# $Id: cse.test,v 1.3 2008/04/01 12:24:11 drh Exp $ +# $Id: cse.test,v 1.4 2008/04/01 15:06:34 drh Exp $ # set testdir [file dirname $argv0] @@ -70,13 +70,40 @@ do_test cse-1.9 { } } {0 -12 1 11 0 -22 1 21} do_test cse-1.10 { - explain { - SELECT CAST(b AS integer), typeof(b), CAST(b AS text), typeof(b) FROM t1 - } execsql { SELECT CAST(b AS integer), typeof(b), CAST(b AS text), typeof(b) FROM t1 } } {11 integer 11 integer 21 integer 21 integer} +do_test cse-1.11 { + execsql { + SELECT *,* FROM t1 WHERE a=2 + UNION ALL + SELECT *,* FROM t1 WHERE a=1 + } +} {2 21 22 23 24 25 2 21 22 23 24 25 1 11 12 13 14 15 1 11 12 13 14 15} +do_test cse-1.12 { + execsql { + SELECT coalesce(b,c,d,e), a, b, c, d, e FROM t1 WHERE a=2 + UNION ALL + SELECT coalesce(e,d,c,b), e, d, c, b, a FROM t1 WHERE a=1 + } +} {21 2 21 22 23 24 14 14 13 12 11 1} +do_test cse-1.13 { + explain { + SELECT upper(b), typeof(b), b FROM t1 + } + execsql { + SELECT upper(b), typeof(b), b FROM t1 + } +} {11 integer 11 21 integer 21} +do_test cse-1.14 { + explain { + SELECT b, typeof(b), upper(b), typeof(b), b FROM t1 + } + execsql { + SELECT b, typeof(b), upper(b), typeof(b), b FROM t1 + } +} {11 integer 11 integer 11 21 integer 21 integer 21} # Overflow the column cache. Create queries involving more and more # columns until the cache overflows. Verify correct operation throughout.