diff options
Diffstat (limited to 'src/whereexpr.c')
-rw-r--r-- | src/whereexpr.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/src/whereexpr.c b/src/whereexpr.c index 461c14af1..7a70b5445 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -199,7 +199,7 @@ static int isLikeOrGlob( ExprList *pList; /* List of operands to the LIKE operator */ int c; /* One character in z[] */ int cnt; /* Number of non-wildcard prefix characters */ - char wc[3]; /* Wildcard characters */ + char wc[4]; /* Wildcard characters */ sqlite3 *db = pParse->db; /* Database connection */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ @@ -246,16 +246,44 @@ static int isLikeOrGlob( return 0; } } + + /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; + if( c==wc[3] && z[cnt]!=0 ){ + if( z[cnt++]>0xc0 ) while( (z[cnt]&0xc0)==0x80 ){ cnt++; } + } } + + /* The optimization is possible only if (1) the pattern does not begin + ** with a wildcard and if (2) the non-wildcard prefix does not end with + ** an (illegal 0xff) character. The second condition is necessary so + ** that we can increment the prefix key to find an upper bound for the + ** range search. + */ if( cnt!=0 && 255!=(u8)z[cnt-1] ){ Expr *pPrefix; + + /* A "complete" match if the pattern ends with "*" or "%" */ *pisComplete = c==wc[0] && z[cnt+1]==0; + + /* Get the pattern prefix. Remove all escapes from the prefix. */ pPrefix = sqlite3Expr(db, TK_STRING, z); - if( pPrefix ) pPrefix->u.zToken[cnt] = 0; + if( pPrefix ){ + int iFrom, iTo; + char *zNew = pPrefix->u.zToken; + zNew[cnt] = 0; + for(iFrom=iTo=0; iFrom<cnt; iFrom++){ + if( zNew[iFrom]==wc[3] ) iFrom++; + zNew[iTo++] = zNew[iFrom]; + } + zNew[iTo] = 0; + } *ppPrefix = pPrefix; + + /* If the RHS pattern is a bound parameter, make arrangements to + ** reprepare the statement when that parameter is rebound */ if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeSetVarmask(v, pRight->iColumn); |