More aggressive optimization of IS NULL and IS NOT NULL operators.
FossilOrigin-Name: c69eec9909af40e1e22d44a6859ef52378ebe06a587373f332f9d379cb39a84d
diff --git a/manifest b/manifest
index a562e38..65dcedb 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Create\sa\snew\sinternal\ssubroutine\sspecifically\sdesigned\sto\sallocate\nExpr\snodes\sthat\shold\sa\s32-bit\sinteger.
-D 2025-12-03T16:54:48.746
+C More\saggressive\soptimization\sof\sIS\sNULL\sand\sIS\sNOT\sNULL\soperators.
+D 2025-12-03T18:18:29.761
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -726,7 +726,7 @@
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
F src/pager.c a81461de271ac4886ad75b7ca2cca8157a48635820c4646cd2714acdc2c17e5f
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
-F src/parse.y 1af718c29a259a80cba96ab7e62ddc2d3f14b1242a1d176868f80c5d4f412e16
+F src/parse.y 6afdb006a4a8aac04a4dd37efd8b5e2d5cc39f9751b63e02cf11d9486ba3562a
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
@@ -2183,11 +2183,8 @@
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P afe5ee64f1cde4945c878220b029f2a22578c2bccda4fddc005c4e6a4718c6cd
-R c225aed59957640feafaa5b7a326af34
-T *branch * expr-opt
-T *sym-expr-opt *
-T -sym-trunk *
+P 38d06f69e516dd13becbfb735a2a0035c2f3c50ea5d661a668b109a996656523
+R e345b725a39db244a730c4ef212bf292
U drh
-Z 7b5c81060b54c05ccfb8538b780dea3f
+Z 8f73060af5100688a4299f0ba560aae8
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index d3f6455..0e54b44 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-38d06f69e516dd13becbfb735a2a0035c2f3c50ea5d661a668b109a996656523
+c69eec9909af40e1e22d44a6859ef52378ebe06a587373f332f9d379cb39a84d
diff --git a/src/parse.y b/src/parse.y
index 2b84b7a..8c11987 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -1363,43 +1363,67 @@
if( A ) A->flags |= EP_InfixFunc;
}
-expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExpr(pParse,@E,A,0);}
-expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExpr(pParse,TK_NOTNULL,A,0);}
-
%include {
- /* A routine to convert a binary TK_IS or TK_ISNOT expression into a
- ** unary TK_ISNULL or TK_NOTNULL expression. */
- static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
- sqlite3 *db = pParse->db;
- if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){
- pA->op = (u8)op;
- sqlite3ExprDelete(db, pA->pRight);
- pA->pRight = 0;
+ /* Create a TK_ISNULL or TK_NOTNULL expression, perhaps optimized to
+ ** to TK_TRUEFALSE, if possible */
+ static Expr *sqlite3PExprIsNull(
+ Parse *pParse, /* Parsing context */
+ int op, /* TK_ISNULL or TK_NOTNULL */
+ Expr *pLeft /* Operand */
+ ){
+ Expr *p = pLeft;
+ assert( op==TK_ISNULL || op==TK_NOTNULL );
+ assert( pLeft!=0 );
+ while( p->op==TK_UPLUS || p->op==TK_UMINUS ){
+ p = p->pLeft;
+ assert( p!=0 );
}
+ switch( p->op ){
+ case TK_INTEGER:
+ case TK_STRING:
+ case TK_FLOAT:
+ case TK_BLOB:
+ sqlite3ExprDeferredDelete(pParse, pLeft);
+ return sqlite3ExprInt32(pParse->db, op==TK_NOTNULL);
+ default:
+ break;
+ }
+ return sqlite3PExpr(pParse, op, pLeft, 0);
+ }
+
+ /* Create a TK_IS or TK_ISNOT operator, perhaps optimized to
+ ** TK_ISNULL or TK_NOTNULL or TK_TRUEFALSE. */
+ static Expr *sqlite3PExprIs(
+ Parse *pParse, /* Parsing context */
+ int op, /* TK_IS or TK_ISNOT */
+ Expr *pLeft, /* Left operand */
+ Expr *pRight /* Right operand */
+ ){
+ if( pRight && pRight->op==TK_NULL ){
+ sqlite3ExprDeferredDelete(pParse, pRight);
+ return sqlite3PExprIsNull(pParse, op==TK_IS ? TK_ISNULL : TK_NOTNULL, pLeft);
+ }
+ return sqlite3PExpr(pParse, op, pLeft, pRight);
}
}
-// expr1 IS expr2
-// expr1 IS NOT expr2
+expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExprIsNull(pParse,@E,A);}
+expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExprIsNull(pParse,TK_NOTNULL,A);}
+
+// expr1 IS expr2 same as expr1 IS NOT DISTICT FROM expr2
+// expr1 IS NOT expr2 same as expr1 IS DISTINCT FROM expr2
//
-// If expr2 is NULL then code as TK_ISNULL or TK_NOTNULL. If expr2
-// is any other expression, code as TK_IS or TK_ISNOT.
-//
expr(A) ::= expr(A) IS expr(Y). {
- A = sqlite3PExpr(pParse,TK_IS,A,Y);
- binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
+ A = sqlite3PExprIs(pParse, TK_IS, A, Y);
}
expr(A) ::= expr(A) IS NOT expr(Y). {
- A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
- binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
+ A = sqlite3PExprIs(pParse, TK_ISNOT, A, Y);
}
expr(A) ::= expr(A) IS NOT DISTINCT FROM expr(Y). {
- A = sqlite3PExpr(pParse,TK_IS,A,Y);
- binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
+ A = sqlite3PExprIs(pParse, TK_IS, A, Y);
}
expr(A) ::= expr(A) IS DISTINCT FROM expr(Y). {
- A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
- binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
+ A = sqlite3PExprIs(pParse, TK_ISNOT, A, Y);
}
expr(A) ::= NOT(B) expr(X).