#include "sqliteInt.h"
#include "whereInt.h"
#ifndef SQLITE_OMIT_EXPLAIN
static const char *explainIndexColumnName(Index *pIdx, int i){
i = pIdx->aiColumn[i];
if( i==XN_EXPR ) return "<expr>";
if( i==XN_ROWID ) return "rowid";
return pIdx->pTable->aCol[i].zCnName;
}
static void explainAppendTerm(
StrAccum *pStr,
Index *pIdx,
int nTerm,
int iTerm,
int bAnd,
const char *zOp
){
int i;
assert( nTerm>=1 );
if( bAnd ) sqlite3_str_append(pStr, " AND ", 5);
if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1);
for(i=0; i<nTerm; i++){
if( i ) sqlite3_str_append(pStr, ",", 1);
sqlite3_str_appendall(pStr, explainIndexColumnName(pIdx, iTerm+i));
}
if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1);
sqlite3_str_append(pStr, zOp, 1);
if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1);
for(i=0; i<nTerm; i++){
if( i ) sqlite3_str_append(pStr, ",", 1);
sqlite3_str_append(pStr, "?", 1);
}
if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1);
}
static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
Index *pIndex = pLoop->u.btree.pIndex;
u16 nEq = pLoop->u.btree.nEq;
u16 nSkip = pLoop->nSkip;
int i, j;
if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
sqlite3_str_append(pStr, " (", 2);
for(i=0; i<nEq; i++){
const char *z = explainIndexColumnName(pIndex, i);
if( i ) sqlite3_str_append(pStr, " AND ", 5);
sqlite3_str_appendf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
}
j = i;
if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
explainAppendTerm(pStr, pIndex, pLoop->u.btree.nBtm, j, i, ">");
i = 1;
}
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<");
}
sqlite3_str_append(pStr, ")", 1);
}
int sqlite3WhereExplainOneScan(
Parse *pParse,
SrcList *pTabList,
WhereLevel *pLevel,
u16 wctrlFlags
){
int ret = 0;
#if !defined(SQLITE_DEBUG)
if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
SrcItem *pItem = &pTabList->a[pLevel->iFrom];
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
int isSearch;
WhereLoop *pLoop;
u32 flags;
char *zMsg;
StrAccum str;
char zBuf[100];
pLoop = pLevel->pWLoop;
flags = pLoop->wsFlags;
if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0;
isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
str.printfFlags = SQLITE_PRINTF_INTERNAL;
sqlite3_str_appendf(&str, "%s %S", isSearch ? "SEARCH" : "SCAN", pItem);
if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
const char *zFmt = 0;
Index *pIdx;
assert( pLoop->u.btree.pIndex!=0 );
pIdx = pLoop->u.btree.pIndex;
assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
if( isSearch ){
zFmt = "PRIMARY KEY";
}
}else if( flags & WHERE_PARTIALIDX ){
zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
}else if( flags & WHERE_AUTO_INDEX ){
zFmt = "AUTOMATIC COVERING INDEX";
}else if( flags & WHERE_IDX_ONLY ){
zFmt = "COVERING INDEX %s";
}else{
zFmt = "INDEX %s";
}
if( zFmt ){
sqlite3_str_append(&str, " USING ", 7);
sqlite3_str_appendf(&str, zFmt, pIdx->zName);
explainIndexRange(&str, pLoop);
}
}else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
char cRangeOp;
#if 0#else
const char *zRowid = "rowid";
#endif
sqlite3_str_appendf(&str, " USING INTEGER PRIMARY KEY (%s", zRowid);
if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
cRangeOp = '=';
}else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
sqlite3_str_appendf(&str, ">? AND %s", zRowid);
cRangeOp = '<';
}else if( flags&WHERE_BTM_LIMIT ){
cRangeOp = '>';
}else{
assert( flags&WHERE_TOP_LIMIT);
cRangeOp = '<';
}
sqlite3_str_appendf(&str, "%c?)", cRangeOp);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s",
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
}
#endif
if( pItem->fg.jointype & JT_LEFT ){
sqlite3_str_appendf(&str, " LEFT-JOIN");
}
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
if( pLoop->nOut>=10 ){
sqlite3_str_appendf(&str, " (~%llu rows)",
sqlite3LogEstToInt(pLoop->nOut));
}else{
sqlite3_str_append(&str, " (~1 row)", 9);
}
#endif
zMsg = sqlite3StrAccumFinish(&str);
sqlite3ExplainBreakpoint("",zMsg);
ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
}
return ret;
}
int sqlite3WhereExplainBloomFilter(
const Parse *pParse,
const WhereInfo *pWInfo,
const WhereLevel *pLevel
){
int ret = 0;
SrcItem *pItem = &pWInfo->pTabList->a[pLevel->iFrom];
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
char *zMsg;
int i;
WhereLoop *pLoop;
StrAccum str;
char zBuf[100];
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
str.printfFlags = SQLITE_PRINTF_INTERNAL;
sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
pLoop = pLevel->pWLoop;
if( pLoop->wsFlags & WHERE_IPK ){
const Table *pTab = pItem->pTab;
if( pTab->iPKey>=0 ){
sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
}else{
sqlite3_str_appendf(&str, "rowid=?");
}
}else{
for(i=pLoop->nSkip; i<pLoop->u.btree.nEq; i++){
const char *z = explainIndexColumnName(pLoop->u.btree.pIndex, i);
if( i>pLoop->nSkip ) sqlite3_str_append(&str, " AND ", 5);
sqlite3_str_appendf(&str, "%s=?", z);
}
}
sqlite3_str_append(&str, ")", 1);
zMsg = sqlite3StrAccumFinish(&str);
ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
sqlite3VdbeScanStatus(v, sqlite3VdbeCurrentAddr(v)-1, 0, 0, 0, 0);
return ret;
}
#endif
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
void sqlite3WhereAddScanStatus(
Vdbe *v,
SrcList *pSrclist,
WhereLevel *pLvl,
int addrExplain
){
if( IS_STMT_SCANSTATUS( sqlite3VdbeDb(v) ) ){
const char *zObj = 0;
WhereLoop *pLoop = pLvl->pWLoop;
int wsFlags = pLoop->wsFlags;
int viaCoroutine = 0;
if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
zObj = pLoop->u.btree.pIndex->zName;
}else{
zObj = pSrclist->a[pLvl->iFrom].zName;
viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
}
sqlite3VdbeScanStatus(
v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
);
if( viaCoroutine==0 ){
if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
}
if( wsFlags & WHERE_INDEXED ){
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
}
}
}
}
#endif
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
int nLoop = 0;
assert( pTerm!=0 );
while( (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_OuterON))
&& (pLevel->notReady & pTerm->prereqAll)==0
){
if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
pTerm->wtFlags |= TERM_LIKECOND;
}else{
pTerm->wtFlags |= TERM_CODED;
}
#ifdef WHERETRACE_ENABLED
if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
sqlite3DebugPrintf("DISABLE-");
sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a)));
}
#endif
if( pTerm->iParent<0 ) break;
pTerm = &pTerm->pWC->a[pTerm->iParent];
assert( pTerm!=0 );
pTerm->nChild--;
if( pTerm->nChild!=0 ) break;
nLoop++;
}
}
static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
Vdbe *v = pParse->pVdbe;
if( zAff==0 ){
assert( pParse->db->mallocFailed );
return;
}
assert( v!=0 );
assert( SQLITE_AFF_NONE<SQLITE_AFF_BLOB );
while( n>0 && zAff[0]<=SQLITE_AFF_BLOB ){
n--;
base++;
zAff++;
}
while( n>1 && zAff[n-1]<=SQLITE_AFF_BLOB ){
n--;
}
if( n>0 ){
sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n);
}
}
static void updateRangeAffinityStr(
Expr *pRight,
int n,
char *zAff
){
int i;
for(i=0; i<n; i++){
Expr *p = sqlite3VectorFieldSubexpr(pRight, i);
if( sqlite3CompareAffinity(p, zAff[i])==SQLITE_AFF_BLOB
|| sqlite3ExprNeedsNoAffinityChange(p, zAff[i])
){
zAff[i] = SQLITE_AFF_BLOB;
}
}
}
static Expr *removeUnindexableInClauseTerms(
Parse *pParse,
int iEq,
WhereLoop *pLoop,
Expr *pX
){
sqlite3 *db = pParse->db;
Select *pSelect;
Expr *pNew;
pNew = sqlite3ExprDup(db, pX, 0);
if( db->mallocFailed==0 ){
for(pSelect=pNew->x.pSelect; pSelect; pSelect=pSelect->pPrior){
ExprList *pOrigRhs;
ExprList *pOrigLhs = 0;
ExprList *pRhs = 0;
ExprList *pLhs = 0;
int i;
assert( ExprUseXSelect(pNew) );
pOrigRhs = pSelect->pEList;
assert( pNew->pLeft!=0 );
assert( ExprUseXList(pNew->pLeft) );
if( pSelect==pNew->x.pSelect ){
pOrigLhs = pNew->pLeft->x.pList;
}
for(i=iEq; i<pLoop->nLTerm; i++){
if( pLoop->aLTerm[i]->pExpr==pX ){
int iField;
assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 );
iField = pLoop->aLTerm[i]->u.x.iField - 1;
if( pOrigRhs->a[iField].pExpr==0 ) continue;
pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
pOrigRhs->a[iField].pExpr = 0;
if( pOrigLhs ){
assert( pOrigLhs->a[iField].pExpr!=0 );
pLhs = sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr);
pOrigLhs->a[iField].pExpr = 0;
}
}
}
sqlite3ExprListDelete(db, pOrigRhs);
if( pOrigLhs ){
sqlite3ExprListDelete(db, pOrigLhs);
pNew->pLeft->x.pList = pLhs;
}
pSelect->pEList = pRhs;
if( pLhs && pLhs->nExpr==1 ){
Expr *p = pLhs->a[0].pExpr;
pLhs->a[0].pExpr = 0;
sqlite3ExprDelete(db, pNew->pLeft);
pNew->pLeft = p;
}
if( pSelect->pOrderBy ){
ExprList *pOrderBy = pSelect->pOrderBy;
for(i=0; i<pOrderBy->nExpr; i++){
pOrderBy->a[i].u.x.iOrderByCol = 0;
}
}
#if 0#endif
}
}
return pNew;
}
static int codeEqualityTerm(
Parse *pParse,
WhereTerm *pTerm,
WhereLevel *pLevel,
int iEq,
int bRev,
int iTarget
){
Expr *pX = pTerm->pExpr;
Vdbe *v = pParse->pVdbe;
int iReg;
assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
assert( iTarget>0 );
if( pX->op==TK_EQ || pX->op==TK_IS ){
iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
}else if( pX->op==TK_ISNULL ){
iReg = iTarget;
sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
#ifndef SQLITE_OMIT_SUBQUERY
}else{
int eType = IN_INDEX_NOOP;
int iTab;
struct InLoop *pIn;
WhereLoop *pLoop = pLevel->pWLoop;
int i;
int nEq = 0;
int *aiMap = 0;
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
&& pLoop->u.btree.pIndex!=0
&& pLoop->u.btree.pIndex->aSortOrder[iEq]
){
testcase( iEq==0 );
testcase( bRev );
bRev = !bRev;
}
assert( pX->op==TK_IN );
iReg = iTarget;
for(i=0; i<iEq; i++){
if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
disableTerm(pLevel, pTerm);
return iTarget;
}
}
for(i=iEq;i<pLoop->nLTerm; i++){
assert( pLoop->aLTerm[i]!=0 );
if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
}
iTab = 0;
if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
}else{
Expr *pExpr = pTerm->pExpr;
if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
sqlite3 *db = pParse->db;
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
if( !db->mallocFailed ){
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
pExpr->iTable = iTab;
}
sqlite3ExprDelete(db, pX);
}else{
int n = sqlite3ExprVectorSize(pX->pLeft);
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
}
pX = pExpr;
}
if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev );
bRev = !bRev;
}
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
VdbeCoverageIf(v, bRev);
VdbeCoverageIf(v, !bRev);
assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
pLoop->wsFlags |= WHERE_IN_ABLE;
if( pLevel->u.in.nIn==0 ){
pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
}
if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){
pLoop->wsFlags |= WHERE_IN_EARLYOUT;
}
i = pLevel->u.in.nIn;
pLevel->u.in.nIn += nEq;
pLevel->u.in.aInLoop =
sqlite3WhereRealloc(pTerm->pWC->pWInfo,
pLevel->u.in.aInLoop,
sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
pIn = pLevel->u.in.aInLoop;
if( pIn ){
int iMap = 0;
pIn += i;
for(i=iEq;i<pLoop->nLTerm; i++){
if( pLoop->aLTerm[i]->pExpr==pX ){
int iOut = iReg + i - iEq;
if( eType==IN_INDEX_ROWID ){
pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
}else{
int iCol = aiMap ? aiMap[iMap++] : 0;
pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
}
sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
if( i==iEq ){
pIn->iCur = iTab;
pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
if( iEq>0 ){
pIn->iBase = iReg - i;
pIn->nPrefix = i;
}else{
pIn->nPrefix = 0;
}
}else{
pIn->eEndLoopOp = OP_Noop;
}
pIn++;
}
}
testcase( iEq>0
&& (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0
&& (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 );
if( iEq>0
&& (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0
){
sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq);
}
}else{
pLevel->u.in.nIn = 0;
}
sqlite3DbFree(pParse->db, aiMap);
#endif
}
if( (pLevel->pWLoop->wsFlags & WHERE_TRANSCONS)==0
|| (pTerm->eOperator & WO_EQUIV)==0
){
disableTerm(pLevel, pTerm);
}
return iReg;
}
static int codeAllEqualityTerms(
Parse *pParse,
WhereLevel *pLevel,
int bRev,
int nExtraReg,
char **pzAff
){
u16 nEq;
u16 nSkip;
Vdbe *v = pParse->pVdbe;
Index *pIdx;
WhereTerm *pTerm;
WhereLoop *pLoop;
int j;
int regBase;
int nReg;
char *zAff;
pLoop = pLevel->pWLoop;
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
nEq = pLoop->u.btree.nEq;
nSkip = pLoop->nSkip;
pIdx = pLoop->u.btree.pIndex;
assert( pIdx!=0 );
regBase = pParse->nMem + 1;
nReg = nEq + nExtraReg;
pParse->nMem += nReg;
zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx));
assert( zAff!=0 || pParse->db->mallocFailed );
if( nSkip ){
int iIdxCur = pLevel->iIdxCur;
sqlite3VdbeAddOp3(v, OP_Null, 0, regBase, regBase+nSkip-1);
sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
VdbeComment((v, "begin skip-scan on %s", pIdx->zName));
j = sqlite3VdbeAddOp0(v, OP_Goto);
assert( pLevel->addrSkip==0 );
pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT),
iIdxCur, 0, regBase, nSkip);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
sqlite3VdbeJumpHere(v, j);
for(j=0; j<nSkip; j++){
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j);
testcase( pIdx->aiColumn[j]==XN_EXPR );
VdbeComment((v, "%s", explainIndexColumnName(pIdx, j)));
}
}
assert( zAff==0 || (int)strlen(zAff)>=nEq );
for(j=nSkip; j<nEq; j++){
int r1;
pTerm = pLoop->aLTerm[j];
assert( pTerm!=0 );
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j);
if( r1!=regBase+j ){
if( nReg==1 ){
sqlite3ReleaseTempReg(pParse, regBase);
regBase = r1;
}else{
sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j);
}
}
if( pTerm->eOperator & WO_IN ){
if( pTerm->pExpr->flags & EP_xIsSelect ){
if( zAff ) zAff[j] = SQLITE_AFF_BLOB;
}
}else if( (pTerm->eOperator & WO_ISNULL)==0 ){
Expr *pRight = pTerm->pExpr->pRight;
if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
VdbeCoverage(v);
}
if( pParse->nErr==0 ){
assert( pParse->db->mallocFailed==0 );
if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){
zAff[j] = SQLITE_AFF_BLOB;
}
if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){
zAff[j] = SQLITE_AFF_BLOB;
}
}
}
}
*pzAff = zAff;
return regBase;
}
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
static void whereLikeOptimizationStringFixup(
Vdbe *v,
WhereLevel *pLevel,
WhereTerm *pTerm
){
if( pTerm->wtFlags & TERM_LIKEOPT ){
VdbeOp *pOp;
assert( pLevel->iLikeRepCntr>0 );
pOp = sqlite3VdbeGetLastOp(v);
assert( pOp!=0 );
assert( pOp->opcode==OP_String8
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed );
pOp->p3 = (int)(pLevel->iLikeRepCntr>>1);
pOp->p5 = (u8)(pLevel->iLikeRepCntr&1);
}
}
#else
# define whereLikeOptimizationStringFixup(A,B,C)
#endif
#ifdef SQLITE_ENABLE_CURSOR_HINTS
struct CCurHint {
int iTabCur;
int iIdxCur;
Index *pIdx;
};
static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
struct CCurHint *pHint = pWalker->u.pCCurHint;
assert( pHint->pIdx!=0 );
if( pExpr->op==TK_COLUMN
&& pExpr->iTable==pHint->iTabCur
&& sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn)<0
){
pWalker->eCode = 1;
}
return WRC_Continue;
}
static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_IS
|| pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT
|| pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE
){
pWalker->eCode = 1;
}else if( pExpr->op==TK_FUNCTION ){
int d1;
char d2[4];
if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
pWalker->eCode = 1;
}
}
return WRC_Continue;
}
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
int rc = WRC_Continue;
int reg;
struct CCurHint *pHint = pWalker->u.pCCurHint;
if( pExpr->op==TK_COLUMN ){
if( pExpr->iTable!=pHint->iTabCur ){
reg = ++pWalker->pParse->nMem;
reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
pExpr->iTable = pHint->iIdxCur;
pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
assert( pExpr->iColumn>=0 );
}
}else if( pExpr->pAggInfo ){
rc = WRC_Prune;
reg = ++pWalker->pParse->nMem;
reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pExpr->op==TK_TRUEFALSE ){
return WRC_Prune;
}
return rc;
}
static void codeCursorHint(
SrcItem *pTabItem,
WhereInfo *pWInfo,
WhereLevel *pLevel,
WhereTerm *pEndRange
){
Parse *pParse = pWInfo->pParse;
sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe;
Expr *pExpr = 0;
WhereLoop *pLoop = pLevel->pWLoop;
int iCur;
WhereClause *pWC;
WhereTerm *pTerm;
int i, j;
struct CCurHint sHint;
Walker sWalker;
if( OptimizationDisabled(db, SQLITE_CursorHints) ) return;
iCur = pLevel->iTabCur;
assert( iCur==pWInfo->pTabList->a[pLevel->iFrom].iCursor );
sHint.iTabCur = iCur;
sHint.iIdxCur = pLevel->iIdxCur;
sHint.pIdx = pLoop->u.btree.pIndex;
memset(&sWalker, 0, sizeof(sWalker));
sWalker.pParse = pParse;
sWalker.u.pCCurHint = &sHint;
pWC = &pWInfo->sWC;
for(i=0; i<pWC->nBase; i++){
pTerm = &pWC->a[i];
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( pTerm->prereqAll & pLevel->notReady ) continue;
if( pTabItem->fg.jointype & JT_LEFT ){
Expr *pExpr = pTerm->pExpr;
if( !ExprHasProperty(pExpr, EP_OuterON)
|| pExpr->w.iJoin!=pTabItem->iCursor
){
sWalker.eCode = 0;
sWalker.xExprCallback = codeCursorHintIsOrFunction;
sqlite3WalkExpr(&sWalker, pTerm->pExpr);
if( sWalker.eCode ) continue;
}
}else{
if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) continue;
}
if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){
for(j=0; j<pLoop->nLTerm && pLoop->aLTerm[j]!=pTerm; j++){}
if( j<pLoop->nLTerm ) continue;
}
if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue;
if( sHint.pIdx!=0 ){
sWalker.eCode = 0;
sWalker.xExprCallback = codeCursorHintCheckExpr;
sqlite3WalkExpr(&sWalker, pTerm->pExpr);
if( sWalker.eCode ) continue;
}
pExpr = sqlite3ExprAnd(pParse, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
}
if( pExpr!=0 ){
sWalker.xExprCallback = codeCursorHintFixExpr;
if( pParse->nErr==0 ) sqlite3WalkExpr(&sWalker, pExpr);
sqlite3VdbeAddOp4(v, OP_CursorHint,
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
(const char*)pExpr, P4_EXPR);
}
}
#else
# define codeCursorHint(A,B,C,D)
#endif
static void codeDeferredSeek(
WhereInfo *pWInfo,
Index *pIdx,
int iCur,
int iIdxCur
){
Parse *pParse = pWInfo->pParse;
Vdbe *v = pParse->pVdbe;
assert( iIdxCur>0 );
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
pWInfo->bDeferredSeek = 1;
sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
){
int i;
Table *pTab = pIdx->pTable;
u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1));
if( ai ){
ai[0] = pTab->nCol;
for(i=0; i<pIdx->nColumn-1; i++){
int x1, x2;
assert( pIdx->aiColumn[i]<pTab->nCol );
x1 = pIdx->aiColumn[i];
x2 = sqlite3TableColumnToStorage(pTab, x1);
testcase( x1!=x2 );
if( x1>=0 ) ai[x2+1] = i+1;
}
sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
}
}
}
static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
assert( nReg>0 );
if( p && sqlite3ExprIsVector(p) ){
#ifndef SQLITE_OMIT_SUBQUERY
if( ExprUseXSelect(p) ){
Vdbe *v = pParse->pVdbe;
int iSelect;
assert( p->op==TK_SELECT );
iSelect = sqlite3CodeSubselect(pParse, p);
sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1);
}else
#endif
{
int i;
const ExprList *pList;
assert( ExprUseXList(p) );
pList = p->x.pList;
assert( nReg<=pList->nExpr );
for(i=0; i<nReg; i++){
sqlite3ExprCode(pParse, pList->a[i].pExpr, iReg+i);
}
}
}else{
assert( nReg==1 || pParse->nErr );
sqlite3ExprCode(pParse, p, iReg);
}
}
static void whereApplyPartialIndexConstraints(
Expr *pTruth,
int iTabCur,
WhereClause *pWC
){
int i;
WhereTerm *pTerm;
while( pTruth->op==TK_AND ){
whereApplyPartialIndexConstraints(pTruth->pLeft, iTabCur, pWC);
pTruth = pTruth->pRight;
}
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
Expr *pExpr;
if( pTerm->wtFlags & TERM_CODED ) continue;
pExpr = pTerm->pExpr;
if( sqlite3ExprCompare(0, pExpr, pTruth, iTabCur)==0 ){
pTerm->wtFlags |= TERM_CODED;
}
}
}
static SQLITE_NOINLINE void filterPullDown(
Parse *pParse,
WhereInfo *pWInfo,
int iLevel,
int addrNxt,
Bitmask notReady
){
while( ++iLevel < pWInfo->nLevel ){
WhereLevel *pLevel = &pWInfo->a[iLevel];
WhereLoop *pLoop = pLevel->pWLoop;
if( pLevel->regFilter==0 ) continue;
if( pLevel->pWLoop->nSkip ) continue;
if( NEVER(pLoop->prereq & notReady) ) continue;
assert( pLevel->addrBrk==0 );
pLevel->addrBrk = addrNxt;
if( pLoop->wsFlags & WHERE_IPK ){
WhereTerm *pTerm = pLoop->aLTerm[0];
int regRowid;
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
regRowid = sqlite3GetTempReg(pParse);
regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid);
sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt);
VdbeCoverage(pParse->pVdbe);
sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
addrNxt, regRowid, 1);
VdbeCoverage(pParse->pVdbe);
}else{
u16 nEq = pLoop->u.btree.nEq;
int r1;
char *zStartAff;
assert( pLoop->wsFlags & WHERE_INDEXED );
assert( (pLoop->wsFlags & WHERE_COLUMN_IN)==0 );
r1 = codeAllEqualityTerms(pParse,pLevel,0,0,&zStartAff);
codeApplyAffinity(pParse, r1, nEq, zStartAff);
sqlite3DbFree(pParse->db, zStartAff);
sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
addrNxt, r1, nEq);
VdbeCoverage(pParse->pVdbe);
}
pLevel->regFilter = 0;
pLevel->addrBrk = 0;
}
}
Bitmask sqlite3WhereCodeOneLoopStart(
Parse *pParse,
Vdbe *v,
WhereInfo *pWInfo,
int iLevel,
WhereLevel *pLevel,
Bitmask notReady
){
int j, k;
int iCur;
int addrNxt;
int bRev;
WhereLoop *pLoop;
WhereClause *pWC;
WhereTerm *pTerm;
sqlite3 *db;
SrcItem *pTabItem;
int addrBrk;
int addrHalt;
int addrCont;
int iRowidReg = 0;
int iReleaseReg = 0;
Index *pIdx = 0;
int iLoop;
pWC = &pWInfo->sWC;
db = pParse->db;
pLoop = pLevel->pWLoop;
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
iCur = pTabItem->iCursor;
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
#if WHERETRACE_ENABLED
if( sqlite3WhereTrace & 0x1 ){
sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
if( sqlite3WhereTrace & 0x1000 ){
sqlite3WhereLoopPrint(pLoop, pWC);
}
}
if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
if( iLevel==0 ){
sqlite3DebugPrintf("WHERE clause being coded:\n");
sqlite3TreeViewExpr(0, pWInfo->pWhere, 0);
}
sqlite3DebugPrintf("All WHERE-clause terms before coding:\n");
sqlite3WhereClausePrint(pWC);
}
#endif
addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(pParse);
assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))
|| pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0
);
if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
pLevel->iLeftJoin = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
VdbeComment((v, "init LEFT JOIN no-match flag"));
}
for(j=iLevel; j>0; j--){
if( pWInfo->a[j].iLeftJoin ) break;
if( pWInfo->a[j].pRJ ) break;
}
addrHalt = pWInfo->a[j].addrBrk;
if( pTabItem->fg.viaCoroutine ){
int regYield = pTabItem->regReturn;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
VdbeCoverage(v);
VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
pLevel->op = OP_Goto;
}else
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
int iReg;
int addrNotFound;
int nConstraint = pLoop->nLTerm;
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
addrNotFound = pLevel->addrBrk;
for(j=0; j<nConstraint; j++){
int iTarget = iReg+j+2;
pTerm = pLoop->aLTerm[j];
if( NEVER(pTerm==0) ) continue;
if( pTerm->eOperator & WO_IN ){
if( SMASKBIT32(j) & pLoop->u.vtab.mHandleIn ){
int iTab = pParse->nTab++;
int iCache = ++pParse->nMem;
sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab);
sqlite3VdbeAddOp3(v, OP_VInitIn, iTab, iTarget, iCache);
}else{
codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
addrNotFound = pLevel->addrNxt;
}
}else{
Expr *pRight = pTerm->pExpr->pRight;
codeExprOrVector(pParse, pRight, iTarget, 1);
if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET
&& pLoop->u.vtab.bOmitOffset
){
assert( pTerm->eOperator==WO_AUX );
assert( pWInfo->pSelect!=0 );
assert( pWInfo->pSelect->iOffset>0 );
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pSelect->iOffset);
VdbeComment((v,"Zero OFFSET counter"));
}
}
}
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
pLoop->u.vtab.idxStr,
pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
VdbeCoverage(v);
pLoop->u.vtab.needFree = 0;
if( db->mallocFailed ) pLoop->u.vtab.idxStr = 0;
pLevel->p1 = iCur;
pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
for(j=0; j<nConstraint; j++){
pTerm = pLoop->aLTerm[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
){
Expr *pCompare;
Expr *pRight;
VdbeOp *pOp;
int iIn;
for(iIn=0; ALWAYS(iIn<pLevel->u.in.nIn); iIn++){
pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[iIn].addrInTop);
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;
}
}
pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
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;
sqlite3ExprIfFalse(
pParse, pCompare, pLevel->addrCont, SQLITE_JUMPIFNULL
);
}
pCompare->pLeft = 0;
}
sqlite3ExprDelete(db, pCompare);
}
}
}else
#endif
if( (pLoop->wsFlags & WHERE_IPK)!=0
&& (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0
){
assert( pLoop->u.btree.nEq==1 );
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
iReleaseReg = ++pParse->nMem;
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
addrNxt = pLevel->addrNxt;
if( pLevel->regFilter ){
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
VdbeCoverage(v);
sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
iRowidReg, 1);
VdbeCoverage(v);
filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady);
}
sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
VdbeCoverage(v);
pLevel->op = OP_Noop;
}else if( (pLoop->wsFlags & WHERE_IPK)!=0
&& (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
){
int testOp = OP_Noop;
int start;
int memEndValue = 0;
WhereTerm *pStart, *pEnd;
j = 0;
pStart = pEnd = 0;
if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++];
if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++];
assert( pStart!=0 || pEnd!=0 );
if( bRev ){
pTerm = pStart;
pStart = pEnd;
pEnd = pTerm;
}
codeCursorHint(pTabItem, pWInfo, pLevel, pEnd);
if( pStart ){
Expr *pX;
int r1, rTemp;
int op;
const u8 aMoveOp[] = {
OP_SeekGT,
OP_SeekLE,
OP_SeekLT,
OP_SeekGE
};
assert( TK_LE==TK_GT+1 );
assert( TK_LT==TK_GT+2 );
assert( TK_GE==TK_GT+3 );
assert( (pStart->wtFlags & TERM_VNULL)==0 );
testcase( pStart->wtFlags & TERM_VIRTUAL );
pX = pStart->pExpr;
assert( pX!=0 );
testcase( pStart->leftCursor!=iCur );
if( sqlite3ExprIsVector(pX->pRight) ){
r1 = rTemp = sqlite3GetTempReg(pParse);
codeExprOrVector(pParse, pX->pRight, r1, 1);
testcase( pX->op==TK_GT );
testcase( pX->op==TK_GE );
testcase( pX->op==TK_LT );
testcase( pX->op==TK_LE );
op = aMoveOp[((pX->op - TK_GT - 1) & 0x3) | 0x1];
assert( pX->op!=TK_GT || op==OP_SeekGE );
assert( pX->op!=TK_GE || op==OP_SeekGE );
assert( pX->op!=TK_LT || op==OP_SeekLE );
assert( pX->op!=TK_LE || op==OP_SeekLE );
}else{
r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
disableTerm(pLevel, pStart);
op = aMoveOp[(pX->op - TK_GT)];
}
sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1);
VdbeComment((v, "pk"));
VdbeCoverageIf(v, pX->op==TK_GT);
VdbeCoverageIf(v, pX->op==TK_LE);
VdbeCoverageIf(v, pX->op==TK_LT);
VdbeCoverageIf(v, pX->op==TK_GE);
sqlite3ReleaseTempReg(pParse, rTemp);
}else{
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
}
if( pEnd ){
Expr *pX;
pX = pEnd->pExpr;
assert( pX!=0 );
assert( (pEnd->wtFlags & TERM_VNULL)==0 );
testcase( pEnd->leftCursor!=iCur );
testcase( pEnd->wtFlags & TERM_VIRTUAL );
memEndValue = ++pParse->nMem;
codeExprOrVector(pParse, pX->pRight, memEndValue, 1);
if( 0==sqlite3ExprIsVector(pX->pRight)
&& (pX->op==TK_LT || pX->op==TK_GT)
){
testOp = bRev ? OP_Le : OP_Ge;
}else{
testOp = bRev ? OP_Lt : OP_Gt;
}
if( 0==sqlite3ExprIsVector(pX->pRight) ){
disableTerm(pLevel, pEnd);
}
}
start = sqlite3VdbeCurrentAddr(v);
pLevel->op = bRev ? OP_Prev : OP_Next;
pLevel->p1 = iCur;
pLevel->p2 = start;
assert( pLevel->p5==0 );
if( testOp!=OP_Noop ){
iRowidReg = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
VdbeCoverageIf(v, testOp==OP_Le);
VdbeCoverageIf(v, testOp==OP_Lt);
VdbeCoverageIf(v, testOp==OP_Ge);
VdbeCoverageIf(v, testOp==OP_Gt);
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
}
}else if( pLoop->wsFlags & WHERE_INDEXED ){
static const u8 aStartOp[] = {
0,
0,
OP_Rewind,
OP_Last,
OP_SeekGT,
OP_SeekLT,
OP_SeekGE,
OP_SeekLE
};
static const u8 aEndOp[] = {
OP_IdxGE,
OP_IdxGT,
OP_IdxLE,
OP_IdxLT,
};
u16 nEq = pLoop->u.btree.nEq;
u16 nBtm = pLoop->u.btree.nBtm;
u16 nTop = pLoop->u.btree.nTop;
int regBase;
WhereTerm *pRangeStart = 0;
WhereTerm *pRangeEnd = 0;
int startEq;
int endEq;
int start_constraints;
int nConstraint;
int iIdxCur;
int nExtraReg = 0;
int op;
char *zStartAff;
char *zEndAff = 0;
u8 bSeekPastNull = 0;
u8 bStopAtNull = 0;
int omitTable;
int regBignull = 0;
int addrSeekScan = 0;
pIdx = pLoop->u.btree.pIndex;
iIdxCur = pLevel->iIdxCur;
assert( nEq>=pLoop->nSkip );
j = nEq;
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
pRangeStart = pLoop->aLTerm[j++];
nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm);
assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
(pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
}
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
pRangeEnd = pLoop->aLTerm[j++];
nExtraReg = MAX(nExtraReg, pLoop->u.btree.nTop);
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
assert( pRangeStart!=0 );
assert( pRangeStart->wtFlags & TERM_LIKEOPT );
pLevel->iLikeRepCntr = (u32)++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr);
VdbeComment((v, "LIKE loop counter"));
pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
testcase( bRev );
testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
assert( (bRev & ~1)==0 );
pLevel->iLikeRepCntr <<=1;
pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC);
}
#endif
if( pRangeStart==0 ){
j = pIdx->aiColumn[nEq];
if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){
bSeekPastNull = 1;
}
}
}
assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0
&& (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0
){
assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 );
assert( pRangeEnd==0 && pRangeStart==0 );
testcase( pLoop->nSkip>0 );
nExtraReg = 1;
bSeekPastNull = 1;
pLevel->regBignull = regBignull = ++pParse->nMem;
if( pLevel->iLeftJoin ){
sqlite3VdbeAddOp2(v, OP_Integer, 0, regBignull);
}
pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse);
}
if( (nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) ){
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
SWAP(u8, bSeekPastNull, bStopAtNull);
SWAP(u8, nBtm, nTop);
}
if( iLevel>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 ){
sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
}
codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd);
regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
if( zStartAff && nTop ){
zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]);
}
addrNxt = (regBignull ? pLevel->addrBignull : pLevel->addrNxt);
testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 );
testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 );
startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE);
endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE);
start_constraints = pRangeStart || nEq>0;
nConstraint = nEq;
if( pRangeStart ){
Expr *pRight = pRangeStart->pExpr->pRight;
codeExprOrVector(pParse, pRight, regBase+nEq, nBtm);
whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
if( (pRangeStart->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
VdbeCoverage(v);
}
if( zStartAff ){
updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]);
}
nConstraint += nBtm;
testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
if( sqlite3ExprIsVector(pRight)==0 ){
disableTerm(pLevel, pRangeStart);
}else{
startEq = 1;
}
bSeekPastNull = 0;
}else if( bSeekPastNull ){
startEq = 0;
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
start_constraints = 1;
nConstraint++;
}else if( regBignull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
start_constraints = 1;
nConstraint++;
}
codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){
}else{
if( regBignull ){
sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull);
VdbeComment((v, "NULL-scan pass ctr"));
}
if( pLevel->regFilter ){
sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
regBase, nEq);
VdbeCoverage(v);
filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady);
}
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
assert( op!=0 );
if( (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 && op==OP_SeekGE ){
assert( regBignull==0 );
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
if( pRangeStart || pRangeEnd ){
sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
addrSeekScan = 0;
}
VdbeCoverage(v);
}
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
VdbeCoverage(v);
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT );
VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
assert( bSeekPastNull==0 || bStopAtNull==0 );
if( regBignull ){
assert( bSeekPastNull==1 || bStopAtNull==1 );
assert( bSeekPastNull==!bStopAtNull );
assert( bStopAtNull==startEq );
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2);
op = aStartOp[(nConstraint>1)*4 + 2 + bRev];
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
nConstraint-startEq);
VdbeCoverage(v);
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
assert( op==OP_Rewind || op==OP_Last || op==OP_SeekGE || op==OP_SeekLE);
}
}
nConstraint = nEq;
assert( pLevel->p2==0 );
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
assert( addrSeekScan==0 );
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
VdbeCoverage(v);
}
if( zEndAff ){
updateRangeAffinityStr(pRight, nTop, zEndAff);
codeApplyAffinity(pParse, regBase+nEq, nTop, zEndAff);
}else{
assert( pParse->db->mallocFailed );
}
nConstraint += nTop;
testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
if( sqlite3ExprIsVector(pRight)==0 ){
disableTerm(pLevel, pRangeEnd);
}else{
endEq = 1;
}
}else if( bStopAtNull ){
if( regBignull==0 ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
endEq = 0;
}
nConstraint++;
}
if( zStartAff ) sqlite3DbNNFreeNN(db, zStartAff);
if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
if( nConstraint ){
if( regBignull ){
sqlite3VdbeAddOp2(v, OP_IfNot, regBignull, sqlite3VdbeCurrentAddr(v)+3);
VdbeComment((v, "If NULL-scan 2nd pass"));
VdbeCoverage(v);
}
op = aEndOp[bRev*2 + endEq];
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
if( addrSeekScan ) sqlite3VdbeJumpHere(v, addrSeekScan);
}
if( regBignull ){
assert( bSeekPastNull==!bStopAtNull );
assert( bSeekPastNull+bStopAtNull==1 );
assert( nConstraint+bSeekPastNull>0 );
sqlite3VdbeAddOp2(v, OP_If, regBignull, sqlite3VdbeCurrentAddr(v)+2);
VdbeComment((v, "If NULL-scan 1st pass"));
VdbeCoverage(v);
op = aEndOp[bRev*2 + bSeekPastNull];
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
nConstraint+bSeekPastNull);
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
}
if( (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0 ){
sqlite3VdbeAddOp3(v, OP_SeekHit, iIdxCur, nEq, nEq);
}
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
&& (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0;
if( omitTable ){
}else if( HasRowid(pIdx->pTable) ){
codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
}else if( iCur!=iIdxCur ){
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; j<pPk->nKeyCol; j++){
k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
}
sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
if( pLevel->iLeftJoin==0 ){
if( pIdx->pPartIdxWhere ){
whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC);
}
}else{
testcase( pIdx->pPartIdxWhere );
assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 );
}
if( pLoop->wsFlags & WHERE_ONEROW ){
pLevel->op = OP_Noop;
}else if( bRev ){
pLevel->op = OP_Prev;
}else{
pLevel->op = OP_Next;
}
pLevel->p1 = iIdxCur;
pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0;
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}else{
assert( pLevel->p5==0 );
}
if( omitTable ) pIdx = 0;
}else
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
if( pLoop->wsFlags & WHERE_MULTI_OR ){
WhereClause *pOrWc;
SrcList *pOrTab;
Index *pCov = 0;
int iCovCur = pParse->nTab++;
int regReturn = ++pParse->nMem;
int regRowset = 0;
int regRowid = 0;
int iLoopBody = sqlite3VdbeMakeLabel(pParse);
int iRetInit;
int untestedTerms = 0;
int ii;
Expr *pAndExpr = 0;
Table *pTab = pTabItem->pTab;
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
assert( pTerm->eOperator & WO_OR );
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
pOrWc = &pTerm->u.pOrInfo->wc;
pLevel->op = OP_Return;
pLevel->p1 = regReturn;
if( pWInfo->nLevel>1 ){
int nNotReady;
SrcItem *origSrc;
nNotReady = pWInfo->nLevel - iLevel - 1;
pOrTab = sqlite3DbMallocRawNN(db,
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
if( pOrTab==0 ) return notReady;
pOrTab->nAlloc = (u8)(nNotReady + 1);
pOrTab->nSrc = pOrTab->nAlloc;
memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem));
origSrc = pWInfo->pTabList->a;
for(k=1; k<=nNotReady; k++){
memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
}
}else{
pOrTab = pWInfo->pTabList;
}
if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
if( HasRowid(pTab) ){
regRowset = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
regRowset = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
}
regRowid = ++pParse->nMem;
}
iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
if( pWC->nTerm>1 ){
int iTerm;
for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
Expr *pExpr = pWC->a[iTerm].pExpr;
if( &pWC->a[iTerm] == pTerm ) continue;
testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
testcase( pWC->a[iTerm].wtFlags & TERM_SLICE );
if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED|TERM_SLICE))!=0 ){
continue;
}
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
if( ExprHasProperty(pExpr, EP_Subquery) ) continue;
pExpr = sqlite3ExprDup(db, pExpr, 0);
pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr);
}
if( pAndExpr ){
pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr);
}
}
ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR"));
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
WhereInfo *pSubWInfo;
Expr *pOrExpr = pOrTerm->pExpr;
Expr *pDelete;
int jmp1 = 0;
testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0
&& !ExprHasProperty(pOrExpr, EP_OuterON)
);
pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0);
if( db->mallocFailed ){
sqlite3ExprDelete(db, pDelete);
continue;
}
if( pAndExpr ){
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
}
ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
WHERETRACE(0xffffffff, ("Subplan for OR-clause:\n"));
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0,
WHERE_OR_SUBCLAUSE, iCovCur);
assert( pSubWInfo || pParse->nErr );
if( pSubWInfo ){
WhereLoop *pSubLoop;
int addrExplain = sqlite3WhereExplainOneScan(
pParse, pOrTab, &pSubWInfo->a[0], 0
);
sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain);
if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
if( HasRowid(pTab) ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid);
jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0,
regRowid, iSet);
VdbeCoverage(v);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
int nPk = pPk->nKeyCol;
int iPk;
int r;
r = sqlite3GetTempRange(pParse, nPk);
for(iPk=0; iPk<nPk; iPk++){
int iCol = pPk->aiColumn[iPk];
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk);
}
if( iSet ){
jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
VdbeCoverage(v);
}
if( iSet>=0 ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid,
r, nPk);
if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
}
sqlite3ReleaseTempRange(pParse, r, nPk);
}
}
sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
if( jmp1 ) sqlite3VdbeJumpHere(v, jmp1);
if( pSubWInfo->untestedTerms ) untestedTerms = 1;
pSubLoop = pSubWInfo->a[0].pWLoop;
assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0
&& (ii==0 || pSubLoop->u.btree.pIndex==pCov)
&& (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex))
){
assert( pSubWInfo->a[0].iIdxCur==iCovCur );
pCov = pSubLoop->u.btree.pIndex;
}else{
pCov = 0;
}
if( sqlite3WhereUsesDeferredSeek(pSubWInfo) ){
pWInfo->bDeferredSeek = 1;
}
sqlite3WhereEnd(pSubWInfo);
ExplainQueryPlanPop(pParse);
}
sqlite3ExprDelete(db, pDelete);
}
}
ExplainQueryPlanPop(pParse);
assert( pLevel->pWLoop==pLoop );
assert( (pLoop->wsFlags & WHERE_MULTI_OR)!=0 );
assert( (pLoop->wsFlags & WHERE_IN_ABLE)==0 );
pLevel->u.pCoveringIdx = pCov;
if( pCov ) pLevel->iIdxCur = iCovCur;
if( pAndExpr ){
pAndExpr->pLeft = 0;
sqlite3ExprDelete(db, pAndExpr);
}
sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeGoto(v, pLevel->addrBrk);
sqlite3VdbeResolveLabel(v, iLoopBody);
assert( pLevel->op==OP_Return );
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); }
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
#endif
{
static const u8 aStep[] = { OP_Next, OP_Prev };
static const u8 aStart[] = { OP_Rewind, OP_Last };
assert( bRev==0 || bRev==1 );
if( pTabItem->fg.isRecursive ){
pLevel->op = OP_Noop;
}else{
codeCursorHint(pTabItem, pWInfo, pLevel, 0);
pLevel->op = aStep[bRev];
pLevel->p1 = iCur;
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}
}
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
pLevel->addrVisit = sqlite3VdbeCurrentAddr(v);
#endif
iLoop = (pIdx ? 1 : 2);
do{
int iNext = 0;
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
Expr *pE;
int skipLikeAddr = 0;
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
testcase( pWInfo->untestedTerms==0
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
pWInfo->untestedTerms = 1;
continue;
}
pE = pTerm->pExpr;
assert( pE!=0 );
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){
if( !ExprHasProperty(pE,EP_OuterON|EP_InnerON) ){
continue;
}else if( (pTabItem->fg.jointype & JT_LEFT)==JT_LEFT
&& !ExprHasProperty(pE,EP_OuterON) ){
continue;
}else{
Bitmask m = sqlite3WhereGetMask(&pWInfo->sMaskSet, pE->w.iJoin);
if( m & pLevel->notReady ){
continue;
}
}
}
if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
iNext = 2;
continue;
}
if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){
if( iNext==0 ) iNext = 3;
continue;
}
if( (pTerm->wtFlags & TERM_LIKECOND)!=0 ){
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
continue;
#else
u32 x = pLevel->iLikeRepCntr;
if( x>0 ){
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1));
VdbeCoverageIf(v, (x&1)==1);
VdbeCoverageIf(v, (x&1)==0);
}
#endif
}
#ifdef WHERETRACE_ENABLED
if( sqlite3WhereTrace ){
VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
pWC->nTerm-j, pTerm, iLoop));
}
if( sqlite3WhereTrace & 0x4000 ){
sqlite3DebugPrintf("Coding auxiliary constraint:\n");
sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
}
#endif
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
pTerm->wtFlags |= TERM_CODED;
}
iLoop = iNext;
}while( iLoop>0 );
for(pTerm=pWC->a, j=pWC->nBase; j>0; j--, pTerm++){
Expr *pE, sEAlt;
WhereTerm *pAlt;
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
if( pTerm->leftCursor!=iCur ) continue;
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ) continue;
pE = pTerm->pExpr;
#ifdef WHERETRACE_ENABLED
if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
sqlite3DebugPrintf("Coding transitive constraint:\n");
sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
}
#endif
assert( !ExprHasProperty(pE, EP_OuterON) );
assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady,
WO_EQ|WO_IN|WO_IS, 0);
if( pAlt==0 ) continue;
if( pAlt->wtFlags & (TERM_CODED) ) continue;
if( (pAlt->eOperator & WO_IN)
&& ExprUseXSelect(pAlt->pExpr)
&& (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
){
continue;
}
testcase( pAlt->eOperator & WO_EQ );
testcase( pAlt->eOperator & WO_IS );
testcase( pAlt->eOperator & WO_IN );
VdbeModuleComment((v, "begin transitive constraint"));
sEAlt = *pAlt->pExpr;
sEAlt.pLeft = pE->pLeft;
sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL);
pAlt->wtFlags |= TERM_CODED;
}
if( pLevel->pRJ ){
Table *pTab;
int nPk;
int r;
int jmp1 = 0;
WhereRightJoin *pRJ = pLevel->pRJ;
pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
if( HasRowid(pTab) ){
r = sqlite3GetTempRange(pParse, 2);
sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
nPk = 1;
}else{
int iPk;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
nPk = pPk->nKeyCol;
r = sqlite3GetTempRange(pParse, nPk+1);
for(iPk=0; iPk<nPk; iPk++){
int iCol = pPk->aiColumn[iPk];
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+1+iPk);
}
}
jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, 0, r+1, nPk);
VdbeCoverage(v);
VdbeComment((v, "match against %s", pTab->zName));
sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r);
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk);
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3VdbeJumpHere(v, jmp1);
sqlite3ReleaseTempRange(pParse, r, nPk+1);
}
if( pLevel->iLeftJoin ){
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
VdbeComment((v, "record LEFT JOIN hit"));
if( pLevel->pRJ==0 ){
goto code_outer_join_constraints;
}
}
if( pLevel->pRJ ){
WhereRightJoin *pRJ = pLevel->pRJ;
sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn);
pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v);
assert( pParse->withinRJSubrtn < 255 );
pParse->withinRJSubrtn++;
code_outer_join_constraints:
for(pTerm=pWC->a, j=0; j<pWC->nBase; j++, pTerm++){
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
assert( pWInfo->untestedTerms );
continue;
}
if( pTabItem->fg.jointype & JT_LTORJ ) continue;
assert( pTerm->pExpr );
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
pTerm->wtFlags |= TERM_CODED;
}
}
#if WHERETRACE_ENABLED
if( sqlite3WhereTrace & 0x4000 ){
sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
iLevel);
sqlite3WhereClausePrint(pWC);
}
if( sqlite3WhereTrace & 0x1 ){
sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n",
iLevel, (u64)pLevel->notReady);
}
#endif
return pLevel->notReady;
}
SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
WhereInfo *pWInfo,
int iLevel,
WhereLevel *pLevel
){
Parse *pParse = pWInfo->pParse;
Vdbe *v = pParse->pVdbe;
WhereRightJoin *pRJ = pLevel->pRJ;
Expr *pSubWhere = 0;
WhereClause *pWC = &pWInfo->sWC;
WhereInfo *pSubWInfo;
WhereLoop *pLoop = pLevel->pWLoop;
SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
SrcList sFrom;
Bitmask mAll = 0;
int k;
ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
pRJ->regReturn);
for(k=0; k<iLevel; k++){
int iIdxCur;
mAll |= pWInfo->a[k].pWLoop->maskSelf;
sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
iIdxCur = pWInfo->a[k].iIdxCur;
if( iIdxCur ){
sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
}
}
if( (pTabItem->fg.jointype & JT_LTORJ)==0 ){
mAll |= pLoop->maskSelf;
for(k=0; k<pWC->nTerm; k++){
WhereTerm *pTerm = &pWC->a[k];
if( (pTerm->wtFlags & (TERM_VIRTUAL|TERM_SLICE))!=0
&& pTerm->eOperator!=WO_ROWVAL
){
break;
}
if( pTerm->prereqAll & ~mAll ) continue;
if( ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ) continue;
pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
}
}
sFrom.nSrc = 1;
sFrom.nAlloc = 1;
memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));
sFrom.a[0].fg.jointype = 0;
assert( pParse->withinRJSubrtn < 100 );
pParse->withinRJSubrtn++;
pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0,
WHERE_RIGHT_JOIN, 0);
if( pSubWInfo ){
int iCur = pLevel->iTabCur;
int r = ++pParse->nMem;
int nPk;
int jmp;
int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
Table *pTab = pTabItem->pTab;
if( HasRowid(pTab) ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
nPk = 1;
}else{
int iPk;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
nPk = pPk->nKeyCol;
pParse->nMem += nPk - 1;
for(iPk=0; iPk<nPk; iPk++){
int iCol = pPk->aiColumn[iPk];
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk);
}
}
jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk);
VdbeCoverage(v);
sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk);
VdbeCoverage(v);
sqlite3VdbeJumpHere(v, jmp);
sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn);
sqlite3WhereEnd(pSubWInfo);
}
sqlite3ExprDelete(pParse->db, pSubWhere);
ExplainQueryPlanPop(pParse);
assert( pParse->withinRJSubrtn>0 );
pParse->withinRJSubrtn--;
}