mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Refactor sqlite3_vtab_in() to make use of the existing
sqlite3_value_pointer() mechanism for passing the list of IN operator RHS values into xFilter, for improved memory safety. FossilOrigin-Name: 8965929be236fe1a6994f31b94c1b7590c7c1e809470c542a76f3e0e275d032f
This commit is contained in:
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Tweaks\sto\sthe\ssqlite3_vtab_in()\sinterface.
|
C Refactor\ssqlite3_vtab_in()\sto\smake\suse\sof\sthe\sexisting\nsqlite3_value_pointer()\smechanism\sfor\spassing\sthe\slist\sof\sIN\soperator\nRHS\svalues\sinto\sxFilter,\sfor\simproved\smemory\ssafety.
|
||||||
D 2022-02-01T21:59:43.937
|
D 2022-02-02T14:36:58.288
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@@ -624,10 +624,10 @@ F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
|
|||||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||||
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
|
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
|
||||||
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
|
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
|
||||||
F src/vdbe.c d6694187a2819df7c2df3bd568fd059617c3edef4aa87e28a8121b02818f4ebf
|
F src/vdbe.c 13a4de20ee07bdfb3dc74ab49b7912208e309caf762a8d1678fb111e2223af35
|
||||||
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
|
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
|
||||||
F src/vdbeInt.h 24d58f12f642dcac102fa75d08e99ad06b6cbc66bf4948bb61e2e223ef9518b6
|
F src/vdbeInt.h b45599a2b59f1ce042512ab6786b0b82a8cf3002f6b0fa60b4834e2cd3ac61d8
|
||||||
F src/vdbeapi.c 84e7e8d161c8fb7259eaa5fe7234f2334ef9fb013674ce34705b56166052b5fa
|
F src/vdbeapi.c a6ae9ef8180b2c51555cc96b8c5b928d45738a90f667a28a1959bcd09646643d
|
||||||
F src/vdbeaux.c e761b8011baec7a4773f0a7594783f2cd71f699ab187c4aad917529ab8acd3fe
|
F src/vdbeaux.c e761b8011baec7a4773f0a7594783f2cd71f699ab187c4aad917529ab8acd3fe
|
||||||
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
|
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
|
||||||
F src/vdbemem.c eb6042667c02c3ef1f968235b4a170e31b23a4b6a57f65a8454eab4d36f14b7f
|
F src/vdbemem.c eb6042667c02c3ef1f968235b4a170e31b23a4b6a57f65a8454eab4d36f14b7f
|
||||||
@@ -1942,8 +1942,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 5acf90a931b27b7d627c0a8fee68170430e09b028d6643b959b0ec14fd59f7ac
|
P 75040183b8e14f20bfedfdcc1a9fb968f2f0193bc698605d1b4791a3699b93d9
|
||||||
R e3dc8c48dc1f78fd77820f7d72429762
|
R 685a004fac313bda3614fce6fec3f1d8
|
||||||
U drh
|
U drh
|
||||||
Z 89712fde261ff7ce2e71753d08fff668
|
Z f2a69210d29b19f1b295e7a7f5450a22
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@@ -1 +1 @@
|
|||||||
75040183b8e14f20bfedfdcc1a9fb968f2f0193bc698605d1b4791a3699b93d9
|
8965929be236fe1a6994f31b94c1b7590c7c1e809470c542a76f3e0e275d032f
|
23
src/vdbe.c
23
src/vdbe.c
@@ -7736,20 +7736,27 @@ case OP_VOpen: {
|
|||||||
|
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
/* Opcode: VInitIn P1 P2 P3 * *
|
/* Opcode: VInitIn P1 P2 P3 * *
|
||||||
** Synopsis: r[P2]=cursor over eph table P1.
|
** Synopsis: r[P2]=ValueList(P1,P3)
|
||||||
**
|
**
|
||||||
** Initialize register P2 as a value that can be used as an iterator over
|
** Set register P2 to be a pointer to a ValueList object for cursor P1
|
||||||
** the contents of ephemeral table P1 by an xFilter callback implementation.
|
** with cache register P3 and output register P3+1. This ValueList object
|
||||||
** Register P3 is used as a cache by the iterator.
|
** can be used as the first argument to sqlite3_vtab_in_first() and
|
||||||
|
** sqlite3_vtab_in_next() to extract all of the values stored in the P1
|
||||||
|
** cursor. Register P3 is used to hold the values returned by
|
||||||
|
** sqlite3_vtab_in_first() and sqlite3_vtab_in_next().
|
||||||
*/
|
*/
|
||||||
case OP_VInitIn: { /* out2 */
|
case OP_VInitIn: { /* out2 */
|
||||||
VdbeCursor *pC;
|
VdbeCursor *pC; /* The cursor containing the RHS values */
|
||||||
|
ValueList *pRhs; /* New ValueList object to put in reg[P2] */
|
||||||
|
|
||||||
pC = p->apCsr[pOp->p1];
|
pC = p->apCsr[pOp->p1];
|
||||||
|
pRhs = sqlite3_malloc64( sizeof(*pRhs) );
|
||||||
|
if( pRhs==0 ) goto no_mem;
|
||||||
|
pRhs->pCsr = pC->uc.pCursor;
|
||||||
|
pRhs->pOut = &aMem[pOp->p3];
|
||||||
pOut = out2Prerelease(p, pOp);
|
pOut = out2Prerelease(p, pOp);
|
||||||
pOut->z = (char*)(pC->uc.pCursor);
|
|
||||||
pOut->u.pVal = &aMem[pOp->p3];
|
|
||||||
pOut->uTemp = SQLITE_VTAB_IN_MAGIC;
|
|
||||||
pOut->flags = MEM_Null;
|
pOut->flags = MEM_Null;
|
||||||
|
sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlite3_free);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||||
|
@@ -195,12 +195,6 @@ struct VdbeFrame {
|
|||||||
*/
|
*/
|
||||||
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
|
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
|
||||||
|
|
||||||
/* Magic number for Mem.uTemp when it is acting as as the cache for the
|
|
||||||
** IN(...) iterator for sqlite3_vtab_in_next()
|
|
||||||
*/
|
|
||||||
#define SQLITE_VTAB_IN_MAGIC 0xd3ab12ec
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Internally, the vdbe manipulates nearly all SQL values as Mem
|
** Internally, the vdbe manipulates nearly all SQL values as Mem
|
||||||
** structures. Each Mem struct may cache multiple representations (string,
|
** structures. Each Mem struct may cache multiple representations (string,
|
||||||
@@ -213,7 +207,6 @@ struct sqlite3_value {
|
|||||||
int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
|
int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
|
||||||
const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
|
const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
|
||||||
FuncDef *pDef; /* Used only when flags==MEM_Agg */
|
FuncDef *pDef; /* Used only when flags==MEM_Agg */
|
||||||
sqlite3_value *pVal;/* Current value for xFilter IN(...) iterator */
|
|
||||||
} u;
|
} u;
|
||||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||||
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
||||||
@@ -489,6 +482,24 @@ struct PreUpdate {
|
|||||||
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
|
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of this object is used to pass an vector of values into
|
||||||
|
** OP_VFilter, the xFilter method of a virtual table. The vector is the
|
||||||
|
** set of values on the right-hand side of an IN constraint.
|
||||||
|
**
|
||||||
|
** The value as passed into xFilter is an sqlite3_value with a "pointer"
|
||||||
|
** type, such as is generated by sqlite3_result_pointer() and read by
|
||||||
|
** sqlite3_value_pointer. Such values have MEM_Term|MEM_Subtype|MEM_Null
|
||||||
|
** and a subtype of 'p'. The sqlite3_vtab_in_first() and _next() interfaces
|
||||||
|
** know how to use this object to step through all the values in the
|
||||||
|
** right operand of the IN constraint.
|
||||||
|
*/
|
||||||
|
typedef struct ValueList ValueList;
|
||||||
|
struct ValueList {
|
||||||
|
BtCursor *pCsr; /* An ephemeral table holding all values */
|
||||||
|
sqlite3_value *pOut; /* Register to hold each decoded output value */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function prototypes
|
** Function prototypes
|
||||||
*/
|
*/
|
||||||
|
@@ -846,63 +846,48 @@ int sqlite3_vtab_nochange(sqlite3_context *p){
|
|||||||
return sqlite3_value_nochange(p->pOut);
|
return sqlite3_value_nochange(p->pOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** The first argument is an iterator value created by VDBE instruction
|
|
||||||
** OP_VInitIn. The iterator is guaranteed to point to a valid entry. This
|
|
||||||
** function attempts to load the current value from the iterator into
|
|
||||||
** object pVal->u.pVal. If successful, (*ppOut) is set to point to
|
|
||||||
** pVal->u.pVal and SQLITE_OK is returned. Otherwise, if an error
|
|
||||||
** occurs, an SQLite error code is returned and (*ppOut) is left unchanged.
|
|
||||||
*/
|
|
||||||
static int vtabInLoadValue(sqlite3_value *pVal, sqlite3_value **ppOut){
|
|
||||||
BtCursor *pCsr = (BtCursor*)pVal->z;
|
|
||||||
sqlite3_value *pOut = pVal->u.pVal;
|
|
||||||
int sz;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
sz = (int)sqlite3BtreePayloadSize(pCsr);
|
|
||||||
if( sz>pVal->szMalloc ){
|
|
||||||
if( pVal->szMalloc==0 ) pVal->zMalloc = 0;
|
|
||||||
pVal->zMalloc = sqlite3DbReallocOrFree(pVal->db, pVal->zMalloc, sz*2);
|
|
||||||
if( pVal->zMalloc ){
|
|
||||||
pVal->szMalloc = sqlite3DbMallocSize(pVal->db, pVal->zMalloc);
|
|
||||||
}else{
|
|
||||||
pVal->szMalloc = 0;
|
|
||||||
return SQLITE_NOMEM_BKPT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = sqlite3BtreePayload(pCsr, 0, sz, pVal->zMalloc);
|
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
u32 iSerial;
|
|
||||||
int iOff = 1 + getVarint32((const u8*)&pVal->zMalloc[1], iSerial);
|
|
||||||
sqlite3VdbeSerialGet((const u8*)&pVal->zMalloc[iOff], iSerial, pOut);
|
|
||||||
pOut->enc = ENC(pVal->db);
|
|
||||||
*ppOut = pOut;
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Implementation of sqlite3_vtab_in_first() (if bNext==0) and
|
** Implementation of sqlite3_vtab_in_first() (if bNext==0) and
|
||||||
** sqlite3_vtab_in_next() (if bNext!=0).
|
** sqlite3_vtab_in_next() (if bNext!=0).
|
||||||
*/
|
*/
|
||||||
static int vtabInOp(sqlite3_value *pVal, sqlite3_value **ppOut, int bNext){
|
static int valueFromValueList(
|
||||||
|
sqlite3_value *pVal, /* Pointer to the ValueList object */
|
||||||
|
sqlite3_value **ppOut, /* Store the next value from the list here */
|
||||||
|
int bNext /* 1 for _next(). 0 for _first() */
|
||||||
|
){
|
||||||
int rc;
|
int rc;
|
||||||
BtCursor *pCsr;
|
ValueList *pRhs;
|
||||||
|
|
||||||
*ppOut = 0;
|
*ppOut = 0;
|
||||||
if( pVal==0 ) return SQLITE_MISUSE;
|
if( pVal==0 ) return SQLITE_MISUSE;
|
||||||
if( pVal->uTemp!=SQLITE_VTAB_IN_MAGIC ) return SQLITE_MISUSE;
|
pRhs = (ValueList*)sqlite3_value_pointer(pVal, "ValueList");
|
||||||
pCsr = (BtCursor*)pVal->z;
|
if( pRhs==0 ) return SQLITE_MISUSE;
|
||||||
if( bNext ){
|
if( bNext ){
|
||||||
rc = sqlite3BtreeNext(pCsr, 0);
|
rc = sqlite3BtreeNext(pRhs->pCsr, 0);
|
||||||
}else{
|
}else{
|
||||||
int dummy = 0;
|
int dummy = 0;
|
||||||
rc = sqlite3BtreeFirst(pCsr, &dummy);
|
rc = sqlite3BtreeFirst(pRhs->pCsr, &dummy);
|
||||||
if( rc==SQLITE_OK && sqlite3BtreeEof(pCsr) ) rc = SQLITE_DONE;
|
if( rc==SQLITE_OK && sqlite3BtreeEof(pRhs->pCsr) ) rc = SQLITE_DONE;
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = vtabInLoadValue(pVal, ppOut);
|
u32 sz; /* Size of current row in bytes */
|
||||||
|
Mem sMem; /* Raw content of current row */
|
||||||
|
memset(&sMem, 0, sizeof(sMem));
|
||||||
|
sz = sqlite3BtreePayloadSize(pRhs->pCsr);
|
||||||
|
rc = sqlite3VdbeMemFromBtreeZeroOffset(pRhs->pCsr,(int)sz,&sMem);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
u8 *zBuf = (u8*)sMem.z;
|
||||||
|
u32 iSerial;
|
||||||
|
sqlite3_value *pOut = pRhs->pOut;
|
||||||
|
int iOff = 1 + getVarint32(&zBuf[1], iSerial);
|
||||||
|
sqlite3VdbeSerialGet(&zBuf[iOff], iSerial, pOut);
|
||||||
|
if( (pOut->flags & MEM_Ephem)!=0 && sqlite3VdbeMemMakeWriteable(pOut) ){
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
}else{
|
||||||
|
*ppOut = pOut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3VdbeMemRelease(&sMem);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -912,7 +897,7 @@ static int vtabInOp(sqlite3_value *pVal, sqlite3_value **ppOut, int bNext){
|
|||||||
** Set (*ppOut) to point to this value before returning.
|
** Set (*ppOut) to point to this value before returning.
|
||||||
*/
|
*/
|
||||||
int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut){
|
int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut){
|
||||||
return vtabInOp(pVal, ppOut, 0);
|
return valueFromValueList(pVal, ppOut, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -920,7 +905,7 @@ int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut){
|
|||||||
** Set (*ppOut) to point to this value before returning.
|
** Set (*ppOut) to point to this value before returning.
|
||||||
*/
|
*/
|
||||||
int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut){
|
int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut){
|
||||||
return vtabInOp(pVal, ppOut, 1);
|
return valueFromValueList(pVal, ppOut, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user