]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Tweaks to the sqlite3_vtab_in() interface.
authordrh <>
Tue, 1 Feb 2022 21:59:43 +0000 (21:59 +0000)
committerdrh <>
Tue, 1 Feb 2022 21:59:43 +0000 (21:59 +0000)
FossilOrigin-Name: 75040183b8e14f20bfedfdcc1a9fb968f2f0193bc698605d1b4791a3699b93d9

manifest
manifest.uuid
src/sqlite.h.in
src/vdbeapi.c
src/where.c

index 7b186939fd46fca475474c312aece5e64f43f022..6f0bf53a93c418d103c155abacbdf432f0c1982d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Index\sin\s2nd\sargument\sto\ssqlite3_vtab_in()\sshould\sbe\son\sthe\saConstraint[]\narray,\snot\sthe\sinternal\sarray\sof\sall\sconstraints.
-D 2022-02-01T16:30:57.444
+C Tweaks\sto\sthe\ssqlite3_vtab_in()\sinterface.
+D 2022-02-01T21:59:43.937
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -554,7 +554,7 @@ F src/resolve.c 24032ae57aec10df2f3fa2e20be0aae7d256bc704124b76c52d763440c7c0fe9
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c a6d2d4bed279d7fe4fcedaf297eaf6441e8e17c6e3947a32d24d23be52ac02f2
 F src/shell.c.in 2f58e6aa6b3d2012db32f1c5fa4591e9d12fd582904632b4fc8f57a382b98fd3
-F src/sqlite.h.in 0aed2b88e91d03314121cd1e546441e37513929793c3cf7584b5b7ce445a9128
+F src/sqlite.h.in 72f3e57c4c0b4284ab9238312f7fd797967cc43f44558a80469a3d9b86a7be2b
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h a95cb9ed106e3d39e2118e4dcc15a14faec3fa50d0093425083d340d9dfd96e6
 F src/sqliteInt.h 838df3e9ba9390058076d2f50c7efde9e0e8747303e788cf5bbe05402ab10924
@@ -627,7 +627,7 @@ F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
 F src/vdbe.c d6694187a2819df7c2df3bd568fd059617c3edef4aa87e28a8121b02818f4ebf
 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
 F src/vdbeInt.h 24d58f12f642dcac102fa75d08e99ad06b6cbc66bf4948bb61e2e223ef9518b6
-F src/vdbeapi.c 4d26cc9eb1a0f937e8d360578dc56d00145bac08afd503ba6ac843007f7d8c1f
+F src/vdbeapi.c 84e7e8d161c8fb7259eaa5fe7234f2334ef9fb013674ce34705b56166052b5fa
 F src/vdbeaux.c e761b8011baec7a4773f0a7594783f2cd71f699ab187c4aad917529ab8acd3fe
 F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
 F src/vdbemem.c eb6042667c02c3ef1f968235b4a170e31b23a4b6a57f65a8454eab4d36f14b7f
@@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
 F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
-F src/where.c cbf02091ed71784f7972ca39aaecb22822781f3b96905ece1a30e80161629769
+F src/where.c 392d552fa6636e94d242954247e277eb9b0d9c45446afb0c0a57f8c6fcb3f792
 F src/whereInt.h 1d821657238a0bd12b3c8f2926c7f8f9294bc5efe20af53c7c50d53a0a026cb9
 F src/wherecode.c 5879604677f0bdfb8d95ff616d834daecc12256346b7d9ad96a7e84a1cb08fdc
 F src/whereexpr.c ddb6ab49f745154c37dbdb291433c933e00175929647290a11f487af701d0392
@@ -1942,8 +1942,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 eb84b80e1f6d8c32bf0c9e1731f0233de0160a13f714f766779ae01fdf504e7b
-R 320e3be3dedfcb44854348cea4a95b96
+P 5acf90a931b27b7d627c0a8fee68170430e09b028d6643b959b0ec14fd59f7ac
+R e3dc8c48dc1f78fd77820f7d72429762
 U drh
