diff options
author | drh <> | 2024-04-23 12:02:03 +0000 |
---|---|---|
committer | drh <> | 2024-04-23 12:02:03 +0000 |
commit | 14602eafa74c2551deeb606b8de2ff9e4190be46 (patch) | |
tree | 0e079a13bb88d899088fb19b8f321a587bb08622 /src | |
parent | 3ac612dd7d242c5ed0d23000b7cb212e75a10874 (diff) | |
parent | 0309fb919aef74ee2df3b87871c43da025cefeb4 (diff) | |
download | sqlite-14602eafa74c2551deeb606b8de2ff9e4190be46.tar.gz sqlite-14602eafa74c2551deeb606b8de2ff9e4190be46.zip |
Fix a problem with vector IN operators used with an index where the affinities
and collations for the various vector terms are different.
FossilOrigin-Name: 86e8c782e7494377de3c27b750cd83a7eb2302c1182ee2004d3864db50fca557
Diffstat (limited to 'src')
-rw-r--r-- | src/where.c | 58 |
1 files changed, 51 insertions, 7 deletions
diff --git a/src/where.c b/src/where.c index 95bea115d..39210ddb2 100644 --- a/src/where.c +++ b/src/where.c @@ -303,6 +303,42 @@ static Expr *whereRightSubexprIsColumn(Expr *p){ } /* +** Term pTerm is guaranteed to be a WO_IN term. It may be a component term +** of a vector IN expression of the form "(x, y, ...) IN (SELECT ...)". +** This function checks to see if the term is compatible with an index +** column with affinity idxaff (one of the SQLITE_AFF_XYZ values). If so, +** it returns a pointer to the name of the collation sequence (e.g. "BINARY" +** or "NOCASE") used by the comparison in pTerm. If it is not compatible +** with affinity idxaff, NULL is returned. +*/ +static SQLITE_NOINLINE const char *indexInAffinityOk( + Parse *pParse, + WhereTerm *pTerm, + u8 idxaff +){ + Expr *pX = pTerm->pExpr; + Expr inexpr; + + assert( pTerm->eOperator & WO_IN ); + + if( sqlite3ExprIsVector(pX->pLeft) ){ + int iField = pTerm->u.x.iField - 1; + inexpr.flags = 0; + inexpr.op = TK_EQ; + inexpr.pLeft = pX->pLeft->x.pList->a[iField].pExpr; + assert( ExprUseXSelect(pX) ); + inexpr.pRight = pX->x.pSelect->pEList->a[iField].pExpr; + pX = &inexpr; + } + + if( sqlite3IndexAffinityOk(pX, idxaff) ){ + CollSeq *pRet = sqlite3ExprCompareCollSeq(pParse, pX); + return pRet ? pRet->zName : sqlite3StrBINARY; + } + return 0; +} + +/* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). ** Return NULL if there are no more matching WhereTerms. @@ -352,16 +388,24 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ if( (pTerm->eOperator & pScan->opMask)!=0 ){ /* Verify the affinity and collating sequence match */ if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){ - CollSeq *pColl; + const char *zCollName; Parse *pParse = pWC->pWInfo->pParse; pX = pTerm->pExpr; - if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ - continue; + + if( (pTerm->eOperator & WO_IN) ){ + zCollName = indexInAffinityOk(pParse, pTerm, pScan->idxaff); + if( !zCollName ) continue; + }else{ + CollSeq *pColl; + if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ + continue; + } + assert(pX->pLeft); + pColl = sqlite3ExprCompareCollSeq(pParse, pX); + zCollName = pColl ? pColl->zName : sqlite3StrBINARY; } - assert(pX->pLeft); - pColl = sqlite3ExprCompareCollSeq(pParse, pX); - if( pColl==0 ) pColl = pParse->db->pDfltColl; - if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ + + if( sqlite3StrICmp(zCollName, pScan->zCollName) ){ continue; } } |