Tweaks to the sqlite3_vtab_in() interface.

FossilOrigin-Name: 75040183b8e14f20bfedfdcc1a9fb968f2f0193bc698605d1b4791a3699b93d9
This commit is contained in:
drh 2022-02-01 21:59:43 +00:00
parent a9f18f0172
commit b30298d3ea
5 changed files with 112 additions and 82 deletions

View File

@ -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.

View File

@ -1 +1 @@
5acf90a931b27b7d627c0a8fee68170430e09b028d6643b959b0ec14fd59f7ac
75040183b8e14f20bfedfdcc1a9fb968f2f0193bc698605d1b4791a3699b93d9

View 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.
**
** 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.
** 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:
**
** <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>
**
** 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.
**
** All-at-once processing of the IN operator is selected if both of the
** following conditions are met:
**
** <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.
**
** <li><p> The last call to sqlite3_vtab_in(P,I,F) for which F was
** non-negative had F>=1.
** </ol>
**
** 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.
** 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(sqlite3_index_info*, int iCons, int bHandle);
/*
** CAPI3REF: Visit the first element of an IN(...) list passed to xFilter
** CAPI3REF: Find all elements on the right-hand side of an IN constraint.
**
** This API may only be used from within an xFilter() callback. The
** results of calling it from outside of an xFilter() callback are
** undefined.
** 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.
**
** 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.
** 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.
**
** 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.
**
** If an error occurs, (*ppOut) is set to NULL and an SQLite error code
** returned.
*/
int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
/*
** CAPI3REF: Visit the next element of an IN(...) list passed to xFilter
**
** 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:
** 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);
/*

View 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;
}

View 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;