-Z 4a8e49183eb36a5777c7e6fa2fd8d0f2
+Z 89712fde261ff7ce2e71753d08fff668
 # Remove this line to create a well-formed Fossil manifest.
index 93bc0e7791848a94f2fae7cde866704d82826037..bfff22a8a9d6fd72fca81cfefbb66b888b5a7c73 100644 (file)
@@ -1 +1 @@
-5acf90a931b27b7d627c0a8fee68170430e09b028d6643b959b0ec14fd59f7ac
\ No newline at end of file
+75040183b8e14f20bfedfdcc1a9fb968f2f0193bc698605d1b4791a3699b93d9
\ No newline at end of file
index 40aa917757c5bf0cee47311f32a0fc10d9270b15..e8122912eefc2a554c0f6c3dc3ecbb5db0dce664 100644 (file)
@@ -9607,72 +9607,94 @@ int sqlite3_vtab_distinct(sqlite3_index_info*);
 /*
 ** CAPI3REF: Identify and handle IN(...) constraints in xBestIndex
 **
-** This API may only be used from within an xBestIndex() callback. The
-** results of calling it from outside of an xBestIndex() callback are
-** undefined.
+** This interface may only be used from within an 
+** [xBestIndex|xBestIndex() method of a [virtual table] implementation.
+** The result of invoking this interface from any other context is
+** undefined and probably harmful.
+**
+** A constraint on a virtual table of the form "column IN (...)" is
+** communicated to the xBestIndex method as a
+** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.  If xBestIndex wants to use
+** this constraint, it must set the corresponding
+** aConstraintUsage[].argvIndex to a postive integer.  Then, under
+** the usual mode of handling IN operators, SQLite generate bytecode
+** that invokes the [xFilter|xFilter() method] once for each value
+** on the right-hand side of the IN operator.  Thus the virtual table
+** only sees a single value from the right-hand side of the IN operator
+** at a time.
+**
+** In some cases, however, it would be advantageous for the virtual
+** table to see all values on the right-hand of the IN operator all at
+** once.  The sqlite3_vtab_in() interfaces facilitates this in two ways:
 **
-** When a column of a virtual table is subject to a "col IN (...)" 
-** constraint, this is passed through to the xBestIndex method of the
-** virtual table as an SQLITE_INDEX_CONSTRAINT_EQ constraint. Then, if
-** the virtual table indicates that it can handle the constraint, SQLite
-** uses the xFilter and xNext methods of the virtual table to query
-** separately for each distinct element in RHS of the IN(...) expression.
-** This API allows a virtual table implementation to determine which 
-** SQLITE_INDEX_CONSTRAINT_EQ constraints are actually IN(...) constraints,
-** and to handle them using a single xFilter scan.
-** 
-** If the second argument passed to this function is not the index of an
-** SQLITE_INDEX_CONSTRAINT_EQ constraint in the aConstraint[] array of the
-** sqlite3_index_info object, or if the SQLITE_INDEX_CONSTRAINT_EQ is not
-** really an IN(...) expression, then this function is a no-op. Zero is
-** returned in this case.
-**
-** Otherwise, if parameter iCons is the index of an SQLITE_INDEX_CONSTRAINT_EQ
-** constraint that is really an IN(...) expression, then this function
-** returns non-zero. In this case, the call also specifies whether SQLite 
-** should invoke xFilter() once for each element on the RHS of the IN(...)
-** expression (the default, if bHandle is zero), or just once for the entire
-** list (if bHandle is non-zero), should the associated 
-** aConstraintUsage[].argvIndex variable be set by xBestIndex.
-**
-** In cases where the list on the RHS of an IN(...) constraint is passed to a
-** single xFilter() call, the (sqlite3_value*) passed appears in most
-** respects to be a NULL value. Except, it may be used with the
-** sqlite3_vtab_in_first() and sqlite3_vtab_in_next() APIs to interate through
-** the list of values.
-*/
-int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
-
-/*
-** CAPI3REF: Visit the first element of an IN(...) list passed to xFilter
+** <ol>
+** <li><p>
+**   A call to sqlite3_vtab_in(P,I,-1) will return true (non-zero)
+**   if and only if the I-th constraint in P->aConstraint[] is
+**   an IN operator that can be processed all at once.  In other words,
+**   sqlite3_vtab_in() with -1 in the third argument is a mechanism
+**   by which the virtual table can ask SQLite if all-at-once processing
+**   of the IN operator is even possible.
+**
+** <li><p>
+**   A call to sqlite3_vtab_in(P,I,F) with F set to 1 or 0 indicates
+**   to SQLite that the virtual table does or does not want to process
+**   the IN operator all-at-once.  Thus when the third parameter (F) is
+**   non-negative, this interface is the mechanism by which the virtual
+**   table tells SQLite how it wants to process in IN operator.
+** </ol>
 **
-** This API may only be used from within an xFilter() callback. The
-** results of calling it from outside of an xFilter() callback are
-** undefined.
+** The sqlite3_vtab_in(P,I,F) interface can be invoked multiple times
+** within the same xBestIndex method call.  For any given P and I parameters,
+** the return value from sqlite3_vtab_in(P,I,F) will always be the same
+** for every invocation within the same xBestIndex call.  If the interface
+** returns true (non-zero), that means that the constraint is an IN operator
+** that can be processed all-at-once.  If the constraint is not an IN
+** operator or cannot be processed all-at-once, then the interface returns
+** false.
 **
-** If the (sqlite3_value*) passed as the first argument to this function
-** is not a value representing the RHS of an IN(...) operator (see
-** API function sqlite3_vtab_in()), of if the RHS of the IN(...) operator
-** is an empty set, this function sets (*ppOut) to NULL and returns 
-** SQLITE_OK. 
+** All-at-once processing of the IN operator is selected if both of the
+** following conditions are met:
 **
-** Otherwise, if no error occurs, it sets (*ppOut) to point to an object
-** containing the first value in the list and returns SQLITE_OK. The
-** pointer is valid until either the xFilter() call returns or until the 
-** next call to sqlite3_vtab_in_first() or sqlite3_vtab_in_next() with
-** the same first argument.
+** <ol>
+** <li><p> The P->aConstraintUsage[I].argvIndex value is set to a positive
+** integer.  This is how the virtual table tells SQLite that it wants to
+** use the I-th constraint.
 **
-** If an error occurs, (*ppOut) is set to NULL and an SQLite error code
-** returned.
+** <li><p> The last call to sqlite3_vtab_in(P,I,F) for which F was
+** non-negative had F>=1.
+** </ol>
+** 
+** If either or both of the conditions above are false, then uses the
+** traditional one-at-a-time processing strategy for IN constraint.
+** If both conditions are true, then the argvIndex-th parameter to the
+** xFilter method will be an [sqlite3_value] that appears to be NULL,
+** but which can be passed to [sqlite3_vtab_in_first()] and
+** [sqlite3_vtab_in_next()] to find all values on the right-hand side
+** of the IN constraint.
 */
