⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 where.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
      }      if( iDirectGt[i]>=0 ){        Expr *pX;        k = iDirectGt[i];        assert( k<nExpr );        pTerm = &aExpr[k];        pX = pTerm->p;        assert( pX!=0 );        assert( pTerm->idxLeft==iCur );        sqlite3ExprCode(pParse, pX->pRight);        sqlite3VdbeAddOp(v, OP_ForceInt, pX->op==TK_LE || pX->op==TK_GT, brk);        sqlite3VdbeAddOp(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk);        VdbeComment((v, "pk"));        disableTerm(pLevel, &pTerm->p);      }else{        sqlite3VdbeAddOp(v, bRev ? OP_Last : OP_Rewind, iCur, brk);      }      if( iDirectLt[i]>=0 ){        Expr *pX;        k = iDirectLt[i];        assert( k<nExpr );        pTerm = &aExpr[k];        pX = pTerm->p;        assert( pX!=0 );        assert( pTerm->idxLeft==iCur );        sqlite3ExprCode(pParse, pX->pRight);        pLevel->iMem = pParse->nMem++;        sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);        if( pX->op==TK_LT || pX->op==TK_GT ){          testOp = bRev ? OP_Le : OP_Ge;        }else{          testOp = bRev ? OP_Lt : OP_Gt;        }        disableTerm(pLevel, &pTerm->p);      }      start = sqlite3VdbeCurrentAddr(v);      pLevel->op = bRev ? OP_Prev : OP_Next;      pLevel->p1 = iCur;      pLevel->p2 = start;      if( testOp!=OP_Noop ){        sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);        sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);        sqlite3VdbeAddOp(v, testOp, 'n', brk);      }    }else if( pIdx==0 ){      /* Case 4:  There is no usable index.  We must do a complete      **          scan of the entire database table.      */      int start;      int opRewind;      assert( omitTable==0 );      brk = pLevel->brk = sqlite3VdbeMakeLabel(v);      cont = pLevel->cont = sqlite3VdbeMakeLabel(v);      if( pLevel->bRev ){        opRewind = OP_Last;        pLevel->op = OP_Prev;      }else{        opRewind = OP_Rewind;        pLevel->op = OP_Next;      }      sqlite3VdbeAddOp(v, opRewind, iCur, brk);      start = sqlite3VdbeCurrentAddr(v);      pLevel->p1 = iCur;      pLevel->p2 = start;    }else{      /* Case 5: The WHERE clause term that refers to the right-most      **         column of the index is an inequality.  For example, if      **         the index is on (x,y,z) and the WHERE clause is of the      **         form "x=5 AND y<10" then this case is used.  Only the      **         right-most column can be an inequality - the rest must      **         use the "==" operator.      **      **         This case is also used when there are no WHERE clause      **         constraints but an index is selected anyway, in order      **         to force the output order to conform to an ORDER BY.      */      int score = pLevel->score;      int nEqColumn = score/32;      int start;      int leFlag=0, geFlag=0;      int testOp;      /* Evaluate the equality constraints      */      for(j=0; j<nEqColumn; j++){        int iIdxCol = pIdx->aiColumn[j];        for(pTerm=aExpr, k=0; k<nExpr; k++, pTerm++){          Expr *pX = pTerm->p;          if( pX==0 ) continue;          if( pTerm->idxLeft==iCur             && pX->op==TK_EQ             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight              && pX->pLeft->iColumn==iIdxCol          ){            sqlite3ExprCode(pParse, pX->pRight);            disableTerm(pLevel, &pTerm->p);            break;          }        }      }      /* Duplicate the equality term values because they will all be      ** used twice: once to make the termination key and once to make the      ** start key.      */      for(j=0; j<nEqColumn; j++){        sqlite3VdbeAddOp(v, OP_Dup, nEqColumn-1, 0);      }      /* Labels for the beginning and end of the loop      */      cont = pLevel->cont = sqlite3VdbeMakeLabel(v);      brk = pLevel->brk = sqlite3VdbeMakeLabel(v);      /* Generate the termination key.  This is the key value that      ** will end the search.  There is no termination key if there      ** are no equality terms and no "X<..." term.      **      ** 2002-Dec-04: On a reverse-order scan, the so-called "termination"      ** key computed here really ends up being the start key.      */      if( (score & 4)!=0 ){        for(pTerm=aExpr, k=0; k<nExpr; k++, pTerm++){          Expr *pX = pTerm->p;          if( pX==0 ) continue;          if( pTerm->idxLeft==iCur             && (pX->op==TK_LT || pX->op==TK_LE)             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight              && pX->pLeft->iColumn==pIdx->aiColumn[j]          ){            sqlite3ExprCode(pParse, pX->pRight);            leFlag = pX->op==TK_LE;            disableTerm(pLevel, &pTerm->p);            break;          }        }        testOp = OP_IdxGE;      }else{        testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop;        leFlag = 1;      }      if( testOp!=OP_Noop ){        int nCol = nEqColumn + ((score & 4)!=0);        pLevel->iMem = pParse->nMem++;        buildIndexProbe(v, nCol, brk, pIdx);        if( pLevel->bRev ){          int op = leFlag ? OP_MoveLe : OP_MoveLt;          sqlite3VdbeAddOp(v, op, iIdxCur, brk);        }else{          sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);        }      }else if( pLevel->bRev ){        sqlite3VdbeAddOp(v, OP_Last, iIdxCur, brk);      }      /* Generate the start key.  This is the key that defines the lower      ** bound on the search.  There is no start key if there are no      ** equality terms and if there is no "X>..." term.  In      ** that case, generate a "Rewind" instruction in place of the      ** start key search.      **      ** 2002-Dec-04: In the case of a reverse-order search, the so-called      ** "start" key really ends up being used as the termination key.      */      if( (score & 8)!=0 ){        for(pTerm=aExpr, k=0; k<nExpr; k++, pTerm++){          Expr *pX = pTerm->p;          if( pX==0 ) continue;          if( pTerm->idxLeft==iCur             && (pX->op==TK_GT || pX->op==TK_GE)             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight              && pX->pLeft->iColumn==pIdx->aiColumn[j]          ){            sqlite3ExprCode(pParse, pX->pRight);            geFlag = pX->op==TK_GE;            disableTerm(pLevel, &pTerm->p);            break;          }        }      }else{        geFlag = 1;      }      if( nEqColumn>0 || (score&8)!=0 ){        int nCol = nEqColumn + ((score&8)!=0);        buildIndexProbe(v, nCol, brk, pIdx);        if( pLevel->bRev ){          pLevel->iMem = pParse->nMem++;          sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);          testOp = OP_IdxLT;        }else{          int op = geFlag ? OP_MoveGe : OP_MoveGt;          sqlite3VdbeAddOp(v, op, iIdxCur, brk);        }      }else if( pLevel->bRev ){        testOp = OP_Noop;      }else{        sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, brk);      }      /* Generate the the top of the loop.  If there is a termination      ** key we have to test for that key and abort at the top of the      ** loop.      */      start = sqlite3VdbeCurrentAddr(v);      if( testOp!=OP_Noop ){        sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);        sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);        if( (leFlag && !pLevel->bRev) || (!geFlag && pLevel->bRev) ){          sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);        }      }      sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);      sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + ((score&4)!=0), cont);      if( !omitTable ){        sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);        sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);      }      /* Record the instruction used to terminate the loop.      */      pLevel->op = pLevel->bRev ? OP_Prev : OP_Next;      pLevel->p1 = iIdxCur;      pLevel->p2 = start;    }    loopMask |= getMask(&maskSet, iCur);    /* Insert code to test every subexpression that can be completely    ** computed using the current set of tables.    */    for(pTerm=aExpr, j=0; j<nExpr; j++, pTerm++){      if( pTerm->p==0 ) continue;      if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue;      if( pLevel->iLeftJoin && !ExprHasProperty(pTerm->p,EP_FromJoin) ){        continue;      }      sqlite3ExprIfFalse(pParse, pTerm->p, cont, 1);      pTerm->p = 0;    }    brk = cont;    /* For a LEFT OUTER JOIN, generate code that will record the fact that    ** at least one row of the right table has matched the left table.      */    if( pLevel->iLeftJoin ){      pLevel->top = sqlite3VdbeCurrentAddr(v);      sqlite3VdbeAddOp(v, OP_Integer, 1, 0);      sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);      VdbeComment((v, "# record LEFT JOIN hit"));      for(pTerm=aExpr, j=0; j<nExpr; j++, pTerm++){        if( pTerm->p==0 ) continue;        if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue;        sqlite3ExprIfFalse(pParse, pTerm->p, cont, 1);        pTerm->p = 0;      }    }  }  pWInfo->iContinue = cont;  freeMaskSet(&maskSet);  return pWInfo;}/*** Generate the end of the WHERE loop.  See comments on ** sqlite3WhereBegin() for additional information.*/void sqlite3WhereEnd(WhereInfo *pWInfo){  Vdbe *v = pWInfo->pParse->pVdbe;  int i;  WhereLevel *pLevel;  SrcList *pTabList = pWInfo->pTabList;  struct SrcList_item *pTabItem;  /* Generate loop termination code.  */  for(i=pTabList->nSrc-1; i>=0; i--){    pLevel = &pWInfo->a[i];    sqlite3VdbeResolveLabel(v, pLevel->cont);    if( pLevel->op!=OP_Noop ){      sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);    }    sqlite3VdbeResolveLabel(v, pLevel->brk);    if( pLevel->inOp!=OP_Noop ){      sqlite3VdbeAddOp(v, pLevel->inOp, pLevel->inP1, pLevel->inP2);    }    if( pLevel->iLeftJoin ){      int addr;      addr = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0);      sqlite3VdbeAddOp(v, OP_NotNull, 1, addr+4 + (pLevel->iIdxCur>=0));      sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);      if( pLevel->iIdxCur>=0 ){        sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0);      }      sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top);    }  }  /* The "break" point is here, just past the end of the outer loop.  ** Set it.  */  sqlite3VdbeResolveLabel(v, pWInfo->iBreak);  /* Close all of the cursors that were opend by sqlite3WhereBegin.  */  pLevel = pWInfo->a;  pTabItem = pTabList->a;  for(i=0; i<pTabList->nSrc; i++, pTabItem++, pLevel++){    Table *pTab = pTabItem->pTab;    assert( pTab!=0 );    if( pTab->isTransient || pTab->pSelect ) continue;    if( (pLevel->score & 1)==0 ){      sqlite3VdbeAddOp(v, OP_Close, pTabItem->iCursor, 0);    }    if( pLevel->pIdx!=0 ){      sqlite3VdbeAddOp(v, OP_Close, pLevel->iIdxCur, 0);    }    /* Make cursor substitutions for cases where we want to use    ** just the index and never reference the table.    **     ** Calls to the code generator in between sqlite3WhereBegin and    ** sqlite3WhereEnd will have created code that references the table    ** directly.  This loop scans all that code looking for opcodes    ** that reference the table and converts them into opcodes that    ** reference the index.    */    if( pLevel->score & 1 ){      int i, j, last;      VdbeOp *pOp;      Index *pIdx = pLevel->pIdx;      assert( pIdx!=0 );      pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);      last = sqlite3VdbeCurrentAddr(v);      for(i=pWInfo->iTop; i<last; i++, pOp++){        if( pOp->p1!=pLevel->iTabCur ) continue;        if( pOp->opcode==OP_Column ){          pOp->p1 = pLevel->iIdxCur;          for(j=0; j<pIdx->nColumn; j++){            if( pOp->p2==pIdx->aiColumn[j] ){              pOp->p2 = j;              break;            }          }        }else if( pOp->opcode==OP_Rowid ){          pOp->p1 = pLevel->iIdxCur;          pOp->opcode = OP_IdxRowid;        }else if( pOp->opcode==OP_NullRow ){          pOp->opcode = OP_Noop;        }      }    }  }  /* Final cleanup  */  sqliteFree(pWInfo);  return;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -