aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c32
-rw-r--r--src/parse.y4
-rw-r--r--src/resolve.c2
-rw-r--r--src/sqliteInt.h3
4 files changed, 8 insertions, 33 deletions
diff --git a/src/expr.c b/src/expr.c
index f2b252792..9513e5ffd 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2550,38 +2550,17 @@ static int sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){
/*
** This routine examines sub-SELECT statements as an expression is being
-** walked as part of sqlite3ExprIsTableConstant() (hereafter IsTabConst()).
-** Most SELECT statements will cause IsTabConst() to return false. However,
-** if:
-**
-** (1) The SELECT is the right-hand side of an IN operator, and
-** (2) Nothing in the SELECT refers to anything other than itself
-**
-** Then this routine causes the sub-SELECT to be bypassed, so that if
-** nothing else is amiss the IsTabConst() routine can return true.
+** walked as part of sqlite3ExprIsTableConstant(). Sub-SELECTs are considered
+** constant as long as they are uncorrelated - meaning that they do not
+** contain any terms from outer contexts.
*/
static int exprSelectWalkTableConstant(Walker *pWalker, Select *pSelect){
- int savedCursor;
assert( pSelect!=0 );
assert( pWalker->eCode==3 || pWalker->eCode==0 );
- if( (pSelect->selFlags & SF_RhsOfIN)==0 ){
+ if( (pSelect->selFlags & SF_Correlated)!=0 ){
pWalker->eCode = 0;
return WRC_Abort;
}
- assert( pSelect->pSrc!=0 );
- assert( pSelect->pSrc->nSrc==1 );
- assert( pSelect->pWhere==0 );
- assert( pSelect->pGroupBy==0 );
- assert( pSelect->pHaving==0 );
- assert( pSelect->pOrderBy==0 );
- assert( pSelect->pPrior==0 );
- assert( pSelect->pNext==0 );
- assert( pSelect->pLimit==0 );
- assert( pSelect->pWith==0 );
- savedCursor = pWalker->u.iCur;
- pWalker->u.iCur = pSelect->pSrc->a[0].iCursor;
- sqlite3WalkExprList(pWalker, pSelect->pEList);
- pWalker->u.iCur = savedCursor;
return WRC_Prune;
}
@@ -2591,8 +2570,7 @@ static int exprSelectWalkTableConstant(Walker *pWalker, Select *pSelect){
** expression must not refer to any non-deterministic function nor any
** table other than iCur.
**
-** 2024-04-05: Operators of the form "expr IN table" are now allowed, where
-** "table" is the name of a table.
+** Enhanced on 2024-04-06: Allow pExpr to contain uncorrelated subqueries.
*/
static int sqlite3ExprIsTableConstant(Expr *p, int iCur){
Walker w;
diff --git a/src/parse.y b/src/parse.y
index 7a3d63766..d22c8e6fc 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -1369,10 +1369,6 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
if( E ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, E);
A = sqlite3PExpr(pParse, TK_IN, A, 0);
sqlite3PExprAddSelect(pParse, A, pSelect);
- if( pParse->nErr==0 ){
- assert( pSelect!=0 );
- pSelect->selFlags |= SF_RhsOfIN;
- }
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
expr(A) ::= EXISTS LP select(Y) RP. {
diff --git a/src/resolve.c b/src/resolve.c
index 6e0c9906a..7378addf5 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -1349,6 +1349,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
testcase( pNC->ncFlags & NC_PartIdx );
testcase( pNC->ncFlags & NC_IdxExpr );
testcase( pNC->ncFlags & NC_GenCol );
+ assert( pExpr->x.pSelect );
if( pNC->ncFlags & NC_SelfRef ){
notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr);
}else{
@@ -1357,6 +1358,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
+ pExpr->x.pSelect->selFlags |= SF_Correlated;
}
pNC->ncFlags |= NC_Subquery;
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 29acb570d..a735c445e 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3585,7 +3585,7 @@ struct Select {
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
-#define SF_RhsOfIN 0x20000000 /* Right-hand-side of an IN operator */
+#define SF_Correlated 0x20000000 /* True if references the outer context */
/* True if S exists and has SF_NestedFrom */
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
@@ -5082,7 +5082,6 @@ int sqlite3ExprTruthValue(const Expr*);
int sqlite3ExprIsConstant(Parse*,Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
-// int sqlite3ExprIsTableConstant(Expr*,int);
int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
int sqlite3ExprContainsSubquery(Expr*);