Index: src/analyze.c ================================================================== --- src/analyze.c +++ src/analyze.c @@ -1272,14 +1272,11 @@ VdbeCoverage(v); callStatGet(v, regStat4, STAT_GET_NEQ, regEq); callStatGet(v, regStat4, STAT_GET_NLT, regLt); callStatGet(v, regStat4, STAT_GET_NDLT, regDLt); sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0); - /* We know that the regSampleRowid row exists because it was read by - ** the previous loop. Thus the not-found jump of seekOp will never - ** be taken */ - VdbeCoverageNeverTaken(v); + VdbeCoverage(v); #ifdef SQLITE_ENABLE_STAT3 sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample); #else for(i=0; ipWith = withDup(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn); #endif - sqlite3SelectSetName(pNew, p->zSelName); + pNew->selId = p->selId; *pp = pNew; pp = &pNew->pPrior; pNext = pNew; } Index: src/insert.c ================================================================== --- src/insert.c +++ src/insert.c @@ -1630,23 +1630,23 @@ int regR; /* Range of registers holding conflicting PK */ int iThisCur; /* Cursor for this UNIQUE index */ int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ + if( bAffinityDone==0 ){ + sqlite3TableAffinity(v, pTab, regNewData+1); + bAffinityDone = 1; + } if( pUpIdx==pIdx ){ addrUniqueOk = sAddr.upsertBtm; upsertBypass = sqlite3VdbeGoto(v, 0); VdbeComment((v, "Skip upsert subroutine")); sqlite3VdbeResolveLabel(v, sAddr.upsertTop2); }else{ addrUniqueOk = sqlite3VdbeMakeLabel(v); } VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName)); - if( bAffinityDone==0 ){ - sqlite3TableAffinity(v, pTab, regNewData+1); - bAffinityDone = 1; - } iThisCur = iIdxCur+ix; /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -3972,11 +3972,12 @@ ** Set the VDBE coverage callback function to xCallback with context ** pointer ptr. */ case SQLITE_TESTCTRL_VDBE_COVERAGE: { #ifdef SQLITE_VDBE_COVERAGE - typedef void (*branch_callback)(void*,int,u8,u8); + typedef void (*branch_callback)(void*,unsigned int, + unsigned char,unsigned char); sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback); sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*); #endif break; } Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -544,50 +544,24 @@ %type multiselect_op {int} multiselect_op(A) ::= UNION(OP). {A = @OP; /*A-overwrites-OP*/} multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP; /*A-overwrites-OP*/} %endif SQLITE_OMIT_COMPOUND_SELECT -oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y) +oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) groupby_opt(P) having_opt(Q) %ifndef SQLITE_OMIT_WINDOWFUNC windowdefn_opt(R) %endif orderby_opt(Z) limit_opt(L). { -#if SELECTTRACE_ENABLED - Token s = S; /*A-overwrites-S*/ -#endif A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L); #ifndef SQLITE_OMIT_WINDOWFUNC if( A ){ A->pWinDefn = R; }else{ sqlite3WindowListDelete(pParse->db, R); } #endif /* SQLITE_OMIT_WINDOWFUNC */ -#if SELECTTRACE_ENABLED - /* Populate the Select.zSelName[] string that is used to help with - ** query planner debugging, to differentiate between multiple Select - ** objects in a complex query. - ** - ** If the SELECT keyword is immediately followed by a C-style comment - ** then extract the first few alphanumeric characters from within that - ** comment to be the zSelName value. Otherwise, the label is #N where - ** is an integer that is incremented with each SELECT statement seen. - */ - if( A!=0 ){ - const char *z = s.z+6; - int i; - sqlite3_snprintf(sizeof(A->zSelName), A->zSelName,"#%d",++pParse->nSelect); - while( z[0]==' ' ) z++; - if( z[0]=='/' && z[1]=='*' ){ - z += 2; - while( z[0]==' ' ) z++; - for(i=0; sqlite3Isalnum(z[i]); i++){} - sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "%.*s", i, z); - } - } -#endif /* SELECTRACE_ENABLED */ } oneselect(A) ::= values(A). %type values {Select*} %destructor values {sqlite3SelectDelete(pParse->db, $$);} Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -19,11 +19,11 @@ */ #if SELECTTRACE_ENABLED /***/ int sqlite3SelectTrace = 0; # define SELECTTRACE(K,P,S,X) \ if(sqlite3SelectTrace&(K)) \ - sqlite3DebugPrintf("%s/%d/%p: ",(S)->zSelName,(P)->addrExplain,(S)),\ + sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\ sqlite3DebugPrintf X #else # define SELECTTRACE(K,P,S,X) #endif @@ -149,13 +149,11 @@ pNew->pEList = pEList; pNew->op = TK_SELECT; pNew->selFlags = selFlags; pNew->iLimit = 0; pNew->iOffset = 0; -#if SELECTTRACE_ENABLED - pNew->zSelName[0] = 0; -#endif + pNew->selId = ++pParse->nSelect; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc)); pNew->pSrc = pSrc; @@ -179,21 +177,10 @@ } assert( pNew!=&standin ); return pNew; } -#if SELECTTRACE_ENABLED -/* -** Set the name of a Select object -*/ -void sqlite3SelectSetName(Select *p, const char *zName){ - if( p && zName ){ - sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName); - } -} -#endif - /* ** Delete the given Select structure and all of its substructures. */ void sqlite3SelectDelete(sqlite3 *db, Select *p){ @@ -3836,12 +3823,12 @@ ** restriction (17d3) */ assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 ); /***** If we reach this point, flattening is permitted. *****/ - SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n", - pSub->zSelName, pSub, iFrom)); + SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n", + pSub->selId, pSub, iFrom)); /* Authorize the subquery */ pParse->zAuthContext = pSubitem->zName; TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0); testcase( i==SQLITE_DENY ); @@ -3888,11 +3875,10 @@ p->pOrderBy = 0; p->pSrc = 0; p->pPrior = 0; p->pLimit = 0; pNew = sqlite3SelectDup(db, p, 0); - sqlite3SelectSetName(pNew, pSub->zSelName); p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->pSrc = pSrc; p->op = TK_ALL; if( pNew==0 ){ @@ -3901,11 +3887,11 @@ pNew->pPrior = pPrior; if( pPrior ) pPrior->pNext = pNew; pNew->pNext = p; p->pPrior = pNew; SELECTTRACE(2,pParse,p,("compound-subquery flattener" - " creates %s.%p as peer\n",pNew->zSelName, pNew)); + " creates %u as peer\n",pNew->selId)); } if( db->mallocFailed ) return 1; } /* Begin flattening the iFrom-th entry of the FROM clause @@ -4621,11 +4607,11 @@ if( pTab==0 ) return SQLITE_NOMEM; pTab->nTabRef = 1; if( pFrom->zAlias ){ pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias); }else{ - pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%p", (void*)pTab); + pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId); } while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); @@ -4727,11 +4713,10 @@ if( IsVirtual(pTab) || pTab->pSelect ){ i16 nCol; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); - sqlite3SelectSetName(pFrom->pSelect, pTab->zName); nCol = pTab->nCol; pTab->nCol = -1; sqlite3WalkSelect(pWalker, pFrom->pSelect); pTab->nCol = nCol; } @@ -5719,11 +5704,11 @@ pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%s", pItem->pTab->zName)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); - ExplainQueryPlan((pParse, 1, "CO-ROUTINE 0x%p", pSub)); + ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeEndCoroutine(v, pItem->regReturn); @@ -5758,11 +5743,11 @@ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); assert( pPrior->pSelect!=0 ); pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - ExplainQueryPlan((pParse, 1, "MATERIALIZE 0x%p", pSub)); + ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId)); sqlite3Select(pParse, pSub, &dest); } pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); @@ -5938,11 +5923,11 @@ sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); sqlite3VdbeResolveLabel(v, addrGosub); - VdbeNoopComment((v, "SELECT inner-loop subroutine")); + VdbeNoopComment((v, "inner-loop subroutine")); selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp1(v, OP_Return, regGosub); VdbeComment((v, "end inner-loop subroutine")); sqlite3VdbeResolveLabel(v, iBreak); Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -1582,10 +1582,11 @@ #define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */ #define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */ #define SQLITE_PushDown 0x1000 /* The push-down optimization */ #define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */ +#define SQLITE_SkipScan 0x4000 /* Skip-scans */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ @@ -2807,13 +2808,11 @@ ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ -#if SELECTTRACE_ENABLED - char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ -#endif + u32 selId; /* Unique identifier number for this SELECT */ int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ Expr *pHaving; /* The HAVING clause */ @@ -3070,13 +3069,11 @@ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ -#if SELECTTRACE_ENABLED - int nSelect; /* Number of SELECT statements seen */ -#endif + int nSelect; /* Number of SELECT stmts. Counter for Select.selId */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ @@ -3386,11 +3383,11 @@ #endif #ifdef SQLITE_VDBE_COVERAGE /* The following callback (if not NULL) is invoked on every VDBE branch ** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE. */ - void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */ + void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif @@ -3518,11 +3515,11 @@ Expr *pStart; /* Expression for " PRECEDING" */ Expr *pEnd; /* Expression for " FOLLOWING" */ Window *pNextWin; /* Next window function belonging to this SELECT */ Expr *pFilter; /* The FILTER expression */ FuncDef *pFunc; /* The function */ - int iEphCsr; /* Temp table used by this window */ + int iEphCsr; /* Partition buffer or Peer buffer */ int regAccum; int regResult; int csrApp; /* Function cursor (used by min/max) */ int regApp; /* Function register (also used by min/max) */ int regPart; /* First in a set of registers holding PARTITION BY @@ -4023,15 +4020,10 @@ Expr *sqlite3ExprDup(sqlite3*,Expr*,int); ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); IdList *sqlite3IdListDup(sqlite3*,IdList*); Select *sqlite3SelectDup(sqlite3*,Select*,int); -#if SELECTTRACE_ENABLED -void sqlite3SelectSetName(Select*,const char*); -#else -# define sqlite3SelectSetName(A,B) -#endif void sqlite3InsertBuiltinFuncs(FuncDef*,int); FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); void sqlite3RegisterBuiltinFunctions(void); void sqlite3RegisterDateTimeFunctions(void); void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -6952,10 +6952,11 @@ { "order-by-idx-join", SQLITE_OrderByIdxJoin }, { "transitive", SQLITE_Transitive }, { "omit-noop-join", SQLITE_OmitNoopJoin }, { "stat3", SQLITE_Stat34 }, { "stat4", SQLITE_Stat34 }, + { "skip-scan", SQLITE_SkipScan }, }; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN"); return TCL_ERROR; Index: src/treeview.c ================================================================== --- src/treeview.c +++ src/treeview.c @@ -137,25 +137,17 @@ sqlite3TreeViewWith(pView, p->pWith, 1); cnt = 1; sqlite3TreeViewPush(pView, 1); } do{ -#if SELECTTRACE_ENABLED - sqlite3TreeViewLine(pView, - "SELECT%s%s (%s/%p) selFlags=0x%x nSelectRow=%d", - ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), - ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), - p->zSelName, p, p->selFlags, - (int)p->nSelectRow - ); -#else - sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", - ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), - ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, - (int)p->nSelectRow - ); -#endif + sqlite3TreeViewLine(pView, + "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d", + ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), + ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), + p->selId, p, p->selFlags, + (int)p->nSelectRow + ); if( cnt++ ) sqlite3TreeViewPop(pView); if( p->pPrior ){ n = 1000; }else{ n = 0; Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -521,11 +521,11 @@ /* Top of the update loop */ if( eOnePass!=ONEPASS_OFF ){ if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){ assert( pPk ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey); - VdbeCoverageNeverTaken(v); + VdbeCoverage(v); } if( eOnePass!=ONEPASS_SINGLE ){ labelContinue = sqlite3VdbeMakeLabel(v); } sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -132,36 +132,60 @@ /* ** Invoke the VDBE coverage callback, if that callback is defined. This ** feature is used for test suite validation only and does not appear an ** production builds. ** -** M is an integer, 2 or 3, that indices how many different ways the -** branch can go. It is usually 2. "I" is the direction the branch -** goes. 0 means falls through. 1 means branch is taken. 2 means the -** second alternative branch is taken. +** M is an integer between 2 and 4. 2 indicates a ordinary two-way +** branch (I=0 means fall through and I=1 means taken). 3 indicates +** a 3-way branch where the third way is when one of the operands is +** NULL. 4 indicates the OP_Jump instruction which has three destinations +** depending on whether the first operand is less than, equal to, or greater +** than the second. ** ** iSrcLine is the source code line (from the __LINE__ macro) that -** generated the VDBE instruction. This instrumentation assumes that all -** source code is in a single file (the amalgamation). Special values 1 -** and 2 for the iSrcLine parameter mean that this particular branch is -** always taken or never taken, respectively. +** generated the VDBE instruction combined with flag bits. The source +** code line number is in the lower 24 bits of iSrcLine and the upper +** 8 bytes are flags. The lower three bits of the flags indicate +** values for I that should never occur. For example, if the branch is +** always taken, the flags should be 0x05 since the fall-through and +** alternate branch are never taken. If a branch is never taken then +** flags should be 0x06 since only the fall-through approach is allowed. +** +** Bit 0x04 of the flags indicates an OP_Jump opcode that is only +** interested in equal or not-equal. In other words, I==0 and I==2 +** should be treated the same. +** +** Since only a line number is retained, not the filename, this macro +** only works for amalgamation builds. But that is ok, since these macros +** should be no-ops except for special builds used to measure test coverage. */ #if !defined(SQLITE_VDBE_COVERAGE) # define VdbeBranchTaken(I,M) #else # define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M) - static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){ - if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){ - M = iSrcLine; - /* Assert the truth of VdbeCoverageAlwaysTaken() and - ** VdbeCoverageNeverTaken() */ - assert( (M & I)==I ); - }else{ - if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ - sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, - iSrcLine,I,M); - } + static void vdbeTakeBranch(u32 iSrcLine, u8 I, u8 M){ + u8 mNever; + assert( I<=2 ); /* 0: fall through, 1: taken, 2: alternate taken */ + assert( M<=4 ); /* 2: two-way branch, 3: three-way branch, 4: OP_Jump */ + assert( I> 24; + assert( (I & mNever)==0 ); + if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ + I |= mNever; + if( M==2 ) I |= 0x04; + if( M==4 ){ + I |= 0x08; + if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/ + } + sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, + iSrcLine&0xffffff, I, M); } #endif /* ** Convert the given register into a string if it isn't one @@ -2160,15 +2184,15 @@ ** in the most recent OP_Compare instruction the P1 vector was less than ** equal to, or greater than the P2 vector, respectively. */ case OP_Jump: { /* jump */ if( iCompare<0 ){ - VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1]; + VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; }else if( iCompare==0 ){ - VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1]; + VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1]; }else{ - VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1]; + VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1]; } break; } /* Opcode: And P1 P2 P3 * * Index: src/vdbe.h ================================================================== --- src/vdbe.h +++ src/vdbe.h @@ -71,11 +71,12 @@ #ifdef VDBE_PROFILE u32 cnt; /* Number of times this instruction was executed */ u64 cycles; /* Total time spent executing this instruction */ #endif #ifdef SQLITE_VDBE_COVERAGE - int iSrcLine; /* Source-code line that generated this opcode */ + u32 iSrcLine; /* Source-code line that generated this opcode + ** with flags in the upper 8 bits */ #endif }; typedef struct VdbeOp VdbeOp; @@ -315,27 +316,56 @@ ** ** VdbeCoverageAlwaysTaken(v) // Previous branch is always taken ** ** VdbeCoverageNeverTaken(v) // Previous branch is never taken ** +** VdbeCoverageNeverNull(v) // Previous three-way branch is only +** // taken on the first two ways. The +** // NULL option is not possible +** +** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested +** // in distingishing equal and not-equal. +** ** Every VDBE branch operation must be tagged with one of the macros above. ** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and ** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch() ** routine in vdbe.c, alerting the developer to the missed tag. +** +** During testing, the test application will invoke +** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback +** routine that is invoked as each bytecode branch is taken. The callback +** contains the sqlite3.c source line number ov the VdbeCoverage macro and +** flags to indicate whether or not the branch was taken. The test application +** is responsible for keeping track of this and reporting byte-code branches +** that are never taken. +** +** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the +** vdbe.c source file for additional information. */ #ifdef SQLITE_VDBE_COVERAGE void sqlite3VdbeSetLineNumber(Vdbe*,int); # define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__) # define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__) -# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2); -# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1); +# define VdbeCoverageAlwaysTaken(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000); +# define VdbeCoverageNeverTaken(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000); +# define VdbeCoverageNeverNull(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000); +# define VdbeCoverageNeverNullIf(v,x) \ + if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000); +# define VdbeCoverageEqNe(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000); # define VDBE_OFFSET_LINENO(x) (__LINE__+x) #else # define VdbeCoverage(v) # define VdbeCoverageIf(v,x) # define VdbeCoverageAlwaysTaken(v) # define VdbeCoverageNeverTaken(v) +# define VdbeCoverageNeverNull(v) +# define VdbeCoverageNeverNullIf(v,x) +# define VdbeCoverageEqNe(v) # define VDBE_OFFSET_LINENO(x) 0 #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -808,11 +808,11 @@ int regYield = pTabItem->regReturn; addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } if( pPartial ){ iContinue = sqlite3VdbeMakeLabel(v); @@ -2670,10 +2670,11 @@ ** more expensive. */ assert( 42==sqlite3LogEst(18) ); if( saved_nEq==saved_nSkip && saved_nEq+1nKeyCol && pProbe->noSkipScan==0 + && OptimizationEnabled(db, SQLITE_SkipScan) && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ LogEst nIter; pNew->u.btree.nEq++; Index: src/wherecode.c ================================================================== --- src/wherecode.c +++ src/wherecode.c @@ -148,11 +148,11 @@ || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ - sqlite3_str_appendf(&str, " SUBQUERY 0x%p", pItem->pSelect); + sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId); }else{ sqlite3_str_appendf(&str, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ @@ -1240,11 +1240,11 @@ if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); pLevel->op = OP_Goto; }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ Index: src/window.c ================================================================== --- src/window.c +++ src/window.c @@ -587,11 +587,13 @@ ** selectWindowRewriteExprCb() by selectWindowRewriteEList(). */ typedef struct WindowRewrite WindowRewrite; struct WindowRewrite { Window *pWin; + SrcList *pSrc; ExprList *pSub; + Select *pSubSelect; /* Current sub-select, if any */ }; /* ** Callback function used by selectWindowRewriteEList(). If necessary, ** this function appends to the output expression-list and updates @@ -598,10 +600,28 @@ ** expression (*ppExpr) in place. */ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ struct WindowRewrite *p = pWalker->u.pRewrite; Parse *pParse = pWalker->pParse; + + /* If this function is being called from within a scalar sub-select + ** that used by the SELECT statement being processed, only process + ** TK_COLUMN expressions that refer to it (the outer SELECT). Do + ** not process aggregates or window functions at all, as they belong + ** to the scalar sub-select. */ + if( p->pSubSelect ){ + if( pExpr->op!=TK_COLUMN ){ + return WRC_Continue; + }else{ + int nSrc = p->pSrc->nSrc; + int i; + for(i=0; iiTable==p->pSrc->a[i].iCursor ) break; + } + if( i==nSrc ) return WRC_Continue; + } + } switch( pExpr->op ){ case TK_FUNCTION: if( pExpr->pWin==0 ){ @@ -641,12 +661,19 @@ } return WRC_Continue; } static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){ - UNUSED_PARAMETER(pWalker); - UNUSED_PARAMETER(pSelect); + struct WindowRewrite *p = pWalker->u.pRewrite; + Select *pSave = p->pSubSelect; + if( pSave==pSelect ){ + return WRC_Continue; + }else{ + p->pSubSelect = pSelect; + sqlite3WalkSelect(pWalker, pSelect); + p->pSubSelect = pSave; + } return WRC_Prune; } /* @@ -653,20 +680,21 @@ ** Iterate through each expression in expression-list pEList. For each: ** ** * TK_COLUMN, ** * aggregate function, or ** * window function with a Window object that is not a member of the -** linked list passed as the second argument (pWin) +** Window list passed as the second argument (pWin). ** ** Append the node to output expression-list (*ppSub). And replace it ** with a TK_COLUMN that reads the (N-1)th element of table ** pWin->iEphCsr, where N is the number of elements in (*ppSub) after ** appending the new one. */ static void selectWindowRewriteEList( Parse *pParse, Window *pWin, + SrcList *pSrc, ExprList *pEList, /* Rewrite expressions in this list */ ExprList **ppSub /* IN/OUT: Sub-select expression-list */ ){ Walker sWalker; WindowRewrite sRewrite; @@ -674,10 +702,11 @@ memset(&sWalker, 0, sizeof(Walker)); memset(&sRewrite, 0, sizeof(WindowRewrite)); sRewrite.pSub = *ppSub; sRewrite.pWin = pWin; + sRewrite.pSrc = pSrc; sWalker.pParse = pParse; sWalker.xExprCallback = selectWindowRewriteExprCb; sWalker.xSelectCallback = selectWindowRewriteSelectCb; sWalker.u.pRewrite = &sRewrite; @@ -751,12 +780,12 @@ /* Assign a cursor number for the ephemeral table used to buffer rows. ** The OpenEphemeral instruction is coded later, after it is known how ** many columns the table will have. */ pMWin->iEphCsr = pParse->nTab++; - selectWindowRewriteEList(pParse, pMWin, p->pEList, &pSublist); - selectWindowRewriteEList(pParse, pMWin, p->pOrderBy, &pSublist); + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist); + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist); pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); /* Append the PARTITION BY and ORDER BY expressions to the to the ** sub-select expression list. They are required to figure out where ** boundaries for partitions and sets of peer rows lie. */ @@ -1036,13 +1065,13 @@ sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverageIf(v, eCond==0); VdbeCoverageIf(v, eCond==1); VdbeCoverageIf(v, eCond==2); sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); - VdbeCoverageIf(v, eCond==0); - VdbeCoverageIf(v, eCond==1); - VdbeCoverageIf(v, eCond==2); + VdbeCoverageNeverNullIf(v, eCond==0); + VdbeCoverageNeverNullIf(v, eCond==1); + VdbeCoverageNeverNullIf(v, eCond==2); sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort); sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC); sqlite3ReleaseTempReg(pParse, regZero); } @@ -1118,11 +1147,11 @@ sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp); sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2); sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2); }else{ sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1); - VdbeCoverage(v); + VdbeCoverageNeverTaken(v); sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ @@ -1230,12 +1259,12 @@ int regRowid = regRecord+1; *pRegSize = regRowid; pParse->nMem += nSub + 2; - /* Martial the row returned by the sub-select into an array of - ** registers. */ + /* Load the column values for the row returned by the sub-select + ** into an array of registers starting at reg. */ for(k=0; kregPart,nPart); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); - VdbeCoverage(v); + VdbeCoverageEqNe(v); sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart); VdbeComment((v, "call flush_partition")); } @@ -1306,13 +1335,13 @@ }else{ sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); } sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); - VdbeCoverage(v); + VdbeCoverageNeverNull(v); + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); + VdbeCoverageNeverTaken(v); sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); sqlite3VdbeResolveLabel(v, lbl); sqlite3ReleaseTempReg(pParse, tmpReg); } else if( pFunc->zName==leadName || pFunc->zName==lagName ){ @@ -1619,20 +1648,20 @@ */ if( pMWin->pEnd && pMWin->eStart==TK_FOLLOWING ){ assert( pMWin->pStart!=0 ); assert( pMWin->eEnd==TK_FOLLOWING ); sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd); - VdbeCoverage(v); + VdbeCoverageNeverNull(v); sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart); sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd); } if( pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){ assert( pMWin->pEnd!=0 ); assert( pMWin->eStart==TK_PRECEDING ); sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd); - VdbeCoverage(v); + VdbeCoverageNeverNull(v); sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart); sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd); } /* Initialize the accumulator register for each window function to NULL */ @@ -1700,11 +1729,11 @@ sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Goto, 0, lblSkipInverse); }else{ sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1); - VdbeCoverage(v); + VdbeCoverageAlwaysTaken(v); } windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize); sqlite3VdbeResolveLabel(v, lblSkipInverse); } if( pMWin->eEnd==TK_FOLLOWING ){ @@ -2003,12 +2032,12 @@ pOrderBy = 0; } pParse->nMem += nSub + 2; - /* Martial the row returned by the sub-select into an array of - ** registers. */ + /* Load the individual column values of the row returned by + ** the sub-select into an array of registers. */ for(k=0; knBufferCol; KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); - VdbeCoverage(v); + VdbeCoverageEqNe(v); windowAggFinal(pParse, pMWin, 1); if( pOrderBy ){ addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); } } @@ -2181,10 +2210,11 @@ ** return rows. */ if( pMWin->eType==TK_ROWS && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy) ){ + VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()")); windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub); }else{ Window *pWin; int bCache = 0; /* True to use CacheStep() */ @@ -2205,13 +2235,15 @@ } } /* Otherwise, call windowCodeDefaultStep(). */ if( bCache ){ + VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()")); windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub); }else{ + VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()")); windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub); } } } #endif /* SQLITE_OMIT_WINDOWFUNC */ Index: test/pg_common.tcl ================================================================== --- test/pg_common.tcl +++ test/pg_common.tcl @@ -69,26 +69,35 @@ # Same as [execsql_test], except coerce all results to floating point values # with two decimal points. # proc execsql_float_test {tn sql} { - set F "%.2f" + set F "%.4f" + set T 0.0001 set res [execsql $sql] set res2 [list] foreach r $res { if {$r != ""} { set r [format $F $r] } lappend res2 $r } - puts $::fd "do_test $tn {" - puts $::fd " set myres {}" - puts $::fd " foreach r \[db eval {[string trim $sql]}\] {" - puts $::fd " lappend myres \[format $F \[set r\]\]" - puts $::fd " }" - puts $::fd " set myres" - puts $::fd "} {$res2}" - puts $::fd "" + set sql [string trim $sql] +puts $::fd [subst -nocommands { +do_test $tn { + set myres {} + foreach r [db eval {$sql}] { + lappend myres [format $F [set r]] + } + set res2 {$res2} + foreach r [set myres] r2 [set res2] { + if {[set r]<([set r2]-$T) || [set r]>([set r2]+$T)} { + error "list element [set i] does not match: got=[set r] expected=[set r2]" + } + } + set {} {} +} {} +}] } proc start_test {name date} { set dir [file dirname $::argv0] set output [file join $dir $name.test] Index: test/resetdb.test ================================================================== --- test/resetdb.test +++ test/resetdb.test @@ -173,8 +173,39 @@ PRAGMA journal_mode; PRAGMA quick_check; } db2 } {0 {1 8192 wal ok}} db2 close + +#------------------------------------------------------------------------- +reset_db +sqlite3 db2 test.db +do_execsql_test 600 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(1), (2), (3), (4); +} {wal} + +do_execsql_test -db db2 610 { + SELECT * FROM t1 +} {1 2 3 4} + +do_test 620 { + set res [list] + db2 eval {SELECT a FROM t1} { + lappend res $a + if {$a==3} { + sqlite3_db_config db RESET_DB 1 + db eval VACUUM + sqlite3_db_config db RESET_DB 0 + } + } + + set res +} {1 2 3 4} + +do_execsql_test -db db2 630 { + SELECT * FROM sqlite_master +} {} finish_test Index: test/selectD.test ================================================================== --- test/selectD.test +++ test/selectD.test @@ -167,8 +167,8 @@ LEFT JOIN (SELECT count(*) AS cnt, x1.d FROM (t42 INNER JOIN t43 ON d=g) AS x1 WHERE x1.d>5 GROUP BY x1.d) AS x2 ON t41.b=x2.d; -} {/*SEARCH SUBQUERY 0x* AS x2 USING AUTOMATIC*/} +} {/*SEARCH SUBQUERY * AS x2 USING AUTOMATIC*/} finish_test Index: test/skipscan1.test ================================================================== --- test/skipscan1.test +++ test/skipscan1.test @@ -335,6 +335,14 @@ ANALYZE sqlite_master; EXPLAIN QUERY PLAN SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5); } {/USING INDEX t9a_ab .ANY.a. AND b=./} + +optimization_control db skip-scan 0 +do_execsql_test skipscan1-9.3 { + EXPLAIN QUERY PLAN + SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5); +} {/{SCAN TABLE t9a}/} +optimization_control db skip-scan 1 + finish_test Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -972,11 +972,13 @@ set dx($id) $detail lappend cx($parent) $id } set a "\n QUERY PLAN\n" append a [append_graph " " dx cx 0] - return [regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx}] + regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx} a + regsub -all {(MATERIALIZE|CO-ROUTINE|SUBQUERY) \d+\y} $a {\1 xxxxxx} a + return $a } # Helper routine for [query_plan_graph SQL]: # # Output rows of the graph that are children of $level. Index: test/upsert1.test ================================================================== --- test/upsert1.test +++ test/upsert1.test @@ -109,7 +109,23 @@ CREATE TABLE t1(x INTEGER PRIMARY KEY, y INT UNIQUE); INSERT INTO t1(x,y) SELECT 1,2 WHERE true ON CONFLICT(x) DO UPDATE SET y=max(t1.y,excluded.y) AND true; SELECT * FROM t1; } {1 2} + +# 2018-07-11 +# Ticket https://sqlite.org/src/tktview/79cad5e4b2e219dd197242e9e5f4 +# UPSERT leads to a corrupt index. +# +do_execsql_test upsert1-600 { + DROP TABLE t1; + CREATE TABLE t1(b UNIQUE, a INT PRIMARY KEY) WITHOUT ROWID; + INSERT OR IGNORE INTO t1(a) VALUES('1') ON CONFLICT(a) DO NOTHING; + PRAGMA integrity_check; +} {ok} +do_execsql_test upsert1-610 { + DELETE FROM t1; + INSERT OR IGNORE INTO t1(a) VALUES('1'),(1) ON CONFLICT(a) DO NOTHING; + PRAGMA integrity_check; +} {ok} finish_test Index: test/window3.test ================================================================== --- test/window3.test +++ test/window3.test cannot compute difference between binary files Index: test/window6.test ================================================================== --- test/window6.test +++ test/window6.test @@ -308,6 +308,32 @@ WITH t1(a,b) AS ( VALUES(1, 2), (2, 3), (3, 4) ) $stmt " $res } + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 11.0 { + CREATE TABLE t1(a INT); + INSERT INTO t1 VALUES(10),(15),(20),(20),(25),(30),(30),(50); + CREATE TABLE t3(x INT, y VARCHAR); + INSERT INTO t3(x,y) VALUES(10,'ten'),('15','fifteen'),(30,'thirty'); +} + +do_execsql_test 11.1 { + SELECT a, (SELECT y FROM t3 WHERE x=a) FROM t1 ORDER BY a; +} { + 10 ten 15 fifteen 20 {} 20 {} 25 {} 30 thirty 30 thirty 50 {} +} + +do_execsql_test 11.2 { + SELECT a, (SELECT y FROM t3 WHERE x=a), sum(a) OVER (ORDER BY a) + FROM t1 ORDER BY a; +} { + 10 ten 10 15 fifteen 25 20 {} 65 20 {} 65 + 25 {} 90 30 thirty 150 30 thirty 150 50 {} 200 +} + finish_test +