1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-10 01:02:56 +03:00

Fix the LEFT JOIN strength reduction for IN operators in the WHERE clause.

Further simplifications and refinement of the algorithm.

FossilOrigin-Name: 96c72dde79d4069f6c2f81467a35b617633f86f7a7dcafbda991affdaa1f8537
This commit is contained in:
drh
2023-06-01 00:01:20 +00:00
parent d8cf688469
commit e411b69537
4 changed files with 73 additions and 22 deletions

View File

@@ -5991,6 +5991,20 @@ int sqlite3ExprImpliesExpr(
return 0;
}
/* This is a helper functino to impliesNotNullRow(). In this routine,
** set pWalker->eCode to one only if *both* of the input expressions
** separately have the implies-not-null-row property.
*/
static void bothImplyNotNullRow(Walker *pWalker, Expr *pE1, Expr *pE2){
if( pWalker->eCode==0 ){
sqlite3WalkExpr(pWalker, pE1);
if( pWalker->eCode ){
pWalker->eCode = 0;
sqlite3WalkExpr(pWalker, pE2);
}
}
}
/*
** This is the Expr node callback for sqlite3ExprImpliesNonNullRow().
** If the expression node requires that the table at pWalker->iCur
@@ -6030,7 +6044,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
case TK_OR:
case TK_AND:
/* Both sides of an AND or OR must separately imply non-NULL row.
/* Both sides of an AND or OR must separately imply non-null-row.
** Consider these cases:
** 1. NOT (x AND y)
** 2. x OR y
@@ -6039,22 +6053,37 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
*/
testcase( pExpr->op==TK_OR );
testcase( pExpr->op==TK_AND );
if( pWalker->eCode==0 ){
sqlite3WalkExpr(pWalker, pExpr->pLeft);
if( pWalker->eCode ){
pWalker->eCode = 0;
sqlite3WalkExpr(pWalker, pExpr->pRight);
}
}
bothImplyNotNullRow(pWalker, pExpr->pLeft, pExpr->pRight);
return WRC_Prune;
case TK_CASE:
case TK_IN:
case TK_BETWEEN:
testcase( pExpr->op==TK_CASE );
testcase( pExpr->op==TK_IN );
testcase( pExpr->op==TK_BETWEEN );
/* In "CASE x WHEN y THEN ..." the overall expression is non-null-row
** if either x or y is non-null-row. If the neither x nor y is
** non-null-row, assume the whole expression is not, to be safe. */
assert( ExprUseXList(pExpr) );
assert( pExpr->x.pList->nExpr>0 );
sqlite3WalkExpr(pWalker, pExpr->pLeft);
sqlite3WalkExpr(pWalker, pExpr->x.pList->a[0].pExpr);
return WRC_Prune;
case TK_IN:
/* Beware of "x NOT IN ()" and "x NOT IN (SELECT 1 WHERE false)",
** both of which can be true. But apart from these cases, if
** the left-hand side of the IN is NULL then the IN itself will be
** NULL. */
if( ExprUseXList(pExpr) && pExpr->x.pList->nExpr>0 ){
sqlite3WalkExpr(pWalker, pExpr->pLeft);
}
return WRC_Prune;
case TK_BETWEEN:
/* In "x NOT BETWEEN y AND z" either x must be non-null-row or else
** both y and z must be non-null row */
assert( ExprUseXList(pExpr) );
assert( pExpr->x.pList->nExpr==2 );
sqlite3WalkExpr(pWalker, pExpr->pLeft);
bothImplyNotNullRow(pWalker, pExpr->x.pList->a[0].pExpr,
pExpr->x.pList->a[1].pExpr);
return WRC_Prune;
/* Virtual tables are allowed to use constraints like x=NULL. So