From: drh <> Date: Sat, 4 May 2024 15:04:45 +0000 (+0000) Subject: Assume that a function is able to return a subtype if either (1) it is itself X-Git-Tag: version-3.46.0~31^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2eb9adb564ee209e2f0ad38718d621ace1c55c72;p=thirdparty%2Fsqlite.git Assume that a function is able to return a subtype if either (1) it is itself marked with SQLITE_RESULT_SUBTYPE, or (2) one of its arguments is a function that is able to return a subtype. This check-in backs out the code changes from the previous two on this same branch, but keeps the test cases from the previous two. FossilOrigin-Name: f16b200f25a0ec59ad765d254d81c3ffdba21f79e6e82807a7b80d00627952e2 --- diff --git a/manifest b/manifest index 95c66ec418..0f9a114b45 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Functions\sthat\spass\sthrough\sthe\ssqlite3_value\sof\sone\sof\stheir\sarguments\smust\nalso\sbe\smarked\sas\sSQLITE_RESULT_SUBTYPE,\sin\scase\sone\sof\stheir\sarguments\shas\na\ssubtype. -D 2024-05-04T11:31:34.734 +C Assume\sthat\sa\sfunction\sis\sable\sto\sreturn\sa\ssubtype\sif\seither\s(1)\sit\sis\sitself\nmarked\swith\sSQLITE_RESULT_SUBTYPE,\sor\s(2)\sone\sof\sits\sarguments\sis\sa\sfunction\nthat\sis\sable\sto\sreturn\sa\ssubtype.\s\sThis\scheck-in\sbacks\sout\sthe\scode\schanges\nfrom\sthe\sprevious\stwo\son\sthis\ssame\sbranch,\sbut\skeeps\sthe\stest\scases\sfrom\nthe\sprevious\stwo. +D 2024-05-04T15:04:45.707 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -705,7 +705,7 @@ F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500 F src/expr.c 005bf7a088a2fb12a50752a2a1d40d423b8942e1920e93c3a1ba76da0bfbe52b F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00 -F src/func.c ee81e2fd91b93da5cee11f2abc1a197d32f037e00a8084d003a47e49b17a6c21 +F src/func.c 283d4f3b2751a1d9339fd93a8a013d1948fd5f4474a3cab0955eb4fafd445d0f F src/global.c 61a419dd9e993b9be0f91de4c4ccf322b053eb829868e089f0321dd669be3b90 F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 @@ -837,7 +837,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 -F src/where.c 0ef9638651b900d64d7e1e877af37cd7900159ff875547ec29b918a1497e5c9c +F src/where.c d235ba520b0147f60732b3bd411e119b43be33d348251edaa6e304a8ad52c511 F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8 F src/wherecode.c b9908c0a1aab095822a1e7032556bedc03b6d29641191e9ca535fb2307cd733d F src/whereexpr.c 67d15caf88a1a9528283d68ff578e024cf9fe810b517bb0343e5aaf695ad97dd @@ -2188,8 +2188,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cdd1610c44876623e629bb8e5779ea689e6d23c545552b088eca63ad2d1cf8da -R 33e55f0c34c1768cb20638651312a57f +P 2f9fba931d9f80b3d5dffb175180098756bccc6a8f665d7aaf8826970ab60d72 +R 14886039188c50fb101aa25afbe73592 U drh -Z 72ec691afb693a210c0cb7b3a98963ca +Z 80e41ac2288666eefe08d1c7b25daa7c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 34db1cbfb6..6c653e5a23 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2f9fba931d9f80b3d5dffb175180098756bccc6a8f665d7aaf8826970ab60d72 \ No newline at end of file +f16b200f25a0ec59ad765d254d81c3ffdba21f79e6e82807a7b80d00627952e2 \ No newline at end of file diff --git a/src/func.c b/src/func.c index 3c98ba96f5..18004984d9 100644 --- a/src/func.c +++ b/src/func.c @@ -984,7 +984,6 @@ static void nullifFunc( UNUSED_PARAMETER(NotUsed); if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){ sqlite3_result_value(context, argv[0]); - sqlite3_result_subtype(context, sqlite3_value_subtype(argv[0])); } } @@ -2609,11 +2608,11 @@ void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(rtrim, 2, 2, 0, trimFunc ), FUNCTION(trim, 1, 3, 0, trimFunc ), FUNCTION(trim, 2, 3, 0, trimFunc ), - FUNCTION2(min, -1, 0, 1, minmaxFunc, SQLITE_RESULT_SUBTYPE), + FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, 0, 0, 1, 0 ), WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), - FUNCTION2(max, -1, 1, 1, minmaxFunc, SQLITE_RESULT_SUBTYPE), + FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), @@ -2644,10 +2643,10 @@ void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ), FUNCTION(concat_ws, 0, 0, 0, 0 ), FUNCTION(concat_ws, 1, 0, 0, 0 ), - INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_RESULT_SUBTYPE), + INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), - FUNCTION2(nullif, 2, 0, 1, nullifFunc, SQLITE_RESULT_SUBTYPE), + FUNCTION(nullif, 2, 0, 1, nullifFunc ), DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), @@ -2726,8 +2725,8 @@ void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(pi, 0, 0, 0, piFunc ), #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ FUNCTION(sign, 1, 0, 0, signFunc ), - INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_RESULT_SUBTYPE), - INLINE_FUNC(iif, 3, INLINEFUNC_iif, SQLITE_RESULT_SUBTYPE), + INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ), + INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ), }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); diff --git a/src/where.c b/src/where.c index 820e922490..13a362dcca 100644 --- a/src/where.c +++ b/src/where.c @@ -5989,6 +5989,58 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( } } +/* +** Expression Node callback for sqlite3ExprCanReturnSubtype(). +** +** Only a function call is able to return a subtype. So if the node +** is not a function call, return WRC_Prune immediately. +** +** A function call is able to return a subtype if it has the +** SQLITE_RESULT_SUBTYPE property. +** +** Assume that every function is able to pass-through a subtype from +** one of its argument (using sqlite3_result_value()). Most functions +** are not this way, but we don't have a mechanism to distinguish those +** that are from those that are not, so assume they all work this way. +** That means that if one of its arguments is another function and that +** other function is able to return a subtype, then this function is +** able to return a subtype. +*/ +static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ + int n; + FuncDef *pDef; + sqlite3 *db; + if( pExpr->op!=TK_FUNCTION ){ + return WRC_Prune; + } + assert( ExprUseXList(pExpr) ); + db = pWalker->pParse->db; + n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; + pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); + if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ + pWalker->eCode = 1; + return WRC_Prune; + } + return WRC_Continue; +} + +/* +** Return TRUE if expression pExpr is able to return a subtype. +** +** A TRUE return does not guarantee that a subtype will be returned. +** It only indicates that a subtype return is possible. False positives +** are acceptable as they only disable an optimization. False negatives, +** on the other hand, can lead to incorrect answers. +*/ +static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){ + Walker w; + memset(&w, 0, sizeof(w)); + w.pParse = pParse; + w.xExprCallback = exprNodeCanReturnSubtype; + sqlite3WalkExpr(&w, pExpr); + return w.eCode; +} + /* ** The index pIdx is used by a query and contains one or more expressions. ** In other words pIdx is an index on an expression. iIdxCur is the cursor @@ -6022,19 +6074,11 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( continue; } if( sqlite3ExprIsConstant(0,pExpr) ) continue; - if( pExpr->op==TK_FUNCTION ){ + if( pExpr->op==TK_FUNCTION && sqlite3ExprCanReturnSubtype(pParse,pExpr) ){ /* Functions that might set a subtype should not be replaced by the ** value taken from an expression index since the index omits the ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */ - int n; - FuncDef *pDef; - sqlite3 *db = pParse->db; - assert( ExprUseXList(pExpr) ); - n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; - pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); - if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ - continue; - } + continue; } p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break;