aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c30
-rw-r--r--src/resolve.c30
-rw-r--r--src/sqliteInt.h3
-rw-r--r--src/where.c45
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 ){