diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 30 | ||||
-rw-r--r-- | src/resolve.c | 30 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 | ||||
-rw-r--r-- | src/where.c | 45 |
4 files changed, 49 insertions, 59 deletions
diff --git a/src/expr.c b/src/expr.c index f35ac56f8..3c95136c5 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2480,20 +2480,20 @@ static void sqlite3ExprCodeIN( }else{ /* If the LHS is NULL, then the result is either false or NULL depending - ** on whether the RHS is empty or not, respectively. - */ - if( nVector==1 && sqlite3ExprCanBeNull(pExpr->pLeft) ){ - if( destIfNull==destIfFalse ){ - /* Shortcut for the common case where the false and NULL outcomes are - ** the same. */ - sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); - }else{ - int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); - VdbeCoverage(v); - sqlite3VdbeGoto(v, destIfNull); - sqlite3VdbeJumpHere(v, addr1); + ** on whether the RHS is empty or not, respectively. */ + if( destIfNull==destIfFalse ){ + for(i=0; i<nVector; i++){ + Expr *p = exprVectorField(pExpr->pLeft, i); + if( sqlite3ExprCanBeNull(p) ){ + sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull); + } } + }else if( nVector==1 && sqlite3ExprCanBeNull(pExpr->pLeft) ){ + int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + VdbeCoverage(v); + sqlite3VdbeGoto(v, destIfNull); + sqlite3VdbeJumpHere(v, addr1); } if( eType==IN_INDEX_ROWID ){ @@ -2501,7 +2501,7 @@ static void sqlite3ExprCodeIN( */ sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, r1); VdbeCoverage(v); - }else if( nVector>1 && eType==IN_INDEX_EPH ){ + }else if( nVector>1 && eType==IN_INDEX_EPH && destIfNull!=destIfFalse ){ int regNull = sqlite3GetTempReg(pParse); int r2 = sqlite3GetTempReg(pParse); int r3 = sqlite3GetTempReg(pParse); @@ -3494,7 +3494,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ } case TK_VECTOR: { - sqlite3ErrorMsg(pParse, "invalid use of row value (1)"); + sqlite3ErrorMsg(pParse, "invalid use of row value"); break; } diff --git a/src/resolve.c b/src/resolve.c index cb9f2fbaa..4d8873963 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -767,14 +767,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } if( pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1 ){ - if( !ExprHasProperty(pExpr, EP_VectorOk) && 0 ){ - sqlite3ErrorMsg(pParse, "invalid use of row value"); - }else{ - ExprSetProperty(pExpr, EP_Vector); - } - } - if( pExpr->op==TK_IN ){ - ExprSetProperty(pExpr->pLeft, EP_VectorOk); + ExprSetProperty(pExpr, EP_Vector); } } break; @@ -784,27 +777,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ break; } - case TK_BETWEEN: { - ExprSetProperty(pExpr->pLeft, EP_VectorOk); - ExprSetProperty(pExpr->x.pList->a[0].pExpr, EP_VectorOk); - ExprSetProperty(pExpr->x.pList->a[1].pExpr, EP_VectorOk); - break; - } - - case TK_EQ: case TK_NE: case TK_IS: case TK_ISNOT: - case TK_LE: case TK_LT: case TK_GE: case TK_GT: - { - ExprSetProperty(pExpr->pLeft, EP_VectorOk); - ExprSetProperty(pExpr->pRight, EP_VectorOk); - break; - }; - case TK_VECTOR: { - if( !ExprHasProperty(pExpr, EP_VectorOk) ){ - sqlite3ErrorMsg(pParse, "invalid use of row value"); - }else{ - ExprSetProperty(pExpr, EP_Vector); - } + ExprSetProperty(pExpr, EP_Vector); break; } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1f653c08f..7219732bc 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2327,8 +2327,7 @@ struct Expr { #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ #define EP_Alias 0x400000 /* Is an alias for a result set column */ -#define EP_VectorOk 0x800000 /* This expression may be a row value */ -#define EP_Vector 0x1000000/* This expression is a row value */ +#define EP_Vector 0x800000 /* This expression is a row value */ /* ** Combinations of two or more EP_* flags diff --git a/src/where.c b/src/where.c index 095891842..6c039c6b7 100644 --- a/src/where.c +++ b/src/where.c @@ -3477,20 +3477,38 @@ static i8 wherePathSatisfiesOrderBy( rev = revSet = 0; distinctColumns = 0; for(j=0; j<nColumn; j++){ - u8 bOnce; /* True to run the ORDER BY search loop */ + u8 bOnce = 1; /* True to run the ORDER BY search loop */ - /* Skip over == and IS and ISNULL terms. - ** (Also skip IN terms when doing WHERE_ORDERBY_LIMIT processing) - */ - if( j<pLoop->u.btree.nEq - && pLoop->nSkip==0 - && ((i = pLoop->aLTerm[j]->eOperator) & eqOpMask)!=0 - ){ - if( i & WO_ISNULL ){ - testcase( isOrderDistinct ); - isOrderDistinct = 0; + assert( j>=pLoop->u.btree.nEq + || (pLoop->aLTerm[j]==0)==(j<pLoop->nSkip) + ); + if( j<pLoop->u.btree.nEq && j>=pLoop->nSkip ){ + u16 eOp = pLoop->aLTerm[j]->eOperator; + + /* Skip over == and IS and ISNULL terms. (Also skip IN terms when + ** doing WHERE_ORDERBY_LIMIT processing). + ** + ** If the current term is a column of an ((?,?) IN (SELECT...)) + ** expression for which the SELECT returns more than one column, + ** check that it is the only column used by this loop. Otherwise, + ** if it is one of two or more, none of the columns can be + ** considered to match an ORDER BY term. */ + if( (eOp & eqOpMask)!=0 ){ + if( eOp & WO_ISNULL ){ + testcase( isOrderDistinct ); + isOrderDistinct = 0; + } + continue; + }else if( eOp & WO_IN ){ + Expr *pX = pLoop->aLTerm[j]->pExpr; + for(i=j+1; i<pLoop->u.btree.nEq; i++){ + if( pLoop->aLTerm[i]->pExpr==pX ){ + assert( (pLoop->aLTerm[i]->eOperator & WO_IN) ); + bOnce = 0; + break; + } + } } - continue; } /* Get the column number in the table (iColumn) and sort order @@ -3519,7 +3537,6 @@ static i8 wherePathSatisfiesOrderBy( /* Find the ORDER BY term that corresponds to the j-th column ** of the index and mark that ORDER BY term off */ - bOnce = 1; isMatch = 0; for(i=0; bOnce && i<nOrderBy; i++){ if( MASKBIT(i) & obSat ) continue; @@ -4012,7 +4029,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( pWInfo->nOBSat<=0 ){ pWInfo->nOBSat = 0; if( nLoop>0 ){ - Bitmask m; + Bitmask m = 0; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m); if( rc==pWInfo->pOrderBy->nExpr ){ |