]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Assume that a function is able to return a subtype if either (1) it is itself func-rw-subtype
authordrh <>
Sat, 4 May 2024 15:04:45 +0000 (15:04 +0000)
committerdrh <>
Sat, 4 May 2024 15:04:45 +0000 (15:04 +0000)
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

manifest
manifest.uuid
src/func.c
src/where.c

index 95c66ec418b3ca26ad2e00b400dc9f1991d44f1e..0f9a114b45dd9e7011e14402c06362eea833b657 100644 (file)
--- 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.
index 34db1cbfb6954ec2eb25419fabcbdfab4a4da895..6c653e5a23477812717b55f03a97d3945daade47 100644 (file)
@@ -1 +1 @@
-2f9fba931d9f80b3d5dffb175180098756bccc6a8f665d7aaf8826970ab60d72
\ No newline at end of file
+f16b200f25a0ec59ad765d254d81c3ffdba21f79e6e82807a7b80d00627952e2
\ No newline at end of file
index 3c98ba96f5ed9cd8ed5acaeb7cb3dedee6dee67c..18004984d983d07b3fc6ac986dc03bf89c1e8634 100644 (file)
@@ -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, ),
     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, ),
+    INLINE_FUNC(iif,             3, INLINEFUNC_iif,      ),
   };
 #ifndef SQLITE_OMIT_ALTERTABLE
   sqlite3AlterFunctions();
index 820e9224903ed1e2950bfec2e4db8867ee1c21a7..13a362dccab32c57b4c888b032d024265de9a64d 100644 (file)
@@ -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;