Merge updates from trunk.
FossilOrigin-Name: 435ce3b3fc0cffb4d7e6f2694c3100066e19f9ed
This commit is contained in:
+1
-1
@@ -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];
|
||||
|
||||
+1
-1
@@ -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{
|
||||
|
||||
+4
-4
@@ -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);
|
||||
|
||||
+69
-49
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -2316,6 +2326,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".
|
||||
@@ -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;
|
||||
|
||||
+18
-16
@@ -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 ),
|
||||
|
||||
@@ -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);
|
||||
|
||||
+81
-50
@@ -108,6 +108,14 @@
|
||||
# define winIsDirSep(a) (((a) == '/') || ((a) == '\\'))
|
||||
#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.
|
||||
*/
|
||||
@@ -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));
|
||||
|
||||
+3
-2
@@ -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];
|
||||
|
||||
+439
-215
File diff suppressed because it is too large
Load Diff
+31
-4
@@ -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 ){
|
||||
|
||||
+4
-4
@@ -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;
|
||||
|
||||
+13
-9
@@ -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
|
||||
|
||||
+38
-43
@@ -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,50 +1767,45 @@ 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() */
|
||||
|
||||
/*
|
||||
** The following are the meanings of bits in the Expr.flags2 field.
|
||||
*/
|
||||
#define EP2_MallocedToken 0x0001 /* Need to sqlite3DbFree() Expr.zToken */
|
||||
#define EP2_Irreducible 0x0002 /* Cannot EXPRDUP_REDUCE this Expr */
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
# define ExprSetIrreducible(X) (X)->flags2 |= EP2_Irreducible
|
||||
#else
|
||||
# define ExprSetIrreducible(X)
|
||||
#endif
|
||||
#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 */
|
||||
|
||||
/*
|
||||
** 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 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 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 ExprSetVVAProperty(E,P) (E)->flags|=(P)
|
||||
#else
|
||||
# define ExprSetVVAProperty(E,P)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 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
|
||||
@@ -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*);
|
||||
|
||||
+2
-1
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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.
|
||||
@@ -534,6 +535,19 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
|
||||
return p->s.db;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
|
||||
@@ -2436,6 +2436,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p->iCurrentTime = 0;
|
||||
p->magic = VDBE_MAGIC_INIT;
|
||||
return p->rc & db->errMask;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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) ){
|
||||
|
||||
+104
-42
@@ -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;
|
||||
}
|
||||
@@ -4257,6 +4274,36 @@ whereLoopInsert_noop:
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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++){
|
||||
|
||||
Reference in New Issue
Block a user