1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-18 10:21:03 +03:00

Fix the code generated for vector IN operator constraints on virtual tables

so that they work even if the "omit" field in the sqlite3_index_info object
is off.  This has apparently never worked correctly before.  Presumably, nobody
has ever before written a virtual table that can use vector IN operator
constraints and that relies on bytecode to double-check the constraints.
Test cases in TH3.  Problem discovered by
dbsqlfuzz cab8e26194a40147627094f3c6849c0a7b1e0310.

FossilOrigin-Name: 21b656572d066b640ff5774205a4f0db13e1b08a35d0fd484da9130e759b0c26
This commit is contained in:
drh
2022-03-07 14:51:29 +00:00
parent c5a55db75d
commit 6d6ea42a25
3 changed files with 42 additions and 39 deletions

View File

@@ -1533,7 +1533,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
int iReg; /* P3 Value for OP_VFilter */
int addrNotFound;
int nConstraint = pLoop->nLTerm;
int iIn; /* Counter for IN constraints */
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
addrNotFound = pLevel->addrBrk;
@@ -1579,50 +1578,54 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
if( pLoop->wsFlags & WHERE_IN_ABLE ){
iIn = pLevel->u.in.nIn;
}else{
iIn = 0;
}
for(j=nConstraint-1; j>=0; j--){
int bIn; /* True to generate byte code to loop over RHS IN values */
for(j=0; j<nConstraint; j++){
pTerm = pLoop->aLTerm[j];
if( (pTerm->eOperator & WO_IN)!=0
&& (SMASKBIT32(j) & pLoop->u.vtab.mHandleIn)==0
){
bIn = 1;
}else{
bIn = 0;
}
if( bIn ) iIn--;
if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
disableTerm(pLevel, pTerm);
}else if( bIn && sqlite3ExprVectorSize(pTerm->pExpr->pLeft)==1 ){
continue;
}
if( (pTerm->eOperator & WO_IN)!=0
&& (SMASKBIT32(j) & pLoop->u.vtab.mHandleIn)==0
&& !db->mallocFailed
){
Expr *pCompare; /* The comparison operator */
Expr *pRight; /* RHS of the comparison */
VdbeOp *pOp; /* Opcode to access the value of the IN constraint */
int iIn; /* IN loop corresponding to the j-th constraint */
/* Reload the constraint value into reg[iReg+j+2]. The same value
** was loaded into the same register prior to the OP_VFilter, but
** the xFilter implementation might have changed the datatype or
** encoding of the value in the register, so it *must* be reloaded. */
assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
if( !db->mallocFailed ){
assert( iIn>=0 && iIn<pLevel->u.in.nIn );
** encoding of the value in the register, so it *must* be reloaded.
*/
for(iIn=0; ALWAYS(iIn<pLevel->u.in.nIn); iIn++){
pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[iIn].addrInTop);
assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
testcase( pOp->opcode==OP_Rowid );
sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
if( (pOp->opcode==OP_Column && pOp->p3==iReg+j+2)
|| (pOp->opcode==OP_Rowid && pOp->p2==iReg+j+2)
){
testcase( pOp->opcode==OP_Rowid );
sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
break;
}
}
/* Generate code that will continue to the next row if
** the IN constraint is not satisfied */
** the IN constraint is not satisfied
*/
pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
assert( pCompare!=0 || db->mallocFailed );
if( pCompare ){
pCompare->pLeft = pTerm->pExpr->pLeft;
if( !db->mallocFailed ){
int iFld = pTerm->u.x.iField;
Expr *pLeft = pTerm->pExpr->pLeft;
assert( pLeft!=0 );
if( iFld>0 ){
assert( pLeft->op==TK_VECTOR );
assert( ExprUseXList(pLeft) );
assert( iFld<=pLeft->x.pList->nExpr );
pCompare->pLeft = pLeft->x.pList->a[iFld-1].pExpr;
}else{
pCompare->pLeft = pLeft;
}
pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
if( pRight ){
pRight->iTable = iReg+j+2;
@@ -1631,11 +1634,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
);
}
pCompare->pLeft = 0;
sqlite3ExprDelete(db, pCompare);
}
sqlite3ExprDelete(db, pCompare);
}
}
assert( iIn==0 || db->mallocFailed );
/* These registers need to be preserved in case there is an IN operator
** loop. So we could deallocate the registers here (and potentially
** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems