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

📄 where.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
          case TK_GT: iDirectGt[i] = j;  break;        }      }    }    /* If we found a term that tests ROWID with == or IN, that term    ** will be used to locate the rows in the database table.  There    ** is not need to continue into the code below that looks for    ** an index.  We will always use the ROWID over an index.    */    if( iDirectEq[i]>=0 ){      loopMask |= mask;      pLevel->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 the one with the highest score.  The score    ** for the index is determined as follows.  For each of the    ** left-most terms that is fixed by an equality operator, add    ** 32 to the score.  The right-most term of the index may be    ** constrained by an inequality.  Add 4 if for an "x<..." constraint    ** and add 8 for an "x>..." constraint.  If both constraints    ** are present, add 12.    **    ** If the left-most term of the index uses an IN operator    ** (ex:  "x IN (...)")  then add 16 to the score.    **    ** If an index can be used for sorting, add 2 to the score.    ** If an index contains all the terms of a table that are ever    ** used by any expression in the SQL statement, then add 1 to    ** the score.    **    ** This scoring system is designed so that the score can later be    ** used to determine how the index is used.  If the score&0x1c is 0    ** then all constraints are equalities.  If score&0x4 is not 0 then    ** there is an inequality used as a termination key.  (ex: "x<...")    ** If score&0x8 is not 0 then there is an inequality used as the    ** start key.  (ex: "x>...").  A score or 0x10 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){      Bitmask eqMask = 0;  /* Index columns covered by an x=... term */      Bitmask ltMask = 0;  /* Index columns covered by an x<... term */      Bitmask gtMask = 0;  /* Index columns covered by an x>... term */      Bitmask inMask = 0;  /* Index columns covered by an x IN .. term */      Bitmask m;      int nEq, score, bRev = 0;      if( pIdx->nColumn>sizeof(eqMask)*8 ){        continue;  /* Ignore indices with too many columns to analyze */      }      for(pTerm=aExpr, j=0; j<nExpr; j++, pTerm++){        Expr *pX = pTerm->p;        CollSeq *pColl = sqlite3ExprCollSeq(pParse, pX->pLeft);        if( !pColl && pX->pRight ){          pColl = sqlite3ExprCollSeq(pParse, pX->pRight);        }        if( !pColl ){          pColl = pParse->db->pDfltColl;        }        if( pTerm->idxLeft==iCur              && (pTerm->prereqRight & loopMask)==pTerm->prereqRight ){          int iColumn = pX->pLeft->iColumn;          int k;          char idxaff = iColumn>=0 ? pIdx->pTable->aCol[iColumn].affinity : 0;           for(k=0; k<pIdx->nColumn; k++){            /* If the collating sequences or affinities don't match,             ** ignore this index.  */            if( pColl!=pIdx->keyInfo.aColl[k] ) continue;            if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;            if( pIdx->aiColumn[k]==iColumn ){              switch( pX->op ){                case TK_IN: {                  if( k==0 ) inMask |= 1;                  break;                }                case TK_EQ: {                  eqMask |= ((Bitmask)1)<<k;                  break;                }                case TK_LE:                case TK_LT: {                  ltMask |= ((Bitmask)1)<<k;                  break;                }                case TK_GE:                case TK_GT: {                  gtMask |= ((Bitmask)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 = (((Bitmask)1)<<(nEq+1))-1;        if( (m & eqMask)!=m ) break;      }      /* Begin assemblying the score      */      score = nEq*32;   /* Base score is 32 times number of == constraints */      m = ((Bitmask)1)<<nEq;      if( m & ltMask ) score+=4;    /* Increase score for a < constraint */      if( m & gtMask ) score+=8;    /* Increase score for a > constraint */      if( score==0 && inMask ) score = 16; /* Default score for IN constraint */      /* Give bonus points if this index can be used for sorting      */      if( i==0 && score!=16 && ppOrderBy && *ppOrderBy ){        int base = pTabList->a[0].iCursor;        if( isSortingIndex(pParse, pIdx, pTab, base, *ppOrderBy, nEq, &bRev) ){          score += 2;        }      }      /* Check to see if we can get away with using just the index without      ** ever reading the table.  If that is the case, then add one bonus      ** point to the score.      */      if( score && pTabItem->colUsed < (((Bitmask)1)<<(BMS-1)) ){        for(m=0, j=0; j<pIdx->nColumn; j++){          int x = pIdx->aiColumn[j];          if( x<BMS-1 ){            m |= ((Bitmask)1)<<x;          }        }        if( (pTabItem->colUsed & m)==pTabItem->colUsed ){          score++;        }      }      /* If the score for this index is the best we have seen so far, then      ** save it      */      if( score>bestScore ){        pBestIdx = pIdx;        bestScore = score;        bestRev = bRev;      }    }    pLevel->pIdx = pBestIdx;    pLevel->score = bestScore;    pLevel->bRev = bestRev;    loopMask |= mask;    if( pBestIdx ){      pLevel->iIdxCur = 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 *pIdx;             /* Index derived from the WHERE clause */    Table *pTab;             /* Left-most table in the FROM clause */    int bRev = 0;            /* True to reverse the output order */    int iCur;                /* Btree-cursor that will be used by pTab */    WhereLevel *pLevel0 = &pWInfo->a[0];    pTab = pTabList->a[0].pTab;    pIdx = pLevel0->pIdx;    iCur = pTabList->a[0].iCursor;    if( pIdx==0 && sortableByRowid(iCur, *ppOrderBy, &bRev) ){      /* The ORDER BY clause specifies ROWID order, which is what we      ** were going to be doing anyway...      */      *ppOrderBy = 0;      pLevel0->bRev = bRev;    }else if( pLevel0->score==16 ){      /* 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.      */    }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.  But do delete the ORDER BY clause      ** if it is redundant.      */    }else if( (pLevel0->score&2)!=0 ){      /* The index that was selected for searching will cause rows to      ** appear in sorted order.      */      *ppOrderBy = 0;    }  }  /* Open all tables in the pTabList and any indices selected for  ** searching those tables.  */  sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */  pLevel = pWInfo->a;  for(i=0, pTabItem=pTabList->a; i<pTabList->nSrc; i++, pTabItem++, pLevel++){    Table *pTab;    Index *pIx;    int iIdxCur = pLevel->iIdxCur;    pTab = pTabItem->pTab;    if( pTab->isTransient || pTab->pSelect ) continue;    if( (pLevel->score & 1)==0 ){      sqlite3OpenTableForReading(v, pTabItem->iCursor, pTab);    }    pLevel->iTabCur = pTabItem->iCursor;    if( (pIx = pLevel->pIdx)!=0 ){      sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);      sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,                     (char*)&pIx->keyInfo, P3_KEYINFO);    }    if( (pLevel->score & 1)!=0 ){      sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);    }    sqlite3CodeVerifySchema(pParse, pTab->iDb);  }  pWInfo->iTop = sqlite3VdbeCurrentAddr(v);  /* Generate the code to do the search  */  loopMask = 0;  pLevel = pWInfo->a;  pTabItem = pTabList->a;  for(i=0; i<pTabList->nSrc; i++, pTabItem++, pLevel++){    int j, k;    int iCur = pTabItem->iCursor;  /* The VDBE cursor for the table */    Index *pIdx;       /* The index we will be using */    int iIdxCur;       /* The VDBE cursor for the index */    int omitTable;     /* True if we use the index only */    pIdx = pLevel->pIdx;    iIdxCur = pLevel->iIdxCur;    pLevel->inOp = OP_Noop;    /* Check to see if it is appropriate to omit the use of the table    ** here and use its index instead.    */    omitTable = (pLevel->score&1)!=0;    /* 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++;      sqlite3VdbeAddOp(v, OP_Null, 0, 0);      sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);      VdbeComment((v, "# init LEFT JOIN no-match flag"));    }    if( i<ARRAYSIZE(iDirectEq) && (k = 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.      */      assert( k<nExpr );      pTerm = &aExpr[k];      assert( pTerm->p!=0 );      assert( pTerm->idxLeft==iCur );      assert( omitTable==0 );      brk = pLevel->brk = sqlite3VdbeMakeLabel(v);      codeEqualityTerm(pParse, pTerm, brk, pLevel);      cont = pLevel->cont = sqlite3VdbeMakeLabel(v);      sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk);      sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk);      VdbeComment((v, "pk"));      pLevel->op = OP_Noop;    }else if( pIdx!=0 && pLevel->score>3 && (pLevel->score&0x0c)==0 ){      /* Case 2:  There is an index and all terms of the WHERE clause that      **          refer to the index using the "==" or "IN" operators.      */      int start;      int nColumn = (pLevel->score+16)/32;      brk = pLevel->brk = sqlite3VdbeMakeLabel(v);      /* For each column of the index, find the term of the WHERE clause that      ** constraints that column.  If the WHERE clause term is X=expr, then      ** evaluation expr and leave the result on the stack */      for(j=0; j<nColumn; j++){        for(pTerm=aExpr, k=0; k<nExpr; k++, pTerm++){          Expr *pX = pTerm->p;          if( pX==0 ) continue;          if( pTerm->idxLeft==iCur             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight              && pX->pLeft->iColumn==pIdx->aiColumn[j]             && (pX->op==TK_EQ || pX->op==TK_IN)          ){            char idxaff = pIdx->pTable->aCol[pX->pLeft->iColumn].affinity;            if( sqlite3IndexAffinityOk(pX, idxaff) ){              codeEqualityTerm(pParse, pTerm, brk, pLevel);              break;            }          }        }      }      pLevel->iMem = pParse->nMem++;      cont = pLevel->cont = sqlite3VdbeMakeLabel(v);      buildIndexProbe(v, nColumn, brk, pIdx);      sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);      /* Generate code (1) to move to the first matching element of the table.      ** Then generate code (2) that jumps to "brk" after the cursor is past      ** the last matching element of the table.  The code (1) is executed      ** once to initialize the search, the code (2) is executed before each      ** iteration of the scan to see if the scan has finished. */      if( pLevel->bRev ){        /* Scan in reverse order */        sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, brk);        start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);        sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, brk);        pLevel->op = OP_Prev;      }else{        /* Scan in the forward order */        sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, brk);        start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);        sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC);        pLevel->op = OP_Next;      }      sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);      sqlite3VdbeAddOp(v, OP_IdxIsNull, nColumn, cont);      if( !omitTable ){        sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);        sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);      }      pLevel->p1 = iIdxCur;      pLevel->p2 = start;    }else if( i<ARRAYSIZE(iDirectLt) && (iDirectLt[i]>=0 || iDirectGt[i]>=0) ){      /* Case 3:  We have an inequality comparison against the ROWID field.      */      int testOp = OP_Noop;      int start;      int bRev = pLevel->bRev;      assert( omitTable==0 );      brk = pLevel->brk = sqlite3VdbeMakeLabel(v);      cont = pLevel->cont = sqlite3VdbeMakeLabel(v);      if( bRev ){        int t = iDirectGt[i];        iDirectGt[i] = iDirectLt[i];        iDirectLt[i] = t;

⌨️ 快捷键说明

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