aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2025-07-01 12:43:13 +0000
committerdrh <>2025-07-01 12:43:13 +0000
commitd82c6a2cf7394354ed1a17ad26d42b02766bb0d2 (patch)
tree8e9ac89dfa2556a13d95f29190491c00e78f88cb /src
parent99f1aa03fb6cb417bd342b79ee09af61245c212f (diff)
downloadsqlite-d82c6a2cf7394354ed1a17ad26d42b02766bb0d2.tar.gz
sqlite-d82c6a2cf7394354ed1a17ad26d42b02766bb0d2.zip
When attempting to optimize "expr AND false" to "false" and
"expr IN ()" to "false", take care not to delete aggregate functions in the "expr" as doing so can change the meaning of the query. See [forum:/forumpost/f4878de3e7dd4764|forum thread f4878de3e7]. FossilOrigin-Name: 77397bd67d918db57d5ac545d6d963194806fdabcdaa8f822b6b09e4cfe8b715
Diffstat (limited to 'src')
-rw-r--r--src/expr.c2
-rw-r--r--src/parse.y19
2 files changed, 15 insertions, 6 deletions
diff --git a/src/expr.c b/src/expr.c
index 6cb9c2aa1..9ed0a121e 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1144,7 +1144,7 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
return pLeft;
}else{
u32 f = pLeft->flags | pRight->flags;
- if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse
+ if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse|EP_HasFunc))==EP_IsFalse
&& !IN_RENAME_OBJECT
){
sqlite3ExprDeferredDelete(pParse, pLeft);
diff --git a/src/parse.y b/src/parse.y
index a5691cad4..617eb7303 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -1429,12 +1429,21 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
** expr1 IN ()
** expr1 NOT IN ()
**
- ** simplify to constants 0 (false) and 1 (true), respectively,
- ** regardless of the value of expr1.
+ ** simplify to constants 0 (false) and 1 (true), respectively.
+ **
+ ** Except, do not apply this optimization if expr1 contains a function
+ ** because that function might be an aggregate (we don't know yet whether
+ ** it is or not) and if it is an aggregate, that could change the meaning
+ ** of the whole query.
*/
- sqlite3ExprUnmapAndDelete(pParse, A);
- A = sqlite3Expr(pParse->db, TK_STRING, N ? "true" : "false");
- if( A ) sqlite3ExprIdToTrueFalse(A);
+ Expr *pB = sqlite3Expr(pParse->db, TK_STRING, N ? "true" : "false");
+ if( pB ) sqlite3ExprIdToTrueFalse(pB);
+ if( !ExprHasProperty(A, EP_HasFunc) ){
+ sqlite3ExprUnmapAndDelete(pParse, A);
+ A = pB;
+ }else{
+ A = sqlite3PExpr(pParse, N ? TK_OR : TK_AND, pB, A);
+ }
}else{
Expr *pRHS = Y->a[0].pExpr;
if( Y->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && A->op!=TK_VECTOR ){