From: drh <> Date: Wed, 3 Dec 2025 18:18:29 +0000 (+0000) Subject: More aggressive optimization of IS NULL and IS NOT NULL operators. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fexpr-opt;p=thirdparty%2Fsqlite.git More aggressive optimization of IS NULL and IS NOT NULL operators. FossilOrigin-Name: c69eec9909af40e1e22d44a6859ef52378ebe06a587373f332f9d379cb39a84d --- diff --git a/manifest b/manifest index a562e38b19..65dcedbe81 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.c a89b501fc195085c7d6c9eec7f5bd782625e94bb2a96b000f4d009703df1083f 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/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd 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 d3f6455321..0e54b44272 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -38d06f69e516dd13becbfb735a2a0035c2f3c50ea5d661a668b109a996656523 +c69eec9909af40e1e22d44a6859ef52378ebe06a587373f332f9d379cb39a84d diff --git a/src/parse.y b/src/parse.y index 2b84b7aa50..8c11987941 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1363,43 +1363,67 @@ expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] { 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).