From: drh <> Date: Mon, 7 Mar 2022 14:59:45 +0000 (+0000) Subject: Fix the code generated for vector IN operator constraints on virtual tables X-Git-Tag: version-3.38.1~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=312d0ec0a77ef672a60a121e4ce93733e8453d61;p=thirdparty%2Fsqlite.git 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: 4a2040d5c78f42b892a080ba086f6ab32f59bb9c31b897af40c4359cdb17b0e9 --- diff --git a/manifest b/manifest index 316982b352..7b53c82312 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\s.import\sproblem\sin\sthe\sCLI\sreported\sby\n[forum:/forumpost/72a024c957|forum\spost\s72a024c957]. -D 2022-03-07T01:28:13.580 +C Fix\sthe\scode\sgenerated\sfor\svector\sIN\soperator\sconstraints\son\svirtual\stables\nso\sthat\sthey\swork\seven\sif\sthe\s"omit"\sfield\sin\sthe\ssqlite3_index_info\sobject\nis\soff.\s\sThis\shas\sapparently\snever\sworked\scorrectly\sbefore.\s\sPresumably,\snobody\nhas\sever\sbefore\swritten\sa\svirtual\stable\sthat\scan\suse\svector\sIN\soperator\nconstraints\sand\sthat\srelies\son\sbytecode\sto\sdouble-check\sthe\sconstraints.\nTest\scases\sin\sTH3.\s\sProblem\sdiscovered\sby\ndbsqlfuzz\scab8e26194a40147627094f3c6849c0a7b1e0310. +D 2022-03-07T14:59:45.436 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -641,7 +641,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c 1471be86b34b8ce328c6c68d7e2ee667c7f801ddf83ff179bc5936700cf43aa7 F src/whereInt.h 15d2975c3b4c193c78c26674400a840da8647fe1777ae3b026e2d15937b38a03 -F src/wherecode.c dd0cdd1b2a0db4f52f8ac36ba4c2fb46eedacc2a833253bc445867cf54081e0f +F src/wherecode.c 84be340684393248b9f3ecbce9b87c8a6f818149b52302702ea0b8d2a9d51faf F src/whereexpr.c 2a71f5491798460c9590317329234d332d9eb1717cba4f3403122189a75c465e F src/window.c dfaec4abc6012cbc18e4a202ca3a5d5a0efcc4011d86a06d882ddaab8aedee4d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1944,10 +1944,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8083757606920151171530f337919553fa8ba902a51744d7b21eeba1558db9fa -Q +4c3a02600f10926da1f88ddbd457bb1486e6e02dee366b5cfc89e498a10daa6f -Q +bf9d1278846dce9255f9a11ddfc5dfac1acea2eadcb20816a19d59f7bccaec0f -R 019f54d2f127da970daad0bc2fb20027 +P d753285bcbb68bdf8f6d95a64af58b20ce6da9f048734fdb0ae49150eb7befd4 +Q +21b656572d066b640ff5774205a4f0db13e1b08a35d0fd484da9130e759b0c26 +R b984960188ad903efb662e97e056efd4 U drh -Z 6fea8bddc882893a47ea3bb1db9d8f05 +Z e343344889b797f3e11e78405c1e934e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a98b6dea17..51b34494be 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d753285bcbb68bdf8f6d95a64af58b20ce6da9f048734fdb0ae49150eb7befd4 \ No newline at end of file +4a2040d5c78f42b892a080ba086f6ab32f59bb9c31b897af40c4359cdb17b0e9 \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index 78350bb034..6944c3acd5 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -1525,7 +1525,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; @@ -1571,50 +1570,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; jaLTerm[j]; + if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){ + disableTerm(pLevel, pTerm); + continue; + } if( (pTerm->eOperator & WO_IN)!=0 && (SMASKBIT32(j) & pLoop->u.vtab.mHandleIn)==0 + && !db->mallocFailed ){ - 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 ){ 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 && iInu.in.nIn ); + ** encoding of the value in the register, so it *must* be reloaded. + */ + for(iIn=0; ALWAYS(iInu.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; @@ -1623,11 +1626,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