diff options
author | mistachkin <mistachkin@noemail.net> | 2013-09-24 19:07:48 +0000 |
---|---|---|
committer | mistachkin <mistachkin@noemail.net> | 2013-09-24 19:07:48 +0000 |
commit | bbff2180161a86873249d332dc72a8aaf4e22f89 (patch) | |
tree | 09b35ca0c564eacc3448303adcc127f24fb1ba2e /src | |
parent | 9a5cbbc4a53b4ab409a56352cad15d0e86726a3d (diff) | |
parent | 6284d0216044049566cd7911dd6e1f070b2ba257 (diff) | |
download | sqlite-bbff2180161a86873249d332dc72a8aaf4e22f89.tar.gz sqlite-bbff2180161a86873249d332dc72a8aaf4e22f89.zip |
Merge updates from trunk.
FossilOrigin-Name: 435ce3b3fc0cffb4d7e6f2694c3100066e19f9ed
Diffstat (limited to 'src')
-rw-r--r-- | src/analyze.c | 2 | ||||
-rw-r--r-- | src/attach.c | 2 | ||||
-rw-r--r-- | src/date.c | 8 | ||||
-rw-r--r-- | src/expr.c | 118 | ||||
-rw-r--r-- | src/func.c | 34 | ||||
-rw-r--r-- | src/malloc.c | 1 | ||||
-rw-r--r-- | src/os_win.c | 131 | ||||
-rw-r--r-- | src/parse.y | 5 | ||||
-rw-r--r-- | src/pragma.c | 654 | ||||
-rw-r--r-- | src/resolve.c | 35 | ||||
-rw-r--r-- | src/select.c | 8 | ||||
-rw-r--r-- | src/sqlite3.rc | 22 | ||||
-rw-r--r-- | src/sqliteInt.h | 79 | ||||
-rw-r--r-- | src/util.c | 3 | ||||
-rw-r--r-- | src/vdbe.c | 1 | ||||
-rw-r--r-- | src/vdbeInt.h | 1 | ||||
-rw-r--r-- | src/vdbeapi.c | 14 | ||||
-rw-r--r-- | src/vdbeaux.c | 1 | ||||
-rw-r--r-- | src/walker.c | 2 | ||||
-rw-r--r-- | src/where.c | 146 |
20 files changed, 826 insertions, 441 deletions
diff --git a/src/analyze.c b/src/analyze.c index 42c81fd65..474d80d1b 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -347,7 +347,7 @@ static void statInit( p->mxSample = mxSample; p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[1])/(mxSample/3+1) + 1); p->current.anLt = &p->current.anEq[nColUp]; - sqlite3_randomness(sizeof(p->iPrn), &p->iPrn); + p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[1])*0xd0944565; /* Set up the Stat4Accum.a[] and aBest[] arrays */ p->a = (struct Stat4Sample*)&p->current.anLt[nColUp]; diff --git a/src/attach.c b/src/attach.c index 6d965ace6..805305dab 100644 --- a/src/attach.c +++ b/src/attach.c @@ -509,7 +509,7 @@ int sqlite3FixExpr( Expr *pExpr /* The expression to be fixed to one database */ ){ while( pExpr ){ - if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ) break; + if( ExprHasProperty(pExpr, EP_TokenOnly) ) break; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1; }else{ diff --git a/src/date.c b/src/date.c index 758dd7c89..5fe3f6786 100644 --- a/src/date.c +++ b/src/date.c @@ -294,8 +294,8 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){ ** Return the number of errors. */ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ - sqlite3 *db = sqlite3_context_db_handle(context); - if( sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD)==SQLITE_OK ){ + p->iJD = sqlite3StmtCurrentTime(context); + if( p->iJD>0 ){ p->validJD = 1; return 0; }else{ @@ -1078,8 +1078,8 @@ static void currentTimeFunc( UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); - db = sqlite3_context_db_handle(context); - if( sqlite3OsCurrentTimeInt64(db->pVfs, &iT) ) return; + iT = sqlite3StmtCurrentTime(context); + if( iT<=0 ) return; t = iT/1000 - 10000*(sqlite3_int64)21086676; #ifdef HAVE_GMTIME_R pTm = gmtime_r(&t, &sNow); diff --git a/src/expr.c b/src/expr.c index 6587ee1f7..b8b0eb731 100644 --- a/src/expr.c +++ b/src/expr.c @@ -70,7 +70,7 @@ Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1); if( pNew ){ pNew->pLeft = pExpr; - pNew->flags |= EP_Collate; + pNew->flags |= EP_Collate|EP_Skip; pExpr = pNew; } } @@ -85,13 +85,21 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ } /* -** Skip over any TK_COLLATE and/or TK_AS operators at the root of -** an expression. +** Skip over any TK_COLLATE or TK_AS operators and any unlikely() +** or likelihood() function at the root of an expression. */ Expr *sqlite3ExprSkipCollate(Expr *pExpr){ - while( pExpr && (pExpr->op==TK_COLLATE || pExpr->op==TK_AS) ){ - pExpr = pExpr->pLeft; - } + while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ + if( ExprHasProperty(pExpr, EP_Unlikely) ){ + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->x.pList->nExpr>0 ); + assert( pExpr->op==TK_FUNCTION ); + pExpr = pExpr->x.pList->a[0].pExpr; + }else{ + assert( pExpr->op==TK_COLLATE || pExpr->op==TK_AS ); + pExpr = pExpr->pLeft; + } + } return pExpr; } @@ -596,7 +604,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ const char *z; if( pExpr==0 ) return; - assert( !ExprHasAnyProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) ); + assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) ); z = pExpr->u.zToken; assert( z!=0 ); assert( z[0]!=0 ); @@ -666,12 +674,12 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p==0 ) return; /* Sanity check: Assert that the IntValue is non-negative if it exists */ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); - if( !ExprHasAnyProperty(p, EP_TokenOnly) ){ + if( !ExprHasProperty(p, EP_TokenOnly) ){ + /* The Expr.x union is never used at the same time as Expr.pRight */ + assert( p->x.pList==0 || p->pRight==0 ); sqlite3ExprDelete(db, p->pLeft); sqlite3ExprDelete(db, p->pRight); - if( !ExprHasProperty(p, EP_Reduced) && (p->flags2 & EP2_MallocedToken)!=0 ){ - sqlite3DbFree(db, p->u.zToken); - } + if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); if( ExprHasProperty(p, EP_xIsSelect) ){ sqlite3SelectDelete(db, p->x.pSelect); }else{ @@ -731,16 +739,19 @@ static int exprStructSize(Expr *p){ static int dupedExprStructSize(Expr *p, int flags){ int nSize; assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ + assert( EXPR_FULLSIZE<=0xfff ); + assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); if( 0==(flags&EXPRDUP_REDUCE) ){ nSize = EXPR_FULLSIZE; }else{ - assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) ); + assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); assert( !ExprHasProperty(p, EP_FromJoin) ); - assert( (p->flags2 & EP2_MallocedToken)==0 ); - assert( (p->flags2 & EP2_Irreducible)==0 ); - if( p->pLeft || p->pRight || p->x.pList ){ + assert( !ExprHasProperty(p, EP_MemToken) ); + assert( !ExprHasProperty(p, EP_NoReduce) ); + if( p->pLeft || p->x.pList ){ nSize = EXPR_REDUCEDSIZE | EP_Reduced; }else{ + assert( p->pRight==0 ); nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly; } } @@ -834,7 +845,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){ } /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */ - pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static); + pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); pNew->flags |= staticFlag; @@ -854,7 +865,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){ } /* Fill in pNew->pLeft and pNew->pRight. */ - if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly) ){ + if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){ zAlloc += dupedExprNodeSize(p, flags); if( ExprHasProperty(pNew, EP_Reduced) ){ pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc); @@ -864,8 +875,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){ *pzBuffer = zAlloc; } }else{ - pNew->flags2 = 0; - if( !ExprHasAnyProperty(p, EP_TokenOnly) ){ + if( !ExprHasProperty(p, EP_TokenOnly) ){ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); pNew->pRight = sqlite3ExprDup(db, p->pRight, 0); } @@ -1175,7 +1185,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ /* If pWalker->u.i is 3 then any term of the expression that comes from ** the ON or USING clauses of a join disqualifies the expression ** from being considered constant. */ - if( pWalker->u.i==3 && ExprHasAnyProperty(pExpr, EP_FromJoin) ){ + if( pWalker->u.i==3 && ExprHasProperty(pExpr, EP_FromJoin) ){ pWalker->u.i = 0; return WRC_Abort; } @@ -1606,7 +1616,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ }else{ testcase( pParse->nQueryLoop>0 ); pParse->nQueryLoop = 0; - if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){ + if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ eType = IN_INDEX_ROWID; } } @@ -1675,7 +1685,7 @@ int sqlite3CodeSubselect( ** If all of the above are false, then we can run this code just once ** save the results, and reuse the same result on subsequent invocations. */ - if( !ExprHasAnyProperty(pExpr, EP_VarSelect) ){ + if( !ExprHasProperty(pExpr, EP_VarSelect) ){ testAddr = sqlite3CodeOnce(pParse); } @@ -1844,7 +1854,7 @@ int sqlite3CodeSubselect( return 0; } rReg = dest.iSDParm; - ExprSetIrreducible(pExpr); + ExprSetVVAProperty(pExpr, EP_NoReduce); break; } } @@ -2317,6 +2327,16 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ #endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */ /* +** Convert an expression node to a TK_REGISTER +*/ +static void exprToRegister(Expr *p, int iReg){ + p->op2 = p->op; + p->op = TK_REGISTER; + p->iTable = iReg; + ExprClearProperty(p, EP_Skip); +} + +/* ** Generate code into the current Vdbe to evaluate the given ** expression. Attempt to store the results in register "target". ** Return the register where results are stored. @@ -2615,7 +2635,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); testcase( op==TK_CONST_FUNC ); testcase( op==TK_FUNCTION ); - if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){ + if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; }else{ pFarg = pExpr->x.pList; @@ -2649,6 +2669,14 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ break; } + /* The UNLIKELY() function is a no-op. The result is the value + ** of the first argument. + */ + if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ + assert( nFarg>=1 ); + sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); + break; + } if( pFarg ){ r1 = sqlite3GetTempRange(pParse, nFarg); @@ -2846,9 +2874,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ ** WHEN x=eN THEN rN ELSE y END ** ** X (if it exists) is in pExpr->pLeft. - ** Y is in pExpr->pRight. The Y is also optional. If there is no - ** ELSE clause and no other term matches, then the result of the - ** exprssion is NULL. + ** Y is in the last element of pExpr->x.pList if pExpr->x.pList->nExpr is + ** odd. The Y is also optional. If the number of elements in x.pList + ** is even, then Y is omitted and the "otherwise" result is NULL. ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1]. ** ** The result of the expression is the Ri for the first matching Ei, @@ -2869,7 +2897,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; ) assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); - assert((pExpr->x.pList->nExpr % 2) == 0); assert(pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; @@ -2879,9 +2906,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ cacheX = *pX; testcase( pX->op==TK_COLUMN ); testcase( pX->op==TK_REGISTER ); - cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, ®Free1); + exprToRegister(&cacheX, sqlite3ExprCodeTemp(pParse, pX, ®Free1)); testcase( regFree1==0 ); - cacheX.op = TK_REGISTER; opCompare.op = TK_EQ; opCompare.pLeft = &cacheX; pTest = &opCompare; @@ -2891,7 +2917,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ ** purposes and possibly overwritten. */ regFree1 = 0; } - for(i=0; i<nExpr; i=i+2){ + for(i=0; i<nExpr-1; i=i+2){ sqlite3ExprCachePush(pParse); if( pX ){ assert( pTest!=0 ); @@ -2909,9 +2935,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ sqlite3ExprCachePop(pParse, 1); sqlite3VdbeResolveLabel(v, nextCase); } - if( pExpr->pRight ){ + if( (nExpr&1)!=0 ){ sqlite3ExprCachePush(pParse); - sqlite3ExprCode(pParse, pExpr->pRight, target); + sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); sqlite3ExprCachePop(pParse, 1); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); @@ -3023,9 +3049,7 @@ int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ int iMem; iMem = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem); - pExpr->iTable = iMem; - pExpr->op2 = pExpr->op; - pExpr->op = TK_REGISTER; + exprToRegister(pExpr, iMem); } return inReg; } @@ -3155,7 +3179,7 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case TK_CONST_FUNC: case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ - if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){ + if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; }else{ pFarg = pExpr->x.pList; @@ -3404,9 +3428,7 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){ ** but suboptimal, so we want to know about the situation to fix it. ** Hence the following assert: */ assert( r2==r1 ); - pExpr->op2 = pExpr->op; - pExpr->op = TK_REGISTER; - pExpr->iTable = r2; + exprToRegister(pExpr, r2); return WRC_Prune; } return WRC_Continue; @@ -3504,9 +3526,7 @@ static void exprCodeBetween( compRight.op = TK_LE; compRight.pLeft = &exprX; compRight.pRight = pExpr->x.pList->a[1].pExpr; - exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1); - exprX.op2 = exprX.op; - exprX.op = TK_REGISTER; + exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, ®Free1)); if( jumpIfTrue ){ sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull); }else{ @@ -3821,8 +3841,8 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ if( pA==0||pB==0 ){ return pB==pA ? 0 : 2; } - assert( !ExprHasAnyProperty(pA, EP_TokenOnly|EP_Reduced) ); - assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) ); + assert( !ExprHasProperty(pA, EP_TokenOnly|EP_Reduced) ); + assert( !ExprHasProperty(pB, EP_TokenOnly|EP_Reduced) ); if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){ return 2; } @@ -4036,7 +4056,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ struct SrcList_item *pItem = pSrcList->a; for(i=0; i<pSrcList->nSrc; i++, pItem++){ struct AggInfo_col *pCol; - assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) ); + assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); if( pExpr->iTable==pItem->iCursor ){ /* If we reach this point, it means that pExpr refers to a table ** that is in the FROM clause of the aggregate query. @@ -4085,7 +4105,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ ** Convert the pExpr to be a TK_AGG_COLUMN referring to that ** pAggInfo->aCol[] entry. */ - ExprSetIrreducible(pExpr); + ExprSetVVAProperty(pExpr, EP_NoReduce); pExpr->pAggInfo = pAggInfo; pExpr->op = TK_AGG_COLUMN; pExpr->iAgg = (i16)k; @@ -4131,8 +4151,8 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ } /* Make pExpr point to the appropriate pAggInfo->aFunc[] entry */ - assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) ); - ExprSetIrreducible(pExpr); + assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); + ExprSetVVAProperty(pExpr, EP_NoReduce); pExpr->iAgg = (i16)i; pExpr->pAggInfo = pAggInfo; return WRC_Prune; diff --git a/src/func.c b/src/func.c index 33eba21b7..73b6c3bb2 100644 --- a/src/func.c +++ b/src/func.c @@ -418,14 +418,14 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ } /* -** The COALESCE() and IFNULL() functions are implemented as VDBE code so -** that unused argument values do not have to be computed. However, we -** still need some kind of function implementation for this routines in -** the function table. That function implementation will never be called -** so it doesn't matter what the implementation is. We might as well use -** the "version()" function as a substitute. +** Some functions like COALESCE() and IFNULL() and UNLIKELY() are implemented +** as VDBE code so that unused argument values do not have to be computed. +** However, we still need some kind of function implementation for this +** routines in the function table. The noopFunc macro provides this. +** noopFunc will never be called so it doesn't matter what the implementation +** is. We might as well use the "version()" function as a substitute. */ -#define ifnullFunc versionFunc /* Substitute function - never called */ +#define noopFunc versionFunc /* Substitute function - never called */ /* ** Implementation of random(). Return a random integer. @@ -544,9 +544,9 @@ struct compareInfo { */ #if defined(SQLITE_EBCDIC) # define sqlite3Utf8Read(A) (*((*A)++)) -# define GlogUpperToLower(A) A = sqlite3UpperToLower[A] +# define GlobUpperToLower(A) A = sqlite3UpperToLower[A] #else -# define GlogUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } +# define GlobUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } #endif static const struct compareInfo globInfo = { '*', '?', '[', 0 }; @@ -625,11 +625,11 @@ static int patternCompare( } while( (c2 = sqlite3Utf8Read(&zString))!=0 ){ if( noCase ){ - GlogUpperToLower(c2); - GlogUpperToLower(c); + GlobUpperToLower(c2); + GlobUpperToLower(c); while( c2 != 0 && c2 != c ){ c2 = sqlite3Utf8Read(&zString); - GlogUpperToLower(c2); + GlobUpperToLower(c2); } }else{ while( c2 != 0 && c2 != c ){ @@ -681,8 +681,8 @@ static int patternCompare( }else{ c2 = sqlite3Utf8Read(&zString); if( noCase ){ - GlogUpperToLower(c); - GlogUpperToLower(c2); + GlobUpperToLower(c); + GlobUpperToLower(c2); } if( c!=c2 ){ return 0; @@ -1798,9 +1798,11 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION(lower, 1, 0, 0, lowerFunc ), FUNCTION(coalesce, 1, 0, 0, 0 ), FUNCTION(coalesce, 0, 0, 0, 0 ), - FUNCTION2(coalesce, -1, 0, 0, ifnullFunc, SQLITE_FUNC_COALESCE), + FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), FUNCTION(hex, 1, 0, 0, hexFunc ), - FUNCTION2(ifnull, 2, 0, 0, ifnullFunc, SQLITE_FUNC_COALESCE), + FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), + FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), + FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), FUNCTION(random, 0, 0, 0, randomFunc ), FUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), diff --git a/src/malloc.c b/src/malloc.c index 35a44e5f6..799f0485d 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -484,6 +484,7 @@ void sqlite3_free(void *p){ */ void sqlite3DbFree(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); + if( p==0 ) return; if( db ){ if( db->pnBytesFreed ){ *db->pnBytesFreed += sqlite3DbMallocSize(db, p); diff --git a/src/os_win.c b/src/os_win.c index 72d6e8ba5..1e9ee0238 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -109,6 +109,14 @@ #endif /* +** This macro is used when a local variable is set to a value that is +** [sometimes] not used by the code (e.g. via conditional compilation). +*/ +#ifndef UNUSED_VARIABLE_VALUE +# define UNUSED_VARIABLE_VALUE(x) (void)(x) +#endif + +/* ** Returns the string that should be used as the directory separator. */ #ifndef winGetDirDep @@ -358,7 +366,8 @@ const sqlite3_mem_methods *sqlite3MemGetWin32(void); */ #ifdef SQLITE_TEST int sqlite3_os_type = 0; -#else +#elif !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ + defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_HAS_WIDE) static int sqlite3_os_type = 0; #endif @@ -673,10 +682,19 @@ static struct win_syscall { #define osGetVersionExA ((BOOL(WINAPI*)( \ LPOSVERSIONINFOA))aSyscall[34].pCurrent) +#if defined(SQLITE_WIN32_HAS_WIDE) + { "GetVersionExW", (SYSCALL)GetVersionExW, 0 }, +#else + { "GetVersionExW", (SYSCALL)0, 0 }, +#endif + +#define osGetVersionExW ((BOOL(WINAPI*)( \ + LPOSVERSIONINFOW))aSyscall[35].pCurrent) + { "HeapAlloc", (SYSCALL)HeapAlloc, 0 }, #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ - SIZE_T))aSyscall[35].pCurrent) + SIZE_T))aSyscall[36].pCurrent) #if !SQLITE_OS_WINRT { "HeapCreate", (SYSCALL)HeapCreate, 0 }, @@ -685,7 +703,7 @@ static struct win_syscall { #endif #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ - SIZE_T))aSyscall[36].pCurrent) + SIZE_T))aSyscall[37].pCurrent) #if !SQLITE_OS_WINRT { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, @@ -693,21 +711,21 @@ static struct win_syscall { { "HeapDestroy", (SYSCALL)0, 0 }, #endif -#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent) +#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent) { "HeapFree", (SYSCALL)HeapFree, 0 }, -#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent) +#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[39].pCurrent) { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 }, #define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \ - SIZE_T))aSyscall[39].pCurrent) + SIZE_T))aSyscall[40].pCurrent) { "HeapSize", (SYSCALL)HeapSize, 0 }, #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ - LPCVOID))aSyscall[40].pCurrent) + LPCVOID))aSyscall[41].pCurrent) #if !SQLITE_OS_WINRT { "HeapValidate", (SYSCALL)HeapValidate, 0 }, @@ -716,7 +734,7 @@ static struct win_syscall { #endif #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ - LPCVOID))aSyscall[41].pCurrent) + LPCVOID))aSyscall[42].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION) { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 }, @@ -724,7 +742,7 @@ static struct win_syscall { { "LoadLibraryA", (SYSCALL)0, 0 }, #endif -#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent) +#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[43].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -733,7 +751,7 @@ static struct win_syscall { { "LoadLibraryW", (SYSCALL)0, 0 }, #endif -#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent) +#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[44].pCurrent) #if !SQLITE_OS_WINRT { "LocalFree", (SYSCALL)LocalFree, 0 }, @@ -741,7 +759,7 @@ static struct win_syscall { { "LocalFree", (SYSCALL)0, 0 }, #endif -#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent) +#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[45].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "LockFile", (SYSCALL)LockFile, 0 }, @@ -751,7 +769,7 @@ static struct win_syscall { #ifndef osLockFile #define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - DWORD))aSyscall[45].pCurrent) + DWORD))aSyscall[46].pCurrent) #endif #if !SQLITE_OS_WINCE @@ -762,7 +780,7 @@ static struct win_syscall { #ifndef osLockFileEx #define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ - LPOVERLAPPED))aSyscall[46].pCurrent) + LPOVERLAPPED))aSyscall[47].pCurrent) #endif #if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)) @@ -772,26 +790,26 @@ static struct win_syscall { #endif #define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - SIZE_T))aSyscall[47].pCurrent) + SIZE_T))aSyscall[48].pCurrent) { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 }, #define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \ - int))aSyscall[48].pCurrent) + int))aSyscall[49].pCurrent) { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 }, #define osQueryPerformanceCounter ((BOOL(WINAPI*)( \ - LARGE_INTEGER*))aSyscall[49].pCurrent) + LARGE_INTEGER*))aSyscall[50].pCurrent) { "ReadFile", (SYSCALL)ReadFile, 0 }, #define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \ - LPOVERLAPPED))aSyscall[50].pCurrent) + LPOVERLAPPED))aSyscall[51].pCurrent) { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 }, -#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent) +#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[52].pCurrent) #if !SQLITE_OS_WINRT { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, @@ -800,7 +818,7 @@ static struct win_syscall { #endif #define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ - DWORD))aSyscall[52].pCurrent) + DWORD))aSyscall[53].pCurrent) #if !SQLITE_OS_WINRT { "Sleep", (SYSCALL)Sleep, 0 }, @@ -808,12 +826,12 @@ static struct win_syscall { { "Sleep", (SYSCALL)0, 0 }, #endif -#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent) +#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[54].pCurrent) { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, #define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \ - LPFILETIME))aSyscall[54].pCurrent) + LPFILETIME))aSyscall[55].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "UnlockFile", (SYSCALL)UnlockFile, 0 }, @@ -823,7 +841,7 @@ static struct win_syscall { #ifndef osUnlockFile #define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - DWORD))aSyscall[55].pCurrent) + DWORD))aSyscall[56].pCurrent) #endif #if !SQLITE_OS_WINCE @@ -833,7 +851,7 @@ static struct win_syscall { #endif #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - LPOVERLAPPED))aSyscall[56].pCurrent) + LPOVERLAPPED))aSyscall[57].pCurrent) #if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, @@ -841,17 +859,17 @@ static struct win_syscall { { "UnmapViewOfFile", (SYSCALL)0, 0 }, #endif -#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent) +#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[58].pCurrent) { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 }, #define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \ - LPCSTR,LPBOOL))aSyscall[58].pCurrent) + LPCSTR,LPBOOL))aSyscall[59].pCurrent) { "WriteFile", (SYSCALL)WriteFile, 0 }, #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ - LPOVERLAPPED))aSyscall[59].pCurrent) + LPOVERLAPPED))aSyscall[60].pCurrent) #if SQLITE_OS_WINRT { "CreateEventExW", (SYSCALL)CreateEventExW, 0 }, @@ -860,7 +878,7 @@ static struct win_syscall { #endif #define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ - DWORD,DWORD))aSyscall[60].pCurrent) + DWORD,DWORD))aSyscall[61].pCurrent) #if !SQLITE_OS_WINRT { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, @@ -869,7 +887,7 @@ static struct win_syscall { #endif #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ - DWORD))aSyscall[61].pCurrent) + DWORD))aSyscall[62].pCurrent) #if SQLITE_OS_WINRT { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, @@ -878,7 +896,7 @@ static struct win_syscall { #endif #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ - BOOL))aSyscall[62].pCurrent) + BOOL))aSyscall[63].pCurrent) #if SQLITE_OS_WINRT { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, @@ -887,7 +905,7 @@ static struct win_syscall { #endif #define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \ - PLARGE_INTEGER,DWORD))aSyscall[63].pCurrent) + PLARGE_INTEGER,DWORD))aSyscall[64].pCurrent) #if SQLITE_OS_WINRT { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 }, @@ -896,7 +914,7 @@ static struct win_syscall { #endif #define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ - FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[64].pCurrent) + FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[65].pCurrent) #if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL) { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, @@ -905,7 +923,7 @@ static struct win_syscall { #endif #define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ - SIZE_T))aSyscall[65].pCurrent) + SIZE_T))aSyscall[66].pCurrent) #if SQLITE_OS_WINRT { "CreateFile2", (SYSCALL)CreateFile2, 0 }, @@ -914,7 +932,7 @@ static struct win_syscall { #endif #define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \ - LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent) + LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[67].pCurrent) #if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION) { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 }, @@ -923,7 +941,7 @@ static struct win_syscall { #endif #define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \ - DWORD))aSyscall[67].pCurrent) + DWORD))aSyscall[68].pCurrent) #if SQLITE_OS_WINRT { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, @@ -931,7 +949,7 @@ static struct win_syscall { { "GetTickCount64", (SYSCALL)0, 0 }, #endif -#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[68].pCurrent) +#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[69].pCurrent) #if SQLITE_OS_WINRT { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 }, @@ -940,7 +958,7 @@ static struct win_syscall { #endif #define osGetNativeSystemInfo ((VOID(WINAPI*)( \ - LPSYSTEM_INFO))aSyscall[69].pCurrent) + LPSYSTEM_INFO))aSyscall[70].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, @@ -948,7 +966,7 @@ static struct win_syscall { { "OutputDebugStringA", (SYSCALL)0, 0 }, #endif -#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[70].pCurrent) +#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[71].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 }, @@ -956,11 +974,11 @@ static struct win_syscall { { "OutputDebugStringW", (SYSCALL)0, 0 }, #endif -#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[71].pCurrent) +#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[72].pCurrent) { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, -#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[72].pCurrent) +#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[73].pCurrent) #if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL) { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, @@ -969,7 +987,7 @@ static struct win_syscall { #endif #define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ - LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[73].pCurrent) + LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[74].pCurrent) }; /* End of the overrideable system calls */ @@ -1125,6 +1143,10 @@ void sqlite3_win32_sleep(DWORD milliseconds){ ** WinNT/2K/XP so that we will know whether or not we can safely call ** the LockFileEx() API. */ +#ifndef NTDDI_WIN8 +# define NTDDI_WIN8 0x06020000 +#endif + #if SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) # define osIsNT() (1) #elif !defined(SQLITE_WIN32_HAS_WIDE) @@ -1132,9 +1154,15 @@ void sqlite3_win32_sleep(DWORD milliseconds){ #else static int osIsNT(void){ if( sqlite3_os_type==0 ){ +#if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 + OSVERSIONINFOW sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExW(&sInfo); +#else OSVERSIONINFOA sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); osGetVersionExA(&sInfo); +#endif sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; } return sqlite3_os_type==2; @@ -1159,7 +1187,7 @@ static void *winMemMalloc(int nBytes){ assert( nBytes>=0 ); p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); if( !p ){ - sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%d), heap=%p", + sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p", nBytes, osGetLastError(), (void*)hHeap); } return p; @@ -1180,7 +1208,7 @@ static void winMemFree(void *pPrior){ #endif if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){ - sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%d), heap=%p", + sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p", pPrior, osGetLastError(), (void*)hHeap); } } @@ -1206,7 +1234,7 @@ static void *winMemRealloc(void *pPrior, int nBytes){ p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes); } if( !p ){ - sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%d), heap=%p", + sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p", pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(), (void*)hHeap); } @@ -1230,7 +1258,7 @@ static int winMemSize(void *p){ if( !p ) return 0; n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p); if( n==(SIZE_T)-1 ){ - sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%d), heap=%p", + sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p", p, osGetLastError(), (void*)hHeap); return 0; } @@ -1260,7 +1288,7 @@ static int winMemInit(void *pAppData){ SQLITE_WIN32_HEAP_MAX_SIZE); if( !pWinMemData->hHeap ){ sqlite3_log(SQLITE_NOMEM, - "failed to HeapCreate (%d), flags=%u, initSize=%u, maxSize=%u", + "failed to HeapCreate (%lu), flags=%u, initSize=%u, maxSize=%u", osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE); return SQLITE_NOMEM; @@ -1272,7 +1300,7 @@ static int winMemInit(void *pAppData){ pWinMemData->hHeap = osGetProcessHeap(); if( !pWinMemData->hHeap ){ sqlite3_log(SQLITE_NOMEM, - "failed to GetProcessHeap (%d)", osGetLastError()); + "failed to GetProcessHeap (%lu)", osGetLastError()); return SQLITE_NOMEM; } pWinMemData->bOwned = FALSE; @@ -1300,7 +1328,7 @@ static void winMemShutdown(void *pAppData){ #endif if( pWinMemData->bOwned ){ if( !osHeapDestroy(pWinMemData->hHeap) ){ - sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), heap=%p", + sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p", osGetLastError(), (void*)pWinMemData->hHeap); } pWinMemData->bOwned = FALSE; @@ -3185,7 +3213,6 @@ static int winDelete(sqlite3_vfs *,const char*,int); static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ winShmNode **pp; winShmNode *p; - BOOL bRc; assert( winShmMutexHeld() ); OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n", osGetCurrentProcessId(), deleteFlag)); @@ -3195,12 +3222,14 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ int i; if( p->mutex ) sqlite3_mutex_free(p->mutex); for(i=0; i<p->nRegion; i++){ - bRc = osUnmapViewOfFile(p->aRegion[i].pMap); + BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap); OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n", osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); + UNUSED_VARIABLE_VALUE(bRc); bRc = osCloseHandle(p->aRegion[i].hMap); OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n", osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); + UNUSED_VARIABLE_VALUE(bRc); } if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ SimulateIOErrorBenign(1); @@ -3919,6 +3948,7 @@ static const sqlite3_io_methods winIoMethod = { ** sqlite3_vfs object. */ +#if 0 /* ** Convert a filename from whatever the underlying operating system ** supports for filenames into UTF-8. Space to hold the result is @@ -3937,6 +3967,7 @@ static char *winConvertToUtf8Filename(const void *zFilename){ /* caller will handle out of memory */ return zConverted; } +#endif /* ** Convert a UTF-8 filename into whatever form the underlying @@ -5154,7 +5185,7 @@ int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==74 ); + assert( ArraySize(aSyscall)==75 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); diff --git a/src/parse.y b/src/parse.y index e9c8a1563..1e8d7f751 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1081,12 +1081,13 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { /* CASE expressions */ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { - A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, Z, 0); + A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0); if( A.pExpr ){ - A.pExpr->x.pList = Y; + A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y; sqlite3ExprSetHeight(pParse, A.pExpr); }else{ sqlite3ExprListDelete(pParse->db, Y); + sqlite3ExprDelete(pParse->db, Z); } A.zStart = C.z; A.zEnd = &E.z[E.n]; diff --git a/src/pragma.c b/src/pragma.c index d4cf597ff..a79b401f0 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -13,6 +13,235 @@ */ #include "sqliteInt.h" +#if !defined(SQLITE_ENABLE_LOCKING_STYLE) +# if defined(__APPLE__) +# define SQLITE_ENABLE_LOCKING_STYLE 1 +# else +# define SQLITE_ENABLE_LOCKING_STYLE 0 +# endif +#endif + +/*************************************************************************** +** The next block of code, including the PragTyp_XXXX macro definitions and +** the aPragmaName[] object is composed of generated code. DO NOT EDIT. +** +** To add new pragmas, edit the code in ../tool/mkpragmatab.tcl and rerun +** that script. Then copy/paste the output in place of the following: +*/ +#define PragTyp_HEADER_VALUE 0 +#define PragTyp_AUTO_VACUUM 1 +#define PragTyp_FLAG 2 +#define PragTyp_BUSY_TIMEOUT 3 +#define PragTyp_CACHE_SIZE 4 +#define PragTyp_CASE_SENSITIVE_LIKE 5 +#define PragTyp_COLLATION_LIST 6 +#define PragTyp_COMPILE_OPTIONS 7 +#define PragTyp_DATA_STORE_DIRECTORY 8 +#define PragTyp_DATABASE_LIST 9 +#define PragTyp_DEFAULT_CACHE_SIZE 10 +#define PragTyp_ENCODING 11 +#define PragTyp_FOREIGN_KEY_CHECK 12 +#define PragTyp_FOREIGN_KEY_LIST 13 +#define PragTyp_INCREMENTAL_VACUUM 14 +#define PragTyp_INDEX_INFO 15 +#define PragTyp_INDEX_LIST 16 +#define PragTyp_INTEGRITY_CHECK 17 +#define PragTyp_JOURNAL_MODE 18 +#define PragTyp_JOURNAL_SIZE_LIMIT 19 +#define PragTyp_LOCK_PROXY_FILE 20 +#define PragTyp_LOCKING_MODE 21 +#define PragTyp_PAGE_COUNT 22 +#define PragTyp_MMAP_SIZE 23 +#define PragTyp_PAGE_SIZE 24 +#define PragTyp_SECURE_DELETE 25 +#define PragTyp_SHRINK_MEMORY 26 +#define PragTyp_SOFT_HEAP_LIMIT 27 +#define PragTyp_SYNCHRONOUS 28 +#define PragTyp_TABLE_INFO 29 +#define PragTyp_TEMP_STORE 30 +#define PragTyp_TEMP_STORE_DIRECTORY 31 +#define PragTyp_WAL_AUTOCHECKPOINT 32 +#define PragTyp_WAL_CHECKPOINT 33 +#define PragTyp_ACTIVATE_EXTENSIONS 34 +#define PragTyp_HEXKEY 35 +#define PragTyp_KEY 36 +#define PragTyp_REKEY 37 +#define PragTyp_LOCK_STATUS 38 +#define PragTyp_PARSER_TRACE 39 +static const struct sPragmaNames { + const char *const zName; /* Name of pragma */ + u8 ePragTyp; /* PragTyp_XXX value */ + u32 iArg; /* Extra argument */ +} aPragmaNames[] = { +#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) + { "activate_extensions", PragTyp_ACTIVATE_EXTENSIONS, 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { "application_id", PragTyp_HEADER_VALUE, 0 }, +#endif +#if !defined(SQLITE_OMIT_AUTOVACUUM) + { "auto_vacuum", PragTyp_AUTO_VACUUM, 0 }, +#endif +#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX) + { "automatic_index", PragTyp_FLAG, + SQLITE_AutoIndex }, +#endif + { "busy_timeout", PragTyp_BUSY_TIMEOUT, 0 }, +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { "cache_size", PragTyp_CACHE_SIZE, 0 }, +#endif + { "cache_spill", PragTyp_FLAG, + SQLITE_CacheSpill }, + { "case_sensitive_like", PragTyp_CASE_SENSITIVE_LIKE, 0 }, + { "checkpoint_fullfsync", PragTyp_FLAG, + SQLITE_CkptFullFSync }, +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { "collation_list", PragTyp_COLLATION_LIST, 0 }, +#endif +#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) + { "compile_options", PragTyp_COMPILE_OPTIONS, 0 }, +#endif + { "count_changes", PragTyp_FLAG, + SQLITE_CountRows }, +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN + { "data_store_directory", PragTyp_DATA_STORE_DIRECTORY, 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { "database_list", PragTyp_DATABASE_LIST, 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) + { "default_cache_size", PragTyp_DEFAULT_CACHE_SIZE, 0 }, +#endif +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + { "defer_foreign_keys", PragTyp_FLAG, + SQLITE_DeferFKs }, +#endif + { "empty_result_callbacks", PragTyp_FLAG, + SQLITE_NullCallback }, +#if !defined(SQLITE_OMIT_UTF16) + { "encoding", PragTyp_ENCODING, 0 }, +#endif +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + { "foreign_key_check", PragTyp_FOREIGN_KEY_CHECK, 0 }, +#endif +#if !defined(SQLITE_OMIT_FOREIGN_KEY) + { "foreign_key_list", PragTyp_FOREIGN_KEY_LIST, 0 }, +#endif +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + { "foreign_keys", PragTyp_FLAG, + SQLITE_ForeignKeys }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { "freelist_count", PragTyp_HEADER_VALUE, 0 }, +#endif + { "full_column_names", PragTyp_FLAG, + SQLITE_FullColNames }, + { "fullfsync", PragTyp_FLAG, + SQLITE_FullFSync }, +#if defined(SQLITE_HAS_CODEC) + { "hexkey", PragTyp_HEXKEY, 0 }, +#endif +#if !defined(SQLITE_OMIT_CHECK) + { "ignore_check_constraints", PragTyp_FLAG, + SQLITE_IgnoreChecks }, +#endif +#if !defined(SQLITE_OMIT_AUTOVACUUM) + { "incremental_vacuum", PragTyp_INCREMENTAL_VACUUM, 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { "index_info", PragTyp_INDEX_INFO, 0 }, + { "index_list", PragTyp_INDEX_LIST, 0 }, +#endif +#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) + { "integrity_check", PragTyp_INTEGRITY_CHECK, 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { "journal_mode", PragTyp_JOURNAL_MODE, 0 }, + { "journal_size_limit", PragTyp_JOURNAL_SIZE_LIMIT, 0 }, +#endif +#if defined(SQLITE_HAS_CODEC) + { "key", PragTyp_KEY, 0 }, +#endif + { "legacy_file_format", PragTyp_FLAG, + SQLITE_LegacyFileFmt }, +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE + { "lock_proxy_file", PragTyp_LOCK_PROXY_FILE, 0 }, +#endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + { "lock_status", PragTyp_LOCK_STATUS, 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { "locking_mode", PragTyp_LOCKING_MODE, 0 }, + { "max_page_count", PragTyp_PAGE_COUNT, 0 }, + { "mmap_size", PragTyp_MMAP_SIZE, 0 }, + { "page_count", PragTyp_PAGE_COUNT, 0 }, + { "page_size", PragTyp_PAGE_SIZE, 0 }, +#endif +#if defined(SQLITE_DEBUG) + { "parser_trace", PragTyp_PARSER_TRACE, 0 }, +#endif + { "query_only", PragTyp_FLAG, + SQLITE_QueryOnly }, +#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) + { "quick_check", PragTyp_INTEGRITY_CHECK, 0 }, +#endif + { "read_uncommitted", PragTyp_FLAG, + SQLITE_ReadUncommitted }, + { "recursive_triggers", PragTyp_FLAG, + SQLITE_RecTriggers }, +#if defined(SQLITE_HAS_CODEC) + { "rekey", PragTyp_REKEY, 0 }, +#endif + { "reverse_unordered_selects", PragTyp_FLAG, + SQLITE_ReverseOrder }, +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { "schema_version", PragTyp_HEADER_VALUE, 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { "secure_delete", PragTyp_SECURE_DELETE, 0 }, +#endif + { "short_column_names", PragTyp_FLAG, + SQLITE_ShortColNames }, + { "shrink_memory", PragTyp_SHRINK_MEMORY, 0 }, + { "soft_heap_limit", PragTyp_SOFT_HEAP_LIMIT, 0 }, +#if defined(SQLITE_DEBUG) + { "sql_trace", PragTyp_FLAG, + SQLITE_SqlTrace }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { "synchronous", PragTyp_SYNCHRONOUS, 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { "table_info", PragTyp_TABLE_INFO, 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { "temp_store", PragTyp_TEMP_STORE, 0 }, + { "temp_store_directory", PragTyp_TEMP_STORE_DIRECTORY, 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { "user_version", PragTyp_HEADER_VALUE, 0 }, +#endif +#if defined(SQLITE_DEBUG) + { "vdbe_addoptrace", PragTyp_FLAG, + SQLITE_VdbeAddopTrace }, + { "vdbe_debug", PragTyp_FLAG, + SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace }, + { "vdbe_listing", PragTyp_FLAG, + SQLITE_VdbeListing }, + { "vdbe_trace", PragTyp_FLAG, + SQLITE_VdbeTrace }, +#endif +#if !defined(SQLITE_OMIT_WAL) + { "wal_autocheckpoint", PragTyp_WAL_AUTOCHECKPOINT, 0 }, + { "wal_checkpoint", PragTyp_WAL_CHECKPOINT, 0 }, +#endif + { "writable_schema", PragTyp_FLAG, + SQLITE_WriteSchema|SQLITE_RecoveryMode }, +}; +/* Number of pragmas: 55 on by default, 66 total. */ +/* End of the automatically generated pragma table. +***************************************************************************/ + /* ** Interpret the given string as a safety level. Return 0 for OFF, ** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or @@ -188,97 +417,6 @@ static void setAllPagerFlags(sqlite3 *db){ #endif -#ifndef SQLITE_OMIT_FLAG_PRAGMAS -/* -** Check to see if zRight and zLeft refer to a pragma that queries -** or changes one of the flags in db->flags. Return 1 if so and 0 if not. -** Also, implement the pragma. -*/ -static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){ - static const struct sPragmaType { - const char *zName; /* Name of the pragma */ - int mask; /* Mask for the db->flags value */ - } aPragma[] = { - { "full_column_names", SQLITE_FullColNames }, - { "short_column_names", SQLITE_ShortColNames }, - { "count_changes", SQLITE_CountRows }, - { "empty_result_callbacks", SQLITE_NullCallback }, - { "legacy_file_format", SQLITE_LegacyFileFmt }, - { "fullfsync", SQLITE_FullFSync }, - { "checkpoint_fullfsync", SQLITE_CkptFullFSync }, - { "cache_spill", SQLITE_CacheSpill }, - { "reverse_unordered_selects", SQLITE_ReverseOrder }, - { "query_only", SQLITE_QueryOnly }, -#ifndef SQLITE_OMIT_AUTOMATIC_INDEX - { "automatic_index", SQLITE_AutoIndex }, -#endif -#ifdef SQLITE_DEBUG - { "sql_trace", SQLITE_SqlTrace }, - { "vdbe_listing", SQLITE_VdbeListing }, - { "vdbe_trace", SQLITE_VdbeTrace }, - { "vdbe_addoptrace", SQLITE_VdbeAddopTrace}, - { "vdbe_debug", SQLITE_SqlTrace | SQLITE_VdbeListing - | SQLITE_VdbeTrace }, -#endif -#ifndef SQLITE_OMIT_CHECK - { "ignore_check_constraints", SQLITE_IgnoreChecks }, -#endif - /* The following is VERY experimental */ - { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode }, - - /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted - ** flag if there are any active statements. */ - { "read_uncommitted", SQLITE_ReadUncommitted }, - { "recursive_triggers", SQLITE_RecTriggers }, - - /* This flag may only be set if both foreign-key and trigger support - ** are present in the build. */ -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - { "foreign_keys", SQLITE_ForeignKeys }, - { "defer_foreign_keys", SQLITE_DeferFKs }, -#endif - }; - int i; - const struct sPragmaType *p; - for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){ - if( sqlite3StrICmp(zLeft, p->zName)==0 ){ - sqlite3 *db = pParse->db; - Vdbe *v; - v = sqlite3GetVdbe(pParse); - assert( v!=0 ); /* Already allocated by sqlite3Pragma() */ - if( ALWAYS(v) ){ - if( zRight==0 ){ - returnSingleInt(pParse, p->zName, (db->flags & p->mask)!=0 ); - }else{ - int mask = p->mask; /* Mask of bits to set or clear. */ - if( db->autoCommit==0 ){ - /* Foreign key support may not be enabled or disabled while not - ** in auto-commit mode. */ - mask &= ~(SQLITE_ForeignKeys); - } - - if( sqlite3GetBoolean(zRight, 0) ){ - db->flags |= mask; - }else{ - db->flags &= ~mask; - if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; - } - - /* Many of the flag-pragmas modify the code generated by the SQL - ** compiler (eg. count_changes). So add an opcode to expire all - ** compiled SQL statements after modifying a pragma value. - */ - sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); - } - } - - return 1; - } - } - return 0; -} -#endif /* SQLITE_OMIT_FLAG_PRAGMAS */ - /* ** Return a human-readable name for a constraint resolution action. */ @@ -348,8 +486,9 @@ void sqlite3Pragma( char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */ const char *zDb = 0; /* The database name */ Token *pId; /* Pointer to <id> token */ - int iDb; /* Database index for <database> */ char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */ + int iDb; /* Database index for <database> */ + int lwr, upr, mid; /* Binary search bounds */ int rc; /* return value form SQLITE_FCNTL_PRAGMA */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ @@ -405,16 +544,36 @@ void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1); sqlite3_free(aFcntl[0]); } - }else if( rc!=SQLITE_NOTFOUND ){ + goto pragma_out; + } + if( rc!=SQLITE_NOTFOUND ){ if( aFcntl[0] ){ sqlite3ErrorMsg(pParse, "%s", aFcntl[0]); sqlite3_free(aFcntl[0]); } pParse->nErr++; pParse->rc = rc; - }else - - + goto pragma_out; + } + + /* Locate the pragma in the lookup table */ + lwr = 0; + upr = ArraySize(aPragmaNames)-1; + while( lwr<=upr ){ + mid = (lwr+upr)/2; + rc = sqlite3_stricmp(zLeft, aPragmaNames[mid].zName); + if( rc==0 ) break; + if( rc<0 ){ + upr = mid - 1; + }else{ + lwr = mid + 1; + } + } + if( lwr>upr ) goto pragma_out; + + /* Jump to the appropriate pragma handler */ + switch( aPragmaNames[mid].ePragTyp ){ + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) /* ** PRAGMA [database.]default_cache_size @@ -432,7 +591,7 @@ void sqlite3Pragma( ** size. But continue to take the absolute value of the default cache ** size of historical compatibility. */ - if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ + case PragTyp_DEFAULT_CACHE_SIZE: { static const VdbeOpList getCacheSize[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */ @@ -464,7 +623,8 @@ void sqlite3Pragma( pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } - }else + break; + } #endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -477,7 +637,7 @@ void sqlite3Pragma( ** database page size value. The value can only be set if ** the database has not yet been created. */ - if( sqlite3StrICmp(zLeft,"page_size")==0 ){ + case PragTyp_PAGE_SIZE: { Btree *pBt = pDb->pBt; assert( pBt!=0 ); if( !zRight ){ @@ -492,7 +652,8 @@ void sqlite3Pragma( db->mallocFailed = 1; } } - }else + break; + } /* ** PRAGMA [database.]secure_delete @@ -502,7 +663,7 @@ void sqlite3Pragma( ** secure_delete flag. The second form changes the secure_delete ** flag setting and reports thenew value. */ - if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){ + case PragTyp_SECURE_DELETE: { Btree *pBt = pDb->pBt; int b = -1; assert( pBt!=0 ); @@ -517,7 +678,8 @@ void sqlite3Pragma( } b = sqlite3BtreeSecureDelete(pBt, b); returnSingleInt(pParse, "secure_delete", b); - }else + break; + } /* ** PRAGMA [database.]max_page_count @@ -536,9 +698,7 @@ void sqlite3Pragma( ** ** Return the number of pages in the specified database. */ - if( sqlite3StrICmp(zLeft,"page_count")==0 - || sqlite3StrICmp(zLeft,"max_page_count")==0 - ){ + case PragTyp_PAGE_COUNT: { int iReg; if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3CodeVerifySchema(pParse, iDb); @@ -552,13 +712,14 @@ void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT); - }else + break; + } /* ** PRAGMA [database.]locking_mode ** PRAGMA [database.]locking_mode = (normal|exclusive) */ - if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){ + case PragTyp_LOCKING_MODE: { const char *zRet = "normal"; int eMode = getLockingMode(zRight); @@ -591,7 +752,8 @@ void sqlite3Pragma( eMode = sqlite3PagerLockingMode(pPager, eMode); } - assert(eMode==PAGER_LOCKINGMODE_NORMAL||eMode==PAGER_LOCKINGMODE_EXCLUSIVE); + assert( eMode==PAGER_LOCKINGMODE_NORMAL + || eMode==PAGER_LOCKINGMODE_EXCLUSIVE ); if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){ zRet = "exclusive"; } @@ -599,14 +761,15 @@ void sqlite3Pragma( sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", SQLITE_STATIC); sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zRet, 0); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); - }else + break; + } /* ** PRAGMA [database.]journal_mode ** PRAGMA [database.]journal_mode = ** (delete|persist|off|truncate|memory|wal|off) */ - if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){ + case PragTyp_JOURNAL_MODE: { int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */ int ii; /* Loop counter */ @@ -649,7 +812,8 @@ void sqlite3Pragma( } } sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); - }else + break; + } /* ** PRAGMA [database.]journal_size_limit @@ -657,7 +821,7 @@ void sqlite3Pragma( ** ** Get or set the size limit on rollback journal files. */ - if( sqlite3StrICmp(zLeft,"journal_size_limit")==0 ){ + case PragTyp_JOURNAL_SIZE_LIMIT: { Pager *pPager = sqlite3BtreePager(pDb->pBt); i64 iLimit = -2; if( zRight ){ @@ -666,7 +830,8 @@ void sqlite3Pragma( } iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); returnSingleInt(pParse, "journal_size_limit", iLimit); - }else + break; + } #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ @@ -678,7 +843,7 @@ void sqlite3Pragma( ** The value is one of: 0 NONE 1 FULL 2 INCREMENTAL */ #ifndef SQLITE_OMIT_AUTOVACUUM - if( sqlite3StrICmp(zLeft,"auto_vacuum")==0 ){ + case PragTyp_AUTO_VACUUM: { Btree *pBt = pDb->pBt; assert( pBt!=0 ); if( sqlite3ReadSchema(pParse) ){ @@ -728,7 +893,8 @@ void sqlite3Pragma( } } } - }else + break; + } #endif /* @@ -737,7 +903,7 @@ void sqlite3Pragma( ** Do N steps of incremental vacuuming on a database. */ #ifndef SQLITE_OMIT_AUTOVACUUM - if( sqlite3StrICmp(zLeft,"incremental_vacuum")==0 ){ + case PragTyp_INCREMENTAL_VACUUM: { int iLimit, addr; if( sqlite3ReadSchema(pParse) ){ goto pragma_out; @@ -752,7 +918,8 @@ void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr); sqlite3VdbeJumpHere(v, addr); - }else + break; + } #endif #ifndef SQLITE_OMIT_PAGER_PRAGMAS @@ -767,7 +934,7 @@ void sqlite3Pragma( ** number of pages is adjusted so that the cache uses -N kibibytes ** of memory. */ - if( sqlite3StrICmp(zLeft,"cache_size")==0 ){ + case PragTyp_CACHE_SIZE: { if( sqlite3ReadSchema(pParse) ) goto pragma_out; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !zRight ){ @@ -777,7 +944,8 @@ void sqlite3Pragma( pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } - }else + break; + } /* ** PRAGMA [database.]mmap_size(N) @@ -793,7 +961,7 @@ void sqlite3Pragma( ** as little or as much as it wants. Except, if N is set to 0 then the ** upper layers will never invoke the xFetch interfaces to the VFS. */ - if( sqlite3StrICmp(zLeft,"mmap_size")==0 ){ + case PragTyp_MMAP_SIZE: { sqlite3_int64 sz; #if SQLITE_MAX_MMAP_SIZE>0 assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); @@ -820,7 +988,8 @@ void sqlite3Pragma( pParse->nErr++; pParse->rc = rc; } - }else + break; + } /* ** PRAGMA temp_store @@ -833,13 +1002,14 @@ void sqlite3Pragma( ** Note that it is possible for the library compile-time options to ** override this setting */ - if( sqlite3StrICmp(zLeft, "temp_store")==0 ){ + case PragTyp_TEMP_STORE: { if( !zRight ){ returnSingleInt(pParse, "temp_store", db->temp_store); }else{ changeTempStorage(pParse, zRight); } - }else + break; + } /* ** PRAGMA temp_store_directory @@ -851,7 +1021,7 @@ void sqlite3Pragma( ** If temporary directory is changed, then invalidateTempStorage. ** */ - if( sqlite3StrICmp(zLeft, "temp_store_directory")==0 ){ + case PragTyp_TEMP_STORE_DIRECTORY: { if( !zRight ){ if( sqlite3_temp_directory ){ sqlite3VdbeSetNumCols(v, 1); @@ -884,7 +1054,8 @@ void sqlite3Pragma( } #endif /* SQLITE_OMIT_WSD */ } - }else + break; + } #if SQLITE_OS_WIN /* @@ -900,7 +1071,7 @@ void sqlite3Pragma( ** by this setting, regardless of its value. ** */ - if( sqlite3StrICmp(zLeft, "data_store_directory")==0 ){ + case PragTyp_DATA_STORE_DIRECTORY: { if( !zRight ){ if( sqlite3_data_directory ){ sqlite3VdbeSetNumCols(v, 1); @@ -927,26 +1098,20 @@ void sqlite3Pragma( } #endif /* SQLITE_OMIT_WSD */ } - }else + break; + } #endif -#if !defined(SQLITE_ENABLE_LOCKING_STYLE) -# if defined(__APPLE__) -# define SQLITE_ENABLE_LOCKING_STYLE 1 -# else -# define SQLITE_ENABLE_LOCKING_STYLE 0 -# endif -#endif #if SQLITE_ENABLE_LOCKING_STYLE /* - ** PRAGMA [database.]lock_proxy_file - ** PRAGMA [database.]lock_proxy_file = ":auto:"|"lock_file_path" - ** - ** Return or set the value of the lock_proxy_file flag. Changing - ** the value sets a specific file to be used for database access locks. - ** - */ - if( sqlite3StrICmp(zLeft, "lock_proxy_file")==0 ){ + ** PRAGMA [database.]lock_proxy_file + ** PRAGMA [database.]lock_proxy_file = ":auto:"|"lock_file_path" + ** + ** Return or set the value of the lock_proxy_file flag. Changing + ** the value sets a specific file to be used for database access locks. + ** + */ + case PragTyp_LOCK_PROXY_FILE: { if( !zRight ){ Pager *pPager = sqlite3BtreePager(pDb->pBt); char *proxy_file_path = NULL; @@ -977,7 +1142,8 @@ void sqlite3Pragma( goto pragma_out; } } - }else + break; + } #endif /* SQLITE_ENABLE_LOCKING_STYLE */ /* @@ -989,7 +1155,7 @@ void sqlite3Pragma( ** default value will be restored the next time the database is ** opened. */ - if( sqlite3StrICmp(zLeft,"synchronous")==0 ){ + case PragTyp_SYNCHRONOUS: { if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( !zRight ){ returnSingleInt(pParse, "synchronous", pDb->safety_level-1); @@ -1002,13 +1168,39 @@ void sqlite3Pragma( setAllPagerFlags(db); } } - }else + break; + } #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ #ifndef SQLITE_OMIT_FLAG_PRAGMAS - if( flagPragma(pParse, zLeft, zRight) ){ - setAllPagerFlags(db); - }else + case PragTyp_FLAG: { + if( zRight==0 ){ + returnSingleInt(pParse, aPragmaNames[mid].zName, + (db->flags & aPragmaNames[mid].iArg)!=0 ); + }else{ + int mask = aPragmaNames[mid].iArg; /* Mask of bits to set or clear. */ + if( db->autoCommit==0 ){ + /* Foreign key support may not be enabled or disabled while not + ** in auto-commit mode. */ + mask &= ~(SQLITE_ForeignKeys); + } + + if( sqlite3GetBoolean(zRight, 0) ){ + db->flags |= mask; + }else{ + db->flags &= ~mask; + if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; + } + + /* Many of the flag-pragmas modify the code generated by the SQL + ** compiler (eg. count_changes). So add an opcode to expire all + ** compiled SQL statements after modifying a pragma value. + */ + sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); + setAllPagerFlags(db); + } + break; + } #endif /* SQLITE_OMIT_FLAG_PRAGMAS */ #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS @@ -1024,7 +1216,7 @@ void sqlite3Pragma( ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. */ - if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){ + case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; pTab = sqlite3FindTable(db, zRight, zDb); @@ -1070,9 +1262,10 @@ void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); } } - }else + } + break; - if( sqlite3StrICmp(zLeft, "index_info")==0 && zRight ){ + case PragTyp_INDEX_INFO: if( zRight ){ Index *pIdx; Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; @@ -1095,9 +1288,10 @@ void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } - }else + } + break; - if( sqlite3StrICmp(zLeft, "index_list")==0 && zRight ){ + case PragTyp_INDEX_LIST: if( zRight ){ Index *pIdx; Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; @@ -1123,9 +1317,10 @@ void sqlite3Pragma( } } } - }else + } + break; - if( sqlite3StrICmp(zLeft, "database_list")==0 ){ + case PragTyp_DATABASE_LIST: { int i; if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 3); @@ -1142,9 +1337,10 @@ void sqlite3Pragma( sqlite3BtreeGetFilename(db->aDb[i].pBt), 0); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } - }else + } + break; - if( sqlite3StrICmp(zLeft, "collation_list")==0 ){ + case PragTyp_COLLATION_LIST: { int i = 0; HashElem *p; sqlite3VdbeSetNumCols(v, 2); @@ -1157,11 +1353,12 @@ void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pColl->zName, 0); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } - }else + } + break; #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */ #ifndef SQLITE_OMIT_FOREIGN_KEY - if( sqlite3StrICmp(zLeft, "foreign_key_list")==0 && zRight ){ + case PragTyp_FOREIGN_KEY_LIST: if( zRight ){ FKey *pFK; Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; @@ -1204,12 +1401,13 @@ void sqlite3Pragma( } } } - }else + } + break; #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_TRIGGER - if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){ + case PragTyp_FOREIGN_KEY_CHECK: { FKey *pFK; /* A foreign key constraint */ Table *pTab; /* Child table contain "REFERENCES" keyword */ Table *pParent; /* Parent table that child points to */ @@ -1319,12 +1517,13 @@ void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); sqlite3VdbeJumpHere(v, addrTop); } - }else + } + break; #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef NDEBUG - if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ + case PragTyp_PARSER_TRACE: { if( zRight ){ if( sqlite3GetBoolean(zRight, 0) ){ sqlite3ParserTrace(stderr, "parser: "); @@ -1332,17 +1531,19 @@ void sqlite3Pragma( sqlite3ParserTrace(0, 0); } } - }else + } + break; #endif /* Reinstall the LIKE and GLOB functions. The variant of LIKE ** used will be case sensitive or not depending on the RHS. */ - if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){ + case PragTyp_CASE_SENSITIVE_LIKE: { if( zRight ){ sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight, 0)); } - }else + } + break; #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 @@ -1353,9 +1554,7 @@ void sqlite3Pragma( ** integrity_check designed to detect most database corruption ** without most of the overhead of a full integrity-check. */ - if( sqlite3StrICmp(zLeft, "integrity_check")==0 - || sqlite3StrICmp(zLeft, "quick_check")==0 - ){ + case PragTyp_INTEGRITY_CHECK: { int i, j, addr, mxErr; /* Code that appears at the end of the integrity check. If no error @@ -1515,7 +1714,8 @@ void sqlite3Pragma( sqlite3VdbeChangeP2(v, addr, -mxErr); sqlite3VdbeJumpHere(v, addr+1); sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); - }else + } + break; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_UTF16 @@ -1541,7 +1741,7 @@ void sqlite3Pragma( ** new database files created using this database handle. It is only ** useful if invoked immediately after the main database i */ - if( sqlite3StrICmp(zLeft, "encoding")==0 ){ + case PragTyp_ENCODING: { static const struct EncName { char *zName; u8 enc; @@ -1588,7 +1788,8 @@ void sqlite3Pragma( } } } - }else + } + break; #endif /* SQLITE_OMIT_UTF16 */ #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS @@ -1622,11 +1823,7 @@ void sqlite3Pragma( ** The user-version is not used internally by SQLite. It may be used by ** applications for any purpose. */ - if( sqlite3StrICmp(zLeft, "schema_version")==0 - || sqlite3StrICmp(zLeft, "user_version")==0 - || sqlite3StrICmp(zLeft, "freelist_count")==0 - || sqlite3StrICmp(zLeft, "application_id")==0 - ){ + case PragTyp_HEADER_VALUE: { int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */ sqlite3VdbeUsesBtree(v, iDb); switch( zLeft[0] ){ @@ -1670,7 +1867,8 @@ void sqlite3Pragma( sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT); } - }else + } + break; #endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS @@ -1680,7 +1878,7 @@ void sqlite3Pragma( ** Return the names of all compile-time options used in this build, ** one option per row. */ - if( sqlite3StrICmp(zLeft, "compile_options")==0 ){ + case PragTyp_COMPILE_OPTIONS: { int i = 0; const char *zOpt; sqlite3VdbeSetNumCols(v, 1); @@ -1690,7 +1888,8 @@ void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zOpt, 0); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); } - }else + } + break; #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ #ifndef SQLITE_OMIT_WAL @@ -1699,7 +1898,7 @@ void sqlite3Pragma( ** ** Checkpoint the database. */ - if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 ){ + case PragTyp_WAL_CHECKPOINT: { int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED); int eMode = SQLITE_CHECKPOINT_PASSIVE; if( zRight ){ @@ -1718,7 +1917,8 @@ void sqlite3Pragma( sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); - }else + } + break; /* ** PRAGMA wal_autocheckpoint @@ -1728,14 +1928,15 @@ void sqlite3Pragma( ** after accumulating N frames in the log. Or query for the current value ** of N. */ - if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){ + case PragTyp_WAL_AUTOCHECKPOINT: { if( zRight ){ sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight)); } returnSingleInt(pParse, "wal_autocheckpoint", db->xWalCallback==sqlite3WalDefaultHook ? SQLITE_PTR_TO_INT(db->pWalArg) : 0); - }else + } + break; #endif /* @@ -1744,9 +1945,10 @@ void sqlite3Pragma( ** This pragma attempts to free as much memory as possible from the ** current database connection. */ - if( sqlite3StrICmp(zLeft, "shrink_memory")==0 ){ + case PragTyp_SHRINK_MEMORY: { sqlite3_db_release_memory(db); - }else + break; + } /* ** PRAGMA busy_timeout @@ -1757,18 +1959,36 @@ void sqlite3Pragma( ** then 0 is returned. Setting the busy_timeout to 0 or negative ** disables the timeout. */ - if( sqlite3StrICmp(zLeft, "busy_timeout")==0 ){ + /*case PragTyp_BUSY_TIMEOUT*/ default: { + assert( aPragmaNames[mid].ePragTyp==PragTyp_BUSY_TIMEOUT ); if( zRight ){ sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); } returnSingleInt(pParse, "timeout", db->busyTimeout); - }else + break; + } + + /* + ** PRAGMA soft_heap_limit + ** PRAGMA soft_heap_limit = N + ** + ** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted, + ** use -1. + */ + case PragTyp_SOFT_HEAP_LIMIT: { + sqlite3_int64 N; + if( zRight && sqlite3Atoi64(zRight, &N, 1000000, SQLITE_UTF8)==SQLITE_OK ){ + sqlite3_soft_heap_limit64(N); + } + returnSingleInt(pParse, "soft_heap_limit", sqlite3_soft_heap_limit64(-1)); + break; + } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases */ - if( sqlite3StrICmp(zLeft, "lock_status")==0 ){ + case PragTyp_LOCK_STATUS: { static const char *const azLockName[] = { "unlocked", "shared", "reserved", "pending", "exclusive" }; @@ -1793,35 +2013,39 @@ void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } - - }else + break; + } #endif #ifdef SQLITE_HAS_CODEC - if( sqlite3StrICmp(zLeft, "key")==0 && zRight ){ - sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); - }else - if( sqlite3StrICmp(zLeft, "rekey")==0 && zRight ){ - sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); - }else - if( zRight && (sqlite3StrICmp(zLeft, "hexkey")==0 || - sqlite3StrICmp(zLeft, "hexrekey")==0) ){ - int i, h1, h2; - char zKey[40]; - for(i=0; (h1 = zRight[i])!=0 && (h2 = zRight[i+1])!=0; i+=2){ - h1 += 9*(1&(h1>>6)); - h2 += 9*(1&(h2>>6)); - zKey[i/2] = (h2 & 0x0f) | ((h1 & 0xf)<<4); - } - if( (zLeft[3] & 0xf)==0xb ){ - sqlite3_key_v2(db, zDb, zKey, i/2); - }else{ - sqlite3_rekey_v2(db, zDb, zKey, i/2); + case PragTyp_KEY: { + if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); + break; + } + case PragTyp_REKEY: { + if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); + break; + } + case PragTyp_HEXKEY: { + if( zRight ){ + int i, h1, h2; + char zKey[40]; + for(i=0; (h1 = zRight[i])!=0 && (h2 = zRight[i+1])!=0; i+=2){ + h1 += 9*(1&(h1>>6)); + h2 += 9*(1&(h2>>6)); + zKey[i/2] = (h2 & 0x0f) | ((h1 & 0xf)<<4); + } + if( (zLeft[3] & 0xf)==0xb ){ + sqlite3_key_v2(db, zDb, zKey, i/2); + }else{ + sqlite3_rekey_v2(db, zDb, zKey, i/2); + } } - }else + break; + } #endif #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) - if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){ + case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ #ifdef SQLITE_HAS_CODEC if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){ sqlite3_activate_see(&zRight[4]); @@ -1832,11 +2056,11 @@ void sqlite3Pragma( sqlite3_activate_cerod(&zRight[6]); } #endif - }else + } + break; #endif - - {/* Empty ELSE clause */} + } /* End of the PRAGMA switch */ pragma_out: sqlite3DbFree(db, zLeft); diff --git a/src/resolve.c b/src/resolve.c index 43a3870e2..eacffc540 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -107,6 +107,7 @@ static void resolveAlias( incrAggFunctionDepth(pDup, nSubquery); pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0); if( pDup==0 ) return; + ExprSetProperty(pDup, EP_Skip); if( pEList->a[iCol].iAlias==0 ){ pEList->a[iCol].iAlias = (u16)(++pParse->nAlias); } @@ -129,7 +130,7 @@ static void resolveAlias( if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); - pExpr->flags2 |= EP2_MallocedToken; + pExpr->flags |= EP_MemToken; } sqlite3DbFree(db, pDup); } @@ -229,12 +230,12 @@ static int lookupName( assert( pNC ); /* the name context cannot be NULL. */ assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ - assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) ); + assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); /* Initialize the node to no-match */ pExpr->iTable = -1; pExpr->pTab = 0; - ExprSetIrreducible(pExpr); + ExprSetVVAProperty(pExpr, EP_NoReduce); /* Translate the schema name in zDb into a pointer to the corresponding ** schema. If not found, pSchema will remain NULL and nothing will match @@ -570,6 +571,19 @@ static void notValidCheckConstraint( # define notValidCheckConstraint(P,N,M) #endif +/* +** Expression p should encode a floating point value between 1.0 and 0.0. +** Return 1024 times this value. Or return -1 if p is not a floating point +** value between 1.0 and 0.0. +*/ +static int exprProbability(Expr *p){ + double r = -1.0; + if( p->op!=TK_FLOAT ) return -1; + sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); + assert( r>=0.0 ); + if( r>1.0 ) return -1; + return (int)(r*1000.0); +} /* ** This routine is callback for sqlite3WalkExpr(). @@ -591,7 +605,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pParse = pNC->pParse; assert( pParse==pWalker->pParse ); - if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return WRC_Prune; + if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune; ExprSetProperty(pExpr, EP_Resolved); #ifndef NDEBUG if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ @@ -683,6 +697,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } }else{ is_agg = pDef->xFunc==0; + if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ + ExprSetProperty(pExpr, EP_Unlikely|EP_Skip); + if( n==2 ){ + pExpr->iTable = exprProbability(pList->a[1].pExpr); + if( pExpr->iTable<0 ){ + sqlite3ErrorMsg(pParse, "second argument to likelihood() must be a " + "constant between 0.0 and 1.0"); + pNC->nErr++; + } + }else{ + pExpr->iTable = 62; /* TUNING: Default 2nd arg to unlikely() is 0.0625 */ + } + } } #ifndef SQLITE_OMIT_AUTHORIZATION if( pDef ){ diff --git a/src/select.c b/src/select.c index 6e409e73a..2ea8e1fc8 100644 --- a/src/select.c +++ b/src/select.c @@ -264,8 +264,8 @@ static void addWhereTerm( pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0); if( pEq && isOuterJoin ){ ExprSetProperty(pEq, EP_FromJoin); - assert( !ExprHasAnyProperty(pEq, EP_TokenOnly|EP_Reduced) ); - ExprSetIrreducible(pEq); + assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); + ExprSetVVAProperty(pEq, EP_NoReduce); pEq->iRightJoinTable = (i16)pE2->iTable; } *ppWhere = sqlite3ExprAnd(db, *ppWhere, pEq); @@ -300,8 +300,8 @@ static void addWhereTerm( static void setJoinExpr(Expr *p, int iTable){ while( p ){ ExprSetProperty(p, EP_FromJoin); - assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) ); - ExprSetIrreducible(p); + assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); + ExprSetVVAProperty(p, EP_NoReduce); p->iRightJoinTable = (i16)iTable; setJoinExpr(p->pLeft, iTable); p = p->pRight; diff --git a/src/sqlite3.rc b/src/sqlite3.rc index 969876da1..aedbb63eb 100644 --- a/src/sqlite3.rc +++ b/src/sqlite3.rc @@ -17,7 +17,11 @@ #include "winresrc.h" #else #include "windows.h" -#endif +#endif /* !defined(_WIN32_WCE) */ + +#if !defined(VS_FF_NONE) +# define VS_FF_NONE 0x00000000L +#endif /* !defined(VS_FF_NONE) */ #include "sqlite3.h" #include "sqlite3rc.h" @@ -26,10 +30,10 @@ * English (U.S.) resources */ -#ifdef _WIN32 +#if defined(_WIN32) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) -#endif /* _WIN32 */ +#endif /* defined(_WIN32) */ /* * Version @@ -38,14 +42,14 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US VS_VERSION_INFO VERSIONINFO FILEVERSION SQLITE_RESOURCE_VERSION PRODUCTVERSION SQLITE_RESOURCE_VERSION - FILEFLAGSMASK 0x3F + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #if defined(_DEBUG) - FILEFLAGS 0x1L + FILEFLAGS VS_FF_DEBUG #else - FILEFLAGS 0x0L -#endif + FILEFLAGS VS_FF_NONE +#endif /* defined(_DEBUG) */ FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP + FILETYPE VFT_DLL FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" @@ -64,6 +68,6 @@ BEGIN END BLOCK "VarFileInfo" BEGIN - VALUE "Translation", 0x409, 1200 + VALUE "Translation", 0x409, 0x4b0 END END diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 6b3fbe851..4a52b64f6 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -921,8 +921,6 @@ struct sqlite3 { void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); void *pCollNeededArg; sqlite3_value *pErr; /* Most recent error message */ - char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ - char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ union { volatile int isInterrupted; /* True if sqlite3_interrupt has been called */ double notUsed1; /* Spacer */ @@ -1032,6 +1030,7 @@ struct sqlite3 { #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ #define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */ +#define SQLITE_AdjustOutEst 0x1000 /* Adjust output estimates using WHERE */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* @@ -1724,7 +1723,7 @@ typedef int ynVar; struct Expr { u8 op; /* Operation performed by this node */ char affinity; /* The affinity of the column or 0 if not a column */ - u16 flags; /* Various flags. EP_* See below */ + u32 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ int iValue; /* Non-negative integer value if EP_IntValue */ @@ -1738,8 +1737,8 @@ struct Expr { Expr *pLeft; /* Left subnode */ Expr *pRight; /* Right subnode */ union { - ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */ - Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */ + ExprList *pList; /* op = IN, EXISTS, SELECT, CASE, FUNCTION, BETWEEN */ + Select *pSelect; /* EP_xIsSelect and op = IN, EXISTS, SELECT */ } x; /* If the EP_Reduced flag is set in the Expr.flags mask, then no @@ -1752,12 +1751,12 @@ struct Expr { #endif int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number - ** TK_TRIGGER: 1 -> new, 0 -> old */ + ** TK_TRIGGER: 1 -> new, 0 -> old + ** EP_Unlikely: 1000 times likelihood */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ - u8 flags2; /* Second set of flags. EP2_... */ u8 op2; /* TK_REGISTER: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth */ @@ -1768,51 +1767,46 @@ struct Expr { /* ** The following are the meanings of bits in the Expr.flags field. */ -#define EP_FromJoin 0x0001 /* Originated in ON or USING clause of a join */ -#define EP_Agg 0x0002 /* Contains one or more aggregate functions */ -#define EP_Resolved 0x0004 /* IDs have been resolved to COLUMNs */ -#define EP_Error 0x0008 /* Expression contains one or more errors */ -#define EP_Distinct 0x0010 /* Aggregate function with DISTINCT keyword */ -#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */ -#define EP_DblQuoted 0x0040 /* token.z was originally in "..." */ -#define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */ -#define EP_Collate 0x0100 /* Tree contains a TK_COLLATE opeartor */ -#define EP_FixedDest 0x0200 /* Result needed in a specific register */ -#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */ -#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */ -#define EP_Hint 0x1000 /* Not used */ -#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */ -#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */ -#define EP_Static 0x8000 /* Held in memory not obtained from malloc() */ +#define EP_FromJoin 0x000001 /* Originated in ON or USING clause of a join */ +#define EP_Agg 0x000002 /* Contains one or more aggregate functions */ +#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */ +#define EP_Error 0x000008 /* Expression contains one or more errors */ +#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ +#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ +#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ +#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ +#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */ +#define EP_FixedDest 0x000200 /* Result needed in a specific register */ +#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ +#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ +#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ +#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ +#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ +#define EP_Static 0x008000 /* Held in memory not obtained from malloc() */ +#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ +#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ +#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ /* -** The following are the meanings of bits in the Expr.flags2 field. +** These macros can be used to test, set, or clear bits in the +** Expr.flags field. */ -#define EP2_MallocedToken 0x0001 /* Need to sqlite3DbFree() Expr.zToken */ -#define EP2_Irreducible 0x0002 /* Cannot EXPRDUP_REDUCE this Expr */ +#define ExprHasProperty(E,P) (((E)->flags&(P))!=0) +#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) +#define ExprSetProperty(E,P) (E)->flags|=(P) +#define ExprClearProperty(E,P) (E)->flags&=~(P) -/* -** The pseudo-routine sqlite3ExprSetIrreducible sets the EP2_Irreducible -** flag on an expression structure. This flag is used for VV&A only. The -** routine is implemented as a macro that only works when in debugging mode, -** so as not to burden production code. +/* The ExprSetVVAProperty() macro is used for Verification, Validation, +** and Accreditation only. It works like ExprSetProperty() during VVA +** processes but is a no-op for delivery. */ #ifdef SQLITE_DEBUG -# define ExprSetIrreducible(X) (X)->flags2 |= EP2_Irreducible +# define ExprSetVVAProperty(E,P) (E)->flags|=(P) #else -# define ExprSetIrreducible(X) +# define ExprSetVVAProperty(E,P) #endif /* -** These macros can be used to test, set, or clear bits in the -** Expr.flags field. -*/ -#define ExprHasProperty(E,P) (((E)->flags&(P))==(P)) -#define ExprHasAnyProperty(E,P) (((E)->flags&(P))!=0) -#define ExprSetProperty(E,P) (E)->flags|=(P) -#define ExprClearProperty(E,P) (E)->flags&=~(P) - -/* ** Macros to determine the number of bytes required by a normal Expr ** struct, an Expr struct with the EP_Reduced flag set in Expr.flags ** and an Expr struct with the EP_TokenOnly flag set. @@ -3190,6 +3184,7 @@ int sqlite3VtabCallDestroy(sqlite3*, int, const char *); int sqlite3VtabBegin(sqlite3 *, VTable *); FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); +sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); int sqlite3Reprepare(Vdbe*); diff --git a/src/util.c b/src/util.c index d83a63015..7ccf2a1fd 100644 --- a/src/util.c +++ b/src/util.c @@ -193,7 +193,8 @@ int sqlite3Dequote(char *z){ case '[': quote = ']'; break; /* For MS SqlServer compatibility */ default: return -1; } - for(i=1, j=0; ALWAYS(z[i]); i++){ + for(i=1, j=0;; i++){ + assert( z[i] ); if( z[i]==quote ){ if( z[i+1]==quote ){ z[j++] = quote; diff --git a/src/vdbe.c b/src/vdbe.c index 70d06eb31..c75aadb19 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -567,6 +567,7 @@ int sqlite3VdbeExec( assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY ); assert( p->bIsReader || p->readOnly!=0 ); p->rc = SQLITE_OK; + p->iCurrentTime = 0; assert( p->explain==0 ); p->pResultSet = 0; db->busyHandler.nBusy = 0; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index a699c414b..3cac04016 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -350,6 +350,7 @@ struct Vdbe { #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif + i64 iCurrentTime; /* Value of julianday('now') for this statement */ i64 nFkConstraint; /* Number of imm. FK constraints this VM */ i64 nStmtDefCons; /* Number of def. constraints when stmt started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 52c6b2a79..d51256217 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -510,6 +510,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){ return rc; } + /* ** Extract the user data from a sqlite3_context structure and return a ** pointer to it. @@ -535,6 +536,19 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ } /* +** Return the current time for a statement +*/ +sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ + Vdbe *v = p->pVdbe; + int rc; + if( v->iCurrentTime==0 ){ + rc = sqlite3OsCurrentTimeInt64(p->s.db->pVfs, &v->iCurrentTime); + if( rc ) v->iCurrentTime = 0; + } + return v->iCurrentTime; +} + +/* ** The following is the implementation of an SQL function that always ** fails with an error message stating that the function is used in the ** wrong context. The sqlite3_overload_function() API might construct diff --git a/src/vdbeaux.c b/src/vdbeaux.c index bb67c6da3..d2e495ea1 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2436,6 +2436,7 @@ int sqlite3VdbeReset(Vdbe *p){ } } #endif + p->iCurrentTime = 0; p->magic = VDBE_MAGIC_INIT; return p->rc & db->errMask; } diff --git a/src/walker.c b/src/walker.c index e71ed2ac4..cde34ad78 100644 --- a/src/walker.c +++ b/src/walker.c @@ -43,7 +43,7 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ testcase( ExprHasProperty(pExpr, EP_Reduced) ); rc = pWalker->xExprCallback(pWalker, pExpr); if( rc==WRC_Continue - && !ExprHasAnyProperty(pExpr,EP_TokenOnly) ){ + && !ExprHasProperty(pExpr,EP_TokenOnly) ){ if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ diff --git a/src/where.c b/src/where.c index 3c8a1eaac..b8ec788bc 100644 --- a/src/where.c +++ b/src/where.c @@ -52,12 +52,13 @@ typedef struct WhereOrSet WhereOrSet; ** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The ** maximum cost for ordinary tables is 64*(2**63) which becomes 6900. ** (Virtual tables can return a larger cost, but let's assume they do not.) -** So all costs can be stored in a 16-bit unsigned integer without risk +** So all costs can be stored in a 16-bit integer without risk ** of overflow. ** ** Costs are estimates, so no effort is made to compute 10*log2(X) exactly. -** Instead, a close estimate is used. Any value of X<=1 is stored as 0. -** X=2 is 10. X=3 is 16. X=1000 is 99. etc. +** Instead, a close estimate is used. Any value of X=1 is stored as 0. +** X=2 is 10. X=3 is 16. X=1000 is 99. etc. Negative values are allowed. +** A WhereCost of -10 means 0.5. WhereCost of -20 means 0.25. And so forth. ** ** The tool/wherecosttest.c source file implements a command-line program ** that will convert WhereCosts to integers, convert integers to WhereCosts @@ -65,7 +66,7 @@ typedef struct WhereOrSet WhereOrSet; ** command-line program is a useful utility to have around when working with ** this module. */ -typedef unsigned short int WhereCost; +typedef short int WhereCost; /* ** This object contains information needed to implement a single nested @@ -106,6 +107,7 @@ struct WhereLevel { Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ + Bitmask notReady; /* FROM entries not usable at this level */ }; /* @@ -268,6 +270,7 @@ struct WhereTerm { WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; + WhereCost truthProb; /* Probability of truth for this expression */ u16 eOperator; /* A WO_xx value describing <op> */ u8 wtFlags; /* TERM_xxx bit flags. See below */ u8 nChild; /* Number of children that must disable us */ @@ -642,6 +645,9 @@ static void whereClauseClear(WhereClause *pWC){ } } +/* Forward declaration */ +static WhereCost whereCost(tRowcnt x); + /* ** Add a single new WhereTerm entry to the WhereClause object pWC. ** The new WhereTerm object is constructed from Expr p and with wtFlags. @@ -683,6 +689,11 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); } pTerm = &pWC->a[idx = pWC->nTerm++]; + if( p && ExprHasProperty(p, EP_Unlikely) ){ + pTerm->truthProb = whereCost(p->iTable) - 99; + }else{ + pTerm->truthProb = -1; + } pTerm->pExpr = sqlite3ExprSkipCollate(p); pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; @@ -2544,6 +2555,7 @@ static int whereRangeScanEst( ){ int rc = SQLITE_OK; int nOut = (int)*pnOut; + WhereCost nNew; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 Index *p = pBuilder->pNew->u.btree.pIndex; @@ -2606,6 +2618,7 @@ static int whereRangeScanEst( whereKeyStats(pParse, p, pRec, 0, a); iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; + nOut--; } } @@ -2620,12 +2633,12 @@ static int whereRangeScanEst( whereKeyStats(pParse, p, pRec, 1, a); iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0); if( iNew<iUpper ) iUpper = iNew; + nOut--; } } pBuilder->pRec = pRec; if( rc==SQLITE_OK ){ - WhereCost nNew; if( iUpper>iLower ){ nNew = whereCost(iUpper - iLower); }else{ @@ -2647,13 +2660,17 @@ static int whereRangeScanEst( assert( pLower || pUpper ); /* TUNING: Each inequality constraint reduces the search space 4-fold. ** A BETWEEN operator, therefore, reduces the search space 16-fold */ + nNew = nOut; if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){ - nOut -= 20; assert( 20==whereCost(4) ); + nNew -= 20; assert( 20==whereCost(4) ); + nOut--; } if( pUpper ){ - nOut -= 20; assert( 20==whereCost(4) ); + nNew -= 20; assert( 20==whereCost(4) ); + nOut--; } - if( nOut<10 ) nOut = 10; + if( nNew<10 ) nNew = 10; + if( nNew<nOut ) nOut = nNew; *pnOut = (WhereCost)nOut; return rc; } @@ -2799,6 +2816,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ if( pTerm && (pTerm->wtFlags & TERM_CODED)==0 && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) + && (pLevel->notReady & pTerm->prereqAll)==0 ){ pTerm->wtFlags |= TERM_CODED; if( pTerm->iParent>=0 ){ @@ -3224,7 +3242,6 @@ static Bitmask codeOneLoopStart( int addrCont; /* Jump here to continue with next cycle */ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ - Bitmask newNotReady; /* Return value */ pParse = pWInfo->pParse; v = pParse->pVdbe; @@ -3234,6 +3251,7 @@ static Bitmask codeOneLoopStart( pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; + pLevel->notReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0; @@ -3886,7 +3904,6 @@ static Bitmask codeOneLoopStart( pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } - newNotReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur); /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. @@ -3896,7 +3913,7 @@ static Bitmask codeOneLoopStart( testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & newNotReady)!=0 ){ + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ testcase( pWInfo->untestedTerms==0 && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); pWInfo->untestedTerms = 1; @@ -3928,7 +3945,7 @@ static Bitmask codeOneLoopStart( if( pLevel->iLeftJoin ) continue; pE = pTerm->pExpr; assert( !ExprHasProperty(pE, EP_FromJoin) ); - assert( (pTerm->prereqRight & newNotReady)!=0 ); + assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; @@ -3956,7 +3973,7 @@ static Bitmask codeOneLoopStart( testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & newNotReady)!=0 ){ + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ assert( pWInfo->untestedTerms ); continue; } @@ -3967,7 +3984,7 @@ static Bitmask codeOneLoopStart( } sqlite3ReleaseTempReg(pParse, iReleaseReg); - return newNotReady; + return pLevel->notReady; } #ifdef WHERETRACE_ENABLED @@ -4188,9 +4205,9 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ assert( p->rSetup==pTemplate->rSetup ); if( p->prereq==pTemplate->prereq && p->nLTerm<pTemplate->nLTerm - && (p->wsFlags & WHERE_INDEXED)!=0 - && (pTemplate->wsFlags & WHERE_INDEXED)!=0 - && p->u.btree.pIndex==pTemplate->u.btree.pIndex + && (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0 + && (p->u.btree.pIndex==pTemplate->u.btree.pIndex + || pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm) ){ /* Overwrite an existing WhereLoop with an similar one that uses ** more terms of the index */ @@ -4205,12 +4222,12 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ if( (p->prereq & pTemplate->prereq)==pTemplate->prereq && p->rRun>=pTemplate->rRun && p->nOut>=pTemplate->nOut - && ALWAYS(p->rSetup>=pTemplate->rSetup) /* See SETUP-INVARIANT above */ ){ /* Overwrite an existing WhereLoop with a better one: one that is ** better at one of (1) dependencies, (2) setup-cost, (3) run-cost ** or (4) number of output rows, and is no worse in any of those ** categories. */ + assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ pNext = p->pNextLoop; break; } @@ -4258,6 +4275,36 @@ whereLoopInsert_noop: } /* +** Adjust the WhereLoop.nOut value downward to account for terms of the +** WHERE clause that reference the loop but which are not used by an +** index. +** +** In the current implementation, the first extra WHERE clause term reduces +** the number of output rows by a factor of 10 and each additional term +** reduces the number of output rows by sqrt(2). +*/ +static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop, int iCur){ + WhereTerm *pTerm, *pX; + Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf); + int i, j; + + if( !OptimizationEnabled(pWC->pWInfo->pParse->db, SQLITE_AdjustOutEst) ){ + return; + } + for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){ + if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break; + if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue; + if( (pTerm->prereqAll & notAllowed)!=0 ) continue; + for(j=pLoop->nLTerm-1; j>=0; j--){ + pX = pLoop->aLTerm[j]; + if( pX==pTerm ) break; + if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; + } + if( j<0 ) pLoop->nOut += pTerm->truthProb; + } +} + +/* ** We have so far matched pBuilder->pNew->u.btree.nEq terms of the index pIndex. ** Try to match one more. ** @@ -4423,7 +4470,7 @@ static int whereLoopAddBtreeIndex( } /* Step cost for each output row */ pNew->rRun = whereCostAdd(pNew->rRun, pNew->nOut); - /* TBD: Adjust nOut for additional constraints */ + whereLoopOutputAdjust(pBuilder->pWC, pNew, pSrc->iCursor); rc = whereLoopInsert(pBuilder, pNew); if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEq<(pProbe->nColumn + (pProbe->zName!=0)) @@ -4627,7 +4674,9 @@ static int whereLoopAddBtree( ** index scans so that a covering index scan will be favored over ** a table scan. */ pNew->rRun = whereCostAdd(rSize,rLogSize) + 16; + whereLoopOutputAdjust(pWC, pNew, pSrc->iCursor); rc = whereLoopInsert(pBuilder, pNew); + pNew->nOut = rSize; if( rc ) break; }else{ Bitmask m = pSrc->colUsed & ~columnsInIndex(pProbe); @@ -4659,7 +4708,9 @@ static int whereLoopAddBtree( ** which we will simplify to just N*log2(N) */ pNew->rRun = rSize + rLogSize; } + whereLoopOutputAdjust(pWC, pNew, pSrc->iCursor); rc = whereLoopInsert(pBuilder, pNew); + pNew->nOut = rSize; if( rc ) break; } } @@ -5266,9 +5317,12 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ - WhereCost rCost; /* Cost of a path */ - WhereCost mxCost = 0; /* Maximum cost of a set of paths */ - WhereCost rSortCost; /* Cost to do a sort */ + int mxI = 0; /* Index of next entry to replace */ + WhereCost rCost; /* Cost of a path */ + WhereCost nOut; /* Number of outputs */ + WhereCost mxCost = 0; /* Maximum cost of a set of paths */ + WhereCost mxOut = 0; /* Maximum nOut value on the set of paths */ + WhereCost rSortCost; /* Cost to do a sort */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ @@ -5337,6 +5391,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ ** Compute its cost */ rCost = whereCostAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); rCost = whereCostAdd(rCost, pFrom->rCost); + nOut = pFrom->nRow + pWLoop->nOut; maskNew = pFrom->maskLoop | pWLoop->maskSelf; if( !isOrderedValid ){ switch( wherePathSatisfiesOrderBy(pWInfo, @@ -5359,7 +5414,11 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ } /* Check to see if pWLoop should be added to the mxChoice best so far */ for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){ - if( pTo->maskLoop==maskNew && pTo->isOrderedValid==isOrderedValid ){ + if( pTo->maskLoop==maskNew + && pTo->isOrderedValid==isOrderedValid + && ((pTo->rCost<=rCost && pTo->nRow<=nOut) || + (pTo->rCost>=rCost && pTo->nRow>=nOut)) + ){ testcase( jj==nTo-1 ); break; } @@ -5368,8 +5427,8 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ if( nTo>=mxChoice && rCost>=mxCost ){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("Skip %s cost=%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, + sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); } #endif @@ -5381,26 +5440,26 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ jj = nTo++; }else{ /* New path replaces the prior worst to keep count below mxChoice */ - for(jj=nTo-1; aTo[jj].rCost<mxCost; jj--){ assert(jj>0); } + jj = mxI; } pTo = &aTo[jj]; #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("New %s cost=%-3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, + sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); } #endif }else{ - if( pTo->rCost<=rCost ){ + if( pTo->rCost<=rCost && pTo->nRow<=nOut ){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Skip %s cost=%-3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, + "Skip %s cost=%-3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); - sqlite3DebugPrintf(" vs %s cost=%-3d order=%c\n", - wherePathName(pTo, iLoop+1, 0), pTo->rCost, + sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n", + wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } #endif @@ -5412,11 +5471,11 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Update %s cost=%-3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, + "Update %s cost=%-3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); - sqlite3DebugPrintf(" was %s cost=%-3d order=%c\n", - wherePathName(pTo, iLoop+1, 0), pTo->rCost, + sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n", + wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } #endif @@ -5424,16 +5483,22 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ /* pWLoop is a winner. Add it to the set of best so far */ pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; pTo->revLoop = revMask; - pTo->nRow = pFrom->nRow + pWLoop->nOut; + pTo->nRow = nOut; pTo->rCost = rCost; pTo->isOrderedValid = isOrderedValid; pTo->isOrdered = isOrdered; memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); pTo->aLoop[iLoop] = pWLoop; if( nTo>=mxChoice ){ + mxI = 0; mxCost = aTo[0].rCost; + mxOut = aTo[0].nRow; for(jj=1, pTo=&aTo[1]; jj<mxChoice; jj++, pTo++){ - if( pTo->rCost>mxCost ) mxCost = pTo->rCost; + if( pTo->rCost>mxCost || (pTo->rCost==mxCost && pTo->nRow>mxOut) ){ + mxCost = pTo->rCost; + mxOut = pTo->nRow; + mxI = jj; + } } } } @@ -5470,12 +5535,9 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ /* Find the lowest cost path. pFrom will be left pointing to that path */ pFrom = aFrom; - assert( nFrom==1 ); -#if 0 /* The following is needed if nFrom is ever more than 1 */ for(ii=1; ii<nFrom; ii++){ if( pFrom->rCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; } -#endif assert( pWInfo->nLevel==nLoop ); /* Load the lowest cost path into pWInfo */ for(iLoop=0; iLoop<nLoop; iLoop++){ |