-int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
+int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
 
 /*
-** CAPI3REF: Visit the next element of an IN(...) list passed to xFilter
+** CAPI3REF: Find all elements on the right-hand side of an IN constraint.
 **
-** This function is called after a successful call to sqlite3_vtab_in_first()
-** to visit the next and subsequent elements of an IN(...) list passed
-** to an xFilter callback. Example usage:
+** These interfaces are only useful from within the
+** [xFilter|xFilter() method] of a virtual table implementation.
+** The result of invoking these interfaces from any other context
+** is undefined and probably harmful.
+**
+** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
+** sqlite3_vtab_in_next(X,P) must be one of the parameters to the
+** xFilter method which invokes those routines, and specifically
+** a parameter that was previously selected for all-at-once IN constraint
+** processing use the [sqlite3_vtab_in()] interface in the
+** [xBestIndex|xBestIndex method].  If the X parameter is not
+** an xFilter argument that was selected for all-at-once IN constraint
+** processing, then these routines return SQLITE_MISUSE or perhaps
+** exhibit some other undefined or harmful behavior.
+**
+** Use these routines to access all values on the right-hand side
+** of the IN constraint using code like the following:
 **
 ** <pre>
 **   for(rc=sqlite3_vtab_in_first(pList, &pVal);
@@ -9685,7 +9707,15 @@ int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
 **     // an error has occurred
 **   }
 ** </pre>
+**
+** On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P)
+** routines return SQLITE_OK and set *P to point to the first or next value
+** on the RHS of the IN constraint.  If there are no more values on the
+** right hand side of the IN constraint, then *P is set to NULL and these
+** routines return [SQLITE_DONE].  The return value might be
+** some other value, such as SQLITE_NOMEM, in the event of a malfunction.
 */
