| Index: third_party/sqlite/src/src/whereexpr.c
|
| diff --git a/third_party/sqlite/src/src/whereexpr.c b/third_party/sqlite/src/src/whereexpr.c
|
| index 99a97079be378d654311847305e2b4cd93460208..826d329b7f1d8f91c942e053ef531e38815093b3 100644
|
| --- a/third_party/sqlite/src/src/whereexpr.c
|
| +++ b/third_party/sqlite/src/src/whereexpr.c
|
| @@ -64,7 +64,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
|
| if( pWC->nTerm>=pWC->nSlot ){
|
| WhereTerm *pOld = pWC->a;
|
| sqlite3 *db = pWC->pWInfo->pParse->db;
|
| - pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
|
| + pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
|
| if( pWC->a==0 ){
|
| if( wtFlags & TERM_DYNAMIC ){
|
| sqlite3ExprDelete(db, p);
|
| @@ -77,7 +77,6 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
|
| sqlite3DbFree(db, pOld);
|
| }
|
| pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
|
| - memset(&pWC->a[pWC->nTerm], 0, sizeof(pWC->a[0])*(pWC->nSlot-pWC->nTerm));
|
| }
|
| pTerm = &pWC->a[idx = pWC->nTerm++];
|
| if( p && ExprHasProperty(p, EP_Unlikely) ){
|
| @@ -89,13 +88,15 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
|
| pTerm->wtFlags = wtFlags;
|
| pTerm->pWC = pWC;
|
| pTerm->iParent = -1;
|
| + memset(&pTerm->eOperator, 0,
|
| + sizeof(WhereTerm) - offsetof(WhereTerm,eOperator));
|
| return idx;
|
| }
|
|
|
| /*
|
| ** Return TRUE if the given operator is one of the operators that is
|
| ** allowed for an indexable WHERE clause term. The allowed operators are
|
| -** "=", "<", ">", "<=", ">=", "IN", and "IS NULL"
|
| +** "=", "<", ">", "<=", ">=", "IN", "IS", and "IS NULL"
|
| */
|
| static int allowedOp(int op){
|
| assert( TK_GT>TK_EQ && TK_GT<TK_GE );
|
| @@ -202,6 +203,7 @@ static int isLikeOrGlob(
|
| sqlite3 *db = pParse->db; /* Database connection */
|
| sqlite3_value *pVal = 0;
|
| int op; /* Opcode of pRight */
|
| + int rc; /* Result code to return */
|
|
|
| if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
|
| return 0;
|
| @@ -267,8 +269,9 @@ static int isLikeOrGlob(
|
| }
|
| }
|
|
|
| + rc = (z!=0);
|
| sqlite3ValueFree(pVal);
|
| - return (z!=0);
|
| + return rc;
|
| }
|
| #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
|
|
|
| @@ -288,7 +291,7 @@ static int isMatchOfColumn(
|
| Expr *pExpr, /* Test this expression */
|
| unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */
|
| ){
|
| - struct Op2 {
|
| + static const struct Op2 {
|
| const char *zOp;
|
| unsigned char eOp2;
|
| } aOp[] = {
|
| @@ -531,6 +534,7 @@ static void exprAnalyzeOrTerm(
|
| if( pOrInfo==0 ) return;
|
| pTerm->wtFlags |= TERM_ORINFO;
|
| pOrWc = &pOrInfo->wc;
|
| + memset(pOrWc->aStatic, 0, sizeof(pOrWc->aStatic));
|
| sqlite3WhereClauseInit(pOrWc, pWInfo);
|
| sqlite3WhereSplit(pOrWc, pExpr, TK_OR);
|
| sqlite3WhereExprAnalyze(pSrc, pOrWc);
|
| @@ -547,7 +551,7 @@ static void exprAnalyzeOrTerm(
|
| WhereAndInfo *pAndInfo;
|
| assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
|
| chngToIN = 0;
|
| - pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
|
| + pAndInfo = sqlite3DbMallocRawNN(db, sizeof(*pAndInfo));
|
| if( pAndInfo ){
|
| WhereClause *pAndWC;
|
| WhereTerm *pAndTerm;
|
| @@ -557,15 +561,17 @@ static void exprAnalyzeOrTerm(
|
| pOrTerm->wtFlags |= TERM_ANDINFO;
|
| pOrTerm->eOperator = WO_AND;
|
| pAndWC = &pAndInfo->wc;
|
| + memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic));
|
| sqlite3WhereClauseInit(pAndWC, pWC->pWInfo);
|
| sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND);
|
| sqlite3WhereExprAnalyze(pSrc, pAndWC);
|
| pAndWC->pOuter = pWC;
|
| - testcase( db->mallocFailed );
|
| if( !db->mallocFailed ){
|
| for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
|
| assert( pAndTerm->pExpr );
|
| - if( allowedOp(pAndTerm->pExpr->op) ){
|
| + if( allowedOp(pAndTerm->pExpr->op)
|
| + || pAndTerm->eOperator==WO_MATCH
|
| + ){
|
| b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
|
| }
|
| }
|
| @@ -728,7 +734,7 @@ static void exprAnalyzeOrTerm(
|
| }
|
| assert( pLeft!=0 );
|
| pDup = sqlite3ExprDup(db, pLeft, 0);
|
| - pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0);
|
| + pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0);
|
| if( pNew ){
|
| int idxNew;
|
| transferJoinMarkings(pNew, pExpr);
|
| @@ -780,12 +786,10 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
| pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
|
| if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
|
| pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
|
| - /* Since pLeft and pRight are both a column references, their collating
|
| - ** sequence should always be defined. */
|
| - zColl1 = ALWAYS(pColl) ? pColl->zName : 0;
|
| + zColl1 = pColl ? pColl->zName : 0;
|
| pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
|
| - zColl2 = ALWAYS(pColl) ? pColl->zName : 0;
|
| - return sqlite3StrICmp(zColl1, zColl2)==0;
|
| + zColl2 = pColl ? pColl->zName : 0;
|
| + return sqlite3_stricmp(zColl1, zColl2)==0;
|
| }
|
|
|
| /*
|
| @@ -820,7 +824,8 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
| ** in any index. Return TRUE (1) if pExpr is an indexed term and return
|
| ** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor
|
| ** number of the table that is indexed and *piColumn to the column number
|
| -** of the column that is indexed, or -2 if an expression is being indexed.
|
| +** of the column that is indexed, or XN_EXPR (-2) if an expression is being
|
| +** indexed.
|
| **
|
| ** If pExpr is a TK_COLUMN column reference, then this routine always returns
|
| ** true even if that particular column is not indexed, because the column
|
| @@ -828,6 +833,7 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
| */
|
| static int exprMightBeIndexed(
|
| SrcList *pFrom, /* The FROM clause */
|
| + int op, /* The specific comparison operator */
|
| Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
|
| Expr *pExpr, /* An operand of a comparison operator */
|
| int *piCur, /* Write the referenced table cursor number here */
|
| @@ -836,6 +842,17 @@ static int exprMightBeIndexed(
|
| Index *pIdx;
|
| int i;
|
| int iCur;
|
| +
|
| + /* If this expression is a vector to the left or right of a
|
| + ** inequality constraint (>, <, >= or <=), perform the processing
|
| + ** on the first element of the vector. */
|
| + assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE );
|
| + assert( TK_IS<TK_GE && TK_ISNULL<TK_GE && TK_IN<TK_GE );
|
| + assert( op<=TK_GE );
|
| + if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){
|
| + pExpr = pExpr->x.pList->a[0].pExpr;
|
| + }
|
| +
|
| if( pExpr->op==TK_COLUMN ){
|
| *piCur = pExpr->iTable;
|
| *piColumn = pExpr->iColumn;
|
| @@ -848,10 +865,10 @@ static int exprMightBeIndexed(
|
| for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| if( pIdx->aColExpr==0 ) continue;
|
| for(i=0; i<pIdx->nKeyCol; i++){
|
| - if( pIdx->aiColumn[i]!=(-2) ) continue;
|
| + if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
|
| if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
|
| *piCur = iCur;
|
| - *piColumn = -2;
|
| + *piColumn = XN_EXPR;
|
| return 1;
|
| }
|
| }
|
| @@ -896,6 +913,7 @@ static void exprAnalyze(
|
| Parse *pParse = pWInfo->pParse; /* Parsing context */
|
| sqlite3 *db = pParse->db; /* Database connection */
|
| unsigned char eOp2; /* op2 value for LIKE/REGEXP/GLOB */
|
| + int nLeft; /* Number of elements on left side vector */
|
|
|
| if( db->mallocFailed ){
|
| return;
|
| @@ -908,6 +926,7 @@ static void exprAnalyze(
|
| op = pExpr->op;
|
| if( op==TK_IN ){
|
| assert( pExpr->pRight==0 );
|
| + if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
|
| if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
| pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
|
| }else{
|
| @@ -924,6 +943,10 @@ static void exprAnalyze(
|
| prereqAll |= x;
|
| extraRight = x-1; /* ON clause terms may not be used with an index
|
| ** on left table of a LEFT JOIN. Ticket #3015 */
|
| + if( (prereqAll>>1)>=x ){
|
| + sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
|
| + return;
|
| + }
|
| }
|
| pTerm->prereqAll = prereqAll;
|
| pTerm->leftCursor = -1;
|
| @@ -934,18 +957,26 @@ static void exprAnalyze(
|
| Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
|
| Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
|
| u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
|
| - if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){
|
| +
|
| + if( pTerm->iField>0 ){
|
| + assert( op==TK_IN );
|
| + assert( pLeft->op==TK_VECTOR );
|
| + pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
|
| + }
|
| +
|
| + if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){
|
| pTerm->leftCursor = iCur;
|
| pTerm->u.leftColumn = iColumn;
|
| pTerm->eOperator = operatorMask(op) & opMask;
|
| }
|
| if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
|
| if( pRight
|
| - && exprMightBeIndexed(pSrc, pTerm->prereqRight, pRight, &iCur, &iColumn)
|
| + && exprMightBeIndexed(pSrc, op, pTerm->prereqRight, pRight, &iCur,&iColumn)
|
| ){
|
| WhereTerm *pNew;
|
| Expr *pDup;
|
| u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
|
| + assert( pTerm->iField==0 );
|
| if( pTerm->leftCursor>=0 ){
|
| int idxNew;
|
| pDup = sqlite3ExprDup(db, pExpr, 0);
|
| @@ -1006,7 +1037,7 @@ static void exprAnalyze(
|
| int idxNew;
|
| pNewExpr = sqlite3PExpr(pParse, ops[i],
|
| sqlite3ExprDup(db, pExpr->pLeft, 0),
|
| - sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
|
| + sqlite3ExprDup(db, pList->a[i].pExpr, 0));
|
| transferJoinMarkings(pNewExpr, pExpr);
|
| idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
| testcase( idxNew==0 );
|
| @@ -1091,7 +1122,7 @@ static void exprAnalyze(
|
| pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
|
| pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
|
| sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
|
| - pStr1, 0);
|
| + pStr1);
|
| transferJoinMarkings(pNewExpr1, pExpr);
|
| idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
|
| testcase( idxNew1==0 );
|
| @@ -1099,7 +1130,7 @@ static void exprAnalyze(
|
| pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
|
| pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
|
| sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
|
| - pStr2, 0);
|
| + pStr2);
|
| transferJoinMarkings(pNewExpr2, pExpr);
|
| idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
|
| testcase( idxNew2==0 );
|
| @@ -1119,7 +1150,7 @@ static void exprAnalyze(
|
| ** virtual tables. The native query optimizer does not attempt
|
| ** to do anything with MATCH functions.
|
| */
|
| - if( isMatchOfColumn(pExpr, &eOp2) ){
|
| + if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){
|
| int idxNew;
|
| Expr *pRight, *pLeft;
|
| WhereTerm *pNewTerm;
|
| @@ -1132,7 +1163,7 @@ static void exprAnalyze(
|
| if( (prereqExpr & prereqColumn)==0 ){
|
| Expr *pNewExpr;
|
| pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
|
| - 0, sqlite3ExprDup(db, pRight, 0), 0);
|
| + 0, sqlite3ExprDup(db, pRight, 0));
|
| idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
| testcase( idxNew==0 );
|
| pNewTerm = &pWC->a[idxNew];
|
| @@ -1149,6 +1180,59 @@ static void exprAnalyze(
|
| }
|
| #endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
|
| + /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create
|
| + ** new terms for each component comparison - "a = ?" and "b = ?". The
|
| + ** new terms completely replace the original vector comparison, which is
|
| + ** no longer used.
|
| + **
|
| + ** This is only required if at least one side of the comparison operation
|
| + ** is not a sub-select. */
|
| + if( pWC->op==TK_AND
|
| + && (pExpr->op==TK_EQ || pExpr->op==TK_IS)
|
| + && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1
|
| + && sqlite3ExprVectorSize(pExpr->pRight)==nLeft
|
| + && ( (pExpr->pLeft->flags & EP_xIsSelect)==0
|
| + || (pExpr->pRight->flags & EP_xIsSelect)==0)
|
| + ){
|
| + int i;
|
| + for(i=0; i<nLeft; i++){
|
| + int idxNew;
|
| + Expr *pNew;
|
| + Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i);
|
| + Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i);
|
| +
|
| + pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight);
|
| + transferJoinMarkings(pNew, pExpr);
|
| + idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC);
|
| + exprAnalyze(pSrc, pWC, idxNew);
|
| + }
|
| + pTerm = &pWC->a[idxTerm];
|
| + pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL; /* Disable the original */
|
| + pTerm->eOperator = 0;
|
| + }
|
| +
|
| + /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
|
| + ** a virtual term for each vector component. The expression object
|
| + ** used by each such virtual term is pExpr (the full vector IN(...)
|
| + ** expression). The WhereTerm.iField variable identifies the index within
|
| + ** the vector on the LHS that the virtual term represents.
|
| + **
|
| + ** This only works if the RHS is a simple SELECT, not a compound
|
| + */
|
| + if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
|
| + && pExpr->pLeft->op==TK_VECTOR
|
| + && pExpr->x.pSelect->pPrior==0
|
| + ){
|
| + int i;
|
| + for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
|
| + int idxNew;
|
| + idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
|
| + pWC->a[idxNew].iField = i+1;
|
| + exprAnalyze(pSrc, pWC, idxNew);
|
| + markTermAsChild(pWC, idxNew, idxTerm);
|
| + }
|
| + }
|
| +
|
| #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| /* When sqlite_stat3 histogram data is available an operator of the
|
| ** form "x IS NOT NULL" can sometimes be evaluated more efficiently
|
| @@ -1169,7 +1253,7 @@ static void exprAnalyze(
|
|
|
| pNewExpr = sqlite3PExpr(pParse, TK_GT,
|
| sqlite3ExprDup(db, pLeft, 0),
|
| - sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0);
|
| + sqlite3ExprAlloc(db, TK_NULL, 0, 0));
|
|
|
| idxNew = whereClauseInsert(pWC, pNewExpr,
|
| TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL);
|
| @@ -1190,6 +1274,8 @@ static void exprAnalyze(
|
| /* Prevent ON clause terms of a LEFT JOIN from being used to drive
|
| ** an index for tables to the left of the join.
|
| */
|
| + testcase( pTerm!=&pWC->a[idxTerm] );
|
| + pTerm = &pWC->a[idxTerm];
|
| pTerm->prereqRight |= extraRight;
|
| }
|
|
|
| @@ -1272,17 +1358,18 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
|
| ** tree.
|
| */
|
| Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
|
| - Bitmask mask = 0;
|
| + Bitmask mask;
|
| if( p==0 ) return 0;
|
| if( p->op==TK_COLUMN ){
|
| mask = sqlite3WhereGetMask(pMaskSet, p->iTable);
|
| return mask;
|
| }
|
| - mask = sqlite3WhereExprUsage(pMaskSet, p->pRight);
|
| - mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
|
| + assert( !ExprHasProperty(p, EP_TokenOnly) );
|
| + mask = p->pRight ? sqlite3WhereExprUsage(pMaskSet, p->pRight) : 0;
|
| + if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
|
| if( ExprHasProperty(p, EP_xIsSelect) ){
|
| mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
|
| - }else{
|
| + }else if( p->x.pList ){
|
| mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
|
| }
|
| return mask;
|
| @@ -1346,13 +1433,13 @@ void sqlite3WhereTabFuncArgs(
|
| pTab->zName, j);
|
| return;
|
| }
|
| - pColRef = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
|
| + pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
|
| if( pColRef==0 ) return;
|
| pColRef->iTable = pItem->iCursor;
|
| pColRef->iColumn = k++;
|
| pColRef->pTab = pTab;
|
| pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
|
| - sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
|
| + sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0));
|
| whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
|
| }
|
| }
|
|
|