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

📄 where.c

📁 sqlite数据库管理系统开放源码
💻 C
📖 第 1 页 / 共 3 页
字号:
  if( nExpr==ARRAYSIZE(aExpr) ){    sqliteErrorMsg(pParse, "WHERE clause too complex - no more "       "than %d terms allowed", (int)ARRAYSIZE(aExpr)-1);    return 0;  }    /* Allocate and initialize the WhereInfo structure that will become the  ** return value.  */  pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));  if( sqlite_malloc_failed ){    sqliteFree(pWInfo);    return 0;  }  pWInfo->pParse = pParse;  pWInfo->pTabList = pTabList;  pWInfo->peakNTab = pWInfo->savedNTab = pParse->nTab;  pWInfo->iBreak = sqliteVdbeMakeLabel(v);  /* Special case: a WHERE clause that is constant.  Evaluate the  ** expression and either jump over all of the code or fall thru.  */  if( pWhere && (pTabList->nSrc==0 || sqliteExprIsConstant(pWhere)) ){    sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);    pWhere = 0;  }  /* Analyze all of the subexpressions.  */  for(i=0; i<nExpr; i++){    exprAnalyze(&maskSet, &aExpr[i]);    /* If we are executing a trigger body, remove all references to    ** new.* and old.* tables from the prerequisite masks.    */    if( pParse->trigStack ){      int x;      if( (x = pParse->trigStack->newIdx) >= 0 ){        int mask = ~getMask(&maskSet, x);        aExpr[i].prereqRight &= mask;        aExpr[i].prereqLeft &= mask;        aExpr[i].prereqAll &= mask;      }      if( (x = pParse->trigStack->oldIdx) >= 0 ){        int mask = ~getMask(&maskSet, x);        aExpr[i].prereqRight &= mask;        aExpr[i].prereqLeft &= mask;        aExpr[i].prereqAll &= mask;      }    }  }  /* Figure out what index to use (if any) for each nested loop.  ** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested  ** loop where i==0 is the outer loop and i==pTabList->nSrc-1 is the inner  ** loop.   **  ** If terms exist that use the ROWID of any table, then set the  ** iDirectEq[], iDirectLt[], or iDirectGt[] elements for that table  ** to the index of the term containing the ROWID.  We always prefer  ** to use a ROWID which can directly access a table rather than an  ** index which requires reading an index first to get the rowid then  ** doing a second read of the actual database table.  **  ** Actually, if there are more than 32 tables in the join, only the  ** first 32 tables are candidates for indices.  This is (again) due  ** to the limit of 32 bits in an integer bitmask.  */  loopMask = 0;  for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++){    int j;    int iCur = pTabList->a[i].iCursor;    /* The cursor for this table */    int mask = getMask(&maskSet, iCur);   /* Cursor mask for this table */    Table *pTab = pTabList->a[i].pTab;    Index *pIdx;    Index *pBestIdx = 0;    int bestScore = 0;    /* Check to see if there is an expression that uses only the    ** ROWID field of this table.  For terms of the form ROWID==expr    ** set iDirectEq[i] to the index of the term.  For terms of the    ** form ROWID<expr or ROWID<=expr set iDirectLt[i] to the term index.    ** For terms like ROWID>expr or ROWID>=expr set iDirectGt[i].    **    ** (Added:) Treat ROWID IN expr like ROWID=expr.    */    pWInfo->a[i].iCur = -1;    iDirectEq[i] = -1;    iDirectLt[i] = -1;    iDirectGt[i] = -1;    for(j=0; j<nExpr; j++){      if( aExpr[j].idxLeft==iCur && aExpr[j].p->pLeft->iColumn<0            && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){        switch( aExpr[j].p->op ){          case TK_IN:          case TK_EQ: iDirectEq[i] = j; break;          case TK_LE:          case TK_LT: iDirectLt[i] = j; break;          case TK_GE:          case TK_GT: iDirectGt[i] = j;  break;        }      }      if( aExpr[j].idxRight==iCur && aExpr[j].p->pRight->iColumn<0            && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){        switch( aExpr[j].p->op ){          case TK_EQ: iDirectEq[i] = j;  break;          case TK_LE:          case TK_LT: iDirectGt[i] = j;  break;          case TK_GE:          case TK_GT: iDirectLt[i] = j;  break;        }      }    }    if( iDirectEq[i]>=0 ){      loopMask |= mask;      pWInfo->a[i].pIdx = 0;      continue;    }    /* Do a search for usable indices.  Leave pBestIdx pointing to    ** the "best" index.  pBestIdx is left set to NULL if no indices    ** are usable.    **    ** The best index is determined as follows.  For each of the    ** left-most terms that is fixed by an equality operator, add    ** 8 to the score.  The right-most term of the index may be    ** constrained by an inequality.  Add 1 if for an "x<..." constraint    ** and add 2 for an "x>..." constraint.  Chose the index that    ** gives the best score.    **    ** This scoring system is designed so that the score can later be    ** used to determine how the index is used.  If the score&7 is 0    ** then all constraints are equalities.  If score&1 is not 0 then    ** there is an inequality used as a termination key.  (ex: "x<...")    ** If score&2 is not 0 then there is an inequality used as the    ** start key.  (ex: "x>...").  A score or 4 is the special case    ** of an IN operator constraint.  (ex:  "x IN ...").    **    ** The IN operator (as in "<expr> IN (...)") is treated the same as    ** an equality comparison except that it can only be used on the    ** left-most column of an index and other terms of the WHERE clause    ** cannot be used in conjunction with the IN operator to help satisfy    ** other columns of the index.    */    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){      int eqMask = 0;  /* Index columns covered by an x=... term */      int ltMask = 0;  /* Index columns covered by an x<... term */      int gtMask = 0;  /* Index columns covered by an x>... term */      int inMask = 0;  /* Index columns covered by an x IN .. term */      int nEq, m, score;      if( pIdx->nColumn>32 ) continue;  /* Ignore indices too many columns */      for(j=0; j<nExpr; j++){        if( aExpr[j].idxLeft==iCur              && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){          int iColumn = aExpr[j].p->pLeft->iColumn;          int k;          for(k=0; k<pIdx->nColumn; k++){            if( pIdx->aiColumn[k]==iColumn ){              switch( aExpr[j].p->op ){                case TK_IN: {                  if( k==0 ) inMask |= 1;                  break;                }                case TK_EQ: {                  eqMask |= 1<<k;                  break;                }                case TK_LE:                case TK_LT: {                  ltMask |= 1<<k;                  break;                }                case TK_GE:                case TK_GT: {                  gtMask |= 1<<k;                  break;                }                default: {                  /* CANT_HAPPEN */                  assert( 0 );                  break;                }              }              break;            }          }        }        if( aExpr[j].idxRight==iCur              && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){          int iColumn = aExpr[j].p->pRight->iColumn;          int k;          for(k=0; k<pIdx->nColumn; k++){            if( pIdx->aiColumn[k]==iColumn ){              switch( aExpr[j].p->op ){                case TK_EQ: {                  eqMask |= 1<<k;                  break;                }                case TK_LE:                case TK_LT: {                  gtMask |= 1<<k;                  break;                }                case TK_GE:                case TK_GT: {                  ltMask |= 1<<k;                  break;                }                default: {                  /* CANT_HAPPEN */                  assert( 0 );                  break;                }              }              break;            }          }        }      }      /* The following loop ends with nEq set to the number of columns      ** on the left of the index with == constraints.      */      for(nEq=0; nEq<pIdx->nColumn; nEq++){        m = (1<<(nEq+1))-1;        if( (m & eqMask)!=m ) break;      }      score = nEq*8;   /* Base score is 8 times number of == constraints */      m = 1<<nEq;      if( m & ltMask ) score++;    /* Increase score for a < constraint */      if( m & gtMask ) score+=2;   /* Increase score for a > constraint */      if( score==0 && inMask ) score = 4;  /* Default score for IN constraint */      if( score>bestScore ){        pBestIdx = pIdx;        bestScore = score;      }    }    pWInfo->a[i].pIdx = pBestIdx;    pWInfo->a[i].score = bestScore;    pWInfo->a[i].bRev = 0;    loopMask |= mask;    if( pBestIdx ){      pWInfo->a[i].iCur = pParse->nTab++;      pWInfo->peakNTab = pParse->nTab;    }  }  /* Check to see if the ORDER BY clause is or can be satisfied by the  ** use of an index on the first table.  */  if( ppOrderBy && *ppOrderBy && pTabList->nSrc>0 ){     Index *pSortIdx;     Index *pIdx;     Table *pTab;     int bRev = 0;     pTab = pTabList->a[0].pTab;     pIdx = pWInfo->a[0].pIdx;     if( pIdx && pWInfo->a[0].score==4 ){       /* If there is already an IN index on the left-most table,       ** it will not give the correct sort order.       ** So, pretend that no suitable index is found.       */       pSortIdx = 0;     }else if( iDirectEq[0]>=0 || iDirectLt[0]>=0 || iDirectGt[0]>=0 ){       /* If the left-most column is accessed using its ROWID, then do       ** not try to sort by index.       */       pSortIdx = 0;     }else{       int nEqCol = (pWInfo->a[0].score+4)/8;       pSortIdx = findSortingIndex(pTab, pTabList->a[0].iCursor,                                    *ppOrderBy, pIdx, nEqCol, &bRev);     }     if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ){       if( pIdx==0 ){         pWInfo->a[0].pIdx = pSortIdx;         pWInfo->a[0].iCur = pParse->nTab++;         pWInfo->peakNTab = pParse->nTab;       }       pWInfo->a[0].bRev = bRev;       *ppOrderBy = 0;     }  }  /* Open all tables in the pTabList and all indices used by those tables.  */  for(i=0; i<pTabList->nSrc; i++){    Table *pTab;    Index *pIx;    pTab = pTabList->a[i].pTab;    if( pTab->isTransient || pTab->pSelect ) continue;    sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);    sqliteVdbeOp3(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum,                     pTab->zName, P3_STATIC);    sqliteCodeVerifySchema(pParse, pTab->iDb);    if( (pIx = pWInfo->a[i].pIdx)!=0 ){      sqliteVdbeAddOp(v, OP_Integer, pIx->iDb, 0);      sqliteVdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum, pIx->zName,0);    }  }  /* Generate the code to do the search  */  loopMask = 0;  for(i=0; i<pTabList->nSrc; i++){    int j, k;    int iCur = pTabList->a[i].iCursor;    Index *pIdx;    WhereLevel *pLevel = &pWInfo->a[i];    /* If this is the right table of a LEFT OUTER JOIN, allocate and    ** initialize a memory cell that records if this table matches any    ** row of the left table of the join.    */    if( i>0 && (pTabList->a[i-1].jointype & JT_LEFT)!=0 ){      if( !pParse->nMem ) pParse->nMem++;      pLevel->iLeftJoin = pParse->nMem++;      sqliteVdbeAddOp(v, OP_String, 0, 0);      sqliteVdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);    }    pIdx = pLevel->pIdx;    pLevel->inOp = OP_Noop;    if( i<ARRAYSIZE(iDirectEq) && iDirectEq[i]>=0 ){      /* Case 1:  We can directly reference a single row using an      **          equality comparison against the ROWID field.  Or      **          we reference multiple rows using a "rowid IN (...)"      **          construct.      */      k = iDirectEq[i];      assert( k<nExpr );      assert( aExpr[k].p!=0 );      assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );      brk = pLevel->brk = sqliteVdbeMakeLabel(v);      if( aExpr[k].idxLeft==iCur ){        Expr *pX = aExpr[k].p;        if( pX->op!=TK_IN ){          sqliteExprCode(pParse, aExpr[k].p->pRight);        }else if( pX->pList ){          sqliteVdbeAddOp(v, OP_SetFirst, pX->iTable, brk);          pLevel->inOp = OP_SetNext;          pLevel->inP1 = pX->iTable;          pLevel->inP2 = sqliteVdbeCurrentAddr(v);        }else{          assert( pX->pSelect );          sqliteVdbeAddOp(v, OP_Rewind, pX->iTable, brk);          sqliteVdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);          pLevel->inP2 = sqliteVdbeAddOp(v, OP_FullKey, pX->iTable, 0);          pLevel->inOp = OP_Next;          pLevel->inP1 = pX->iTable;        }      }else{        sqliteExprCode(pParse, aExpr[k].p->pLeft);      }      disableTerm(pLevel, &aExpr[k].p);      cont = pLevel->cont = sqliteVdbeMakeLabel(v);      sqliteVdbeAddOp(v, OP_MustBeInt, 1, brk);      haveKey = 0;      sqliteVdbeAddOp(v, OP_NotExists, iCur, brk);      pLevel->op = OP_Noop;    }else if( pIdx!=0 && pLevel->score>0 && pLevel->score%4==0 ){      /* Case 2:  There is an index and all terms of the WHERE clause that      **          refer to the index use the "==" or "IN" operators.      */      int start;      int testOp;      int nColumn = (pLevel->score+4)/8;      brk = pLevel->brk = sqliteVdbeMakeLabel(v);      for(j=0; j<nColumn; j++){        for(k=0; k<nExpr; k++){          Expr *pX = aExpr[k].p;          if( pX==0 ) continue;          if( aExpr[k].idxLeft==iCur             && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight              && pX->pLeft->iColumn==pIdx->aiColumn[j]          ){            if( pX->op==TK_EQ ){              sqliteExprCode(pParse, pX->pRight);              disableTerm(pLevel, &aExpr[k].p);              break;            }            if( pX->op==TK_IN && nColumn==1 ){              if( pX->pList ){                sqliteVdbeAddOp(v, OP_SetFirst, pX->iTable, brk);                pLevel->inOp = OP_SetNext;                pLevel->inP1 = pX->iTable;                pLevel->inP2 = sqliteVdbeCurrentAddr(v);              }else{                assert( pX->pSelect );                sqliteVdbeAddOp(v, OP_Rewind, pX->iTable, brk);                sqliteVdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);                pLevel->inP2 = sqliteVdbeAddOp(v, OP_FullKey, pX->iTable, 0);                pLevel->inOp = OP_Next;                pLevel->inP1 = pX->iTable;              }              disableTerm(pLevel, &aExpr[k].p);              break;            }          }          if( aExpr[k].idxRight==iCur             && aExpr[k].p->op==TK_EQ             && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft             && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]          ){            sqliteExprCode(pParse, aExpr[k].p->pLeft);            disableTerm(pLevel, &aExpr[k].p);            break;          }        }

⌨️ 快捷键说明

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