+int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
 int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut);
 
 /*
index 1521eee79b05058f53959d359fa59c89f695b653..46b466b6bbe6fc33ee911b77f65a5ab5b2175057 100644 (file)
@@ -888,21 +888,21 @@ static int vtabInLoadValue(sqlite3_value *pVal, sqlite3_value **ppOut){
 ** sqlite3_vtab_in_next() (if bNext!=0).
 */
 static int vtabInOp(sqlite3_value *pVal, sqlite3_value **ppOut, int bNext){
-  int rc = SQLITE_OK;
+  int rc;
+  BtCursor *pCsr;
   *ppOut = 0;
-  if( pVal && pVal->uTemp==SQLITE_VTAB_IN_MAGIC ){
-    BtCursor *pCsr = (BtCursor*)pVal->z;
-
-    if( bNext ){
-      rc = sqlite3BtreeNext(pCsr, 0);
-    }else{
-      int dummy = 0;
-      rc = sqlite3BtreeFirst(pCsr, &dummy);
-    }
-
-    if( rc==SQLITE_OK && sqlite3BtreeEof(pCsr)==0 ){
-      rc = vtabInLoadValue(pVal, ppOut);
-    }
+  if( pVal==0 ) return SQLITE_MISUSE;
+  if( pVal->uTemp!=SQLITE_VTAB_IN_MAGIC ) return SQLITE_MISUSE;
+  pCsr = (BtCursor*)pVal->z;
+  if( bNext ){
+    rc = sqlite3BtreeNext(pCsr, 0);
+  }else{
+    int dummy = 0;
+    rc = sqlite3BtreeFirst(pCsr, &dummy);
+    if( rc==SQLITE_OK && sqlite3BtreeEof(pCsr) ) rc = SQLITE_DONE;
+  }
+  if( rc==SQLITE_OK ){
+    rc = vtabInLoadValue(pVal, ppOut);
   }
   return rc;
 }
index 4f65e934fc549138836b32408746d22e7b7dbea3..169c4ccf14b425427e1e00c1441cc875e5b3a792 100644 (file)
@@ -3605,7 +3605,7 @@ static int whereLoopAddVirtualOne(
         }
       }
       if( SMASKBIT32(i) & pHidden->mHandleIn ){ 
-        pNew->u.vtab.mHandleIn |= SMASKBIT32(iTerm);
+        pNew->u.vtab.mHandleIn |= MASKBIT32(iTerm);
       }else if( (pTerm->eOperator & WO_IN)!=0 ){
         /* A virtual table that is constrained by an IN clause may not
         ** consume the ORDER BY clause because (1) the order of IN terms
@@ -3715,7 +3715,7 @@ int sqlite3_vtab_in(sqlite3_index_info *pIdxInfo, int iCons, int bHandle){
   if( m & pHidden->mIn ){
     if( bHandle==0 ){ 
       pHidden->mHandleIn &= ~m;
-    }else{
+    }else if( bHandle>0 ){
       pHidden->mHandleIn |= m;
     }
     return 1;