📄 where.c
字号:
** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22)** \________/ \_______________/ \________________/** slot[0] slot[1] slot[2]**** The original WHERE clause in pExpr is unaltered. All this routine** does is make slot[] entries point to substructure within pExpr.**** In the previous sentence and in the diagram, "slot[]" refers to** the WhereClause.a[] array. The slot[] array grows as needed to contain** all terms of the WHERE clause.*/static void whereSplit(WhereClause *pWC, Expr *pExpr, int op){ pWC->op = (u8)op; if( pExpr==0 ) return; if( pExpr->op!=op ){ whereClauseInsert(pWC, pExpr, 0); }else{ whereSplit(pWC, pExpr->pLeft, op); whereSplit(pWC, pExpr->pRight, op); }}/*** Initialize an expression mask set*/#define initMaskSet(P) memset(P, 0, sizeof(*P))/*** Return the bitmask for the given cursor number. Return 0 if** iCursor is not in the set.*/static Bitmask getMask(WhereMaskSet *pMaskSet, int iCursor){ int i; for(i=0; i<pMaskSet->n; i++){ if( pMaskSet->ix[i]==iCursor ){ return ((Bitmask)1)<<i; } } return 0;}/*** Create a new mask for cursor iCursor.**** There is one cursor per table in the FROM clause. The number of** tables in the FROM clause is limited by a test early in the** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[]** array will never overflow.*/static void createMask(WhereMaskSet *pMaskSet, int iCursor){ assert( pMaskSet->n < ArraySize(pMaskSet->ix) ); pMaskSet->ix[pMaskSet->n++] = iCursor;}/*** This routine walks (recursively) an expression tree and generates** a bitmask indicating which tables are used in that expression** tree.**** In order for this routine to work, the calling function must have** previously invoked sqlite3ResolveExprNames() on the expression. See** the header comment on that routine for additional information.** The sqlite3ResolveExprNames() routines looks for column names and** sets their opcodes to TK_COLUMN and their Expr.iTable fields to** the VDBE cursor number of the table. This routine just has to** translate the cursor numbers into bitmask values and OR all** the bitmasks together.*/static Bitmask exprListTableUsage(WhereMaskSet*, ExprList*);static Bitmask exprSelectTableUsage(WhereMaskSet*, Select*);static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){ Bitmask mask = 0; if( p==0 ) return 0; if( p->op==TK_COLUMN ){ mask = getMask(pMaskSet, p->iTable); return mask; } mask = exprTableUsage(pMaskSet, p->pRight); mask |= exprTableUsage(pMaskSet, p->pLeft); mask |= exprListTableUsage(pMaskSet, p->pList); mask |= exprSelectTableUsage(pMaskSet, p->pSelect); return mask;}static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){ int i; Bitmask mask = 0; if( pList ){ for(i=0; i<pList->nExpr; i++){ mask |= exprTableUsage(pMaskSet, pList->a[i].pExpr); } } return mask;}static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){ Bitmask mask = 0; while( pS ){ mask |= exprListTableUsage(pMaskSet, pS->pEList); mask |= exprListTableUsage(pMaskSet, pS->pGroupBy); mask |= exprListTableUsage(pMaskSet, pS->pOrderBy); mask |= exprTableUsage(pMaskSet, pS->pWhere); mask |= exprTableUsage(pMaskSet, pS->pHaving); pS = pS->pPrior; } return mask;}/*** Return TRUE if the given operator is one of the operators that is** allowed for an indexable WHERE clause term. The allowed operators are** "=", "<", ">", "<=", ">=", and "IN".*/static int allowedOp(int op){ assert( TK_GT>TK_EQ && TK_GT<TK_GE ); assert( TK_LT>TK_EQ && TK_LT<TK_GE ); assert( TK_LE>TK_EQ && TK_LE<TK_GE ); assert( TK_GE==TK_EQ+4 ); return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;}/*** Swap two objects of type TYPE.*/#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}/*** Commute a comparison operator. Expressions of the form "X op Y"** are converted into "Y op X".**** If a collation sequence is associated with either the left or right** side of the comparison, it remains associated with the same side after** the commutation. So "Y collate NOCASE op X" becomes ** "X collate NOCASE op Y". This is because any collation sequence on** the left hand side of a comparison overrides any collation sequence ** attached to the right. For the same reason the EP_ExpCollate flag** is not commuted.*/static void exprCommute(Parse *pParse, Expr *pExpr){ u16 expRight = (pExpr->pRight->flags & EP_ExpCollate); u16 expLeft = (pExpr->pLeft->flags & EP_ExpCollate); assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); pExpr->pRight->pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); pExpr->pLeft->pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl); pExpr->pRight->flags = (pExpr->pRight->flags & ~EP_ExpCollate) | expLeft; pExpr->pLeft->flags = (pExpr->pLeft->flags & ~EP_ExpCollate) | expRight; SWAP(Expr*,pExpr->pRight,pExpr->pLeft); if( pExpr->op>=TK_GT ){ assert( TK_LT==TK_GT+2 ); assert( TK_GE==TK_LE+2 ); assert( TK_GT>TK_EQ ); assert( TK_GT<TK_LE ); assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE ); pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT; }}/*** Translate from TK_xx operator to WO_xx bitmask.*/static u16 operatorMask(int op){ u16 c; assert( allowedOp(op) ); if( op==TK_IN ){ c = WO_IN; }else if( op==TK_ISNULL ){ c = WO_ISNULL; }else{ assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff ); c = (u16)(WO_EQ<<(op-TK_EQ)); } assert( op!=TK_ISNULL || c==WO_ISNULL ); assert( op!=TK_IN || c==WO_IN ); assert( op!=TK_EQ || c==WO_EQ ); assert( op!=TK_LT || c==WO_LT ); assert( op!=TK_LE || c==WO_LE ); assert( op!=TK_GT || c==WO_GT ); assert( op!=TK_GE || c==WO_GE ); return c;}/*** Search for a term in the WHERE clause that is of the form "X <op> <expr>"** where X is a reference to the iColumn of table iCur and <op> is one of** the WO_xx operator codes specified by the op parameter.** Return a pointer to the term. Return 0 if not found.*/static WhereTerm *findTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */){ WhereTerm *pTerm; int k; assert( iCur>=0 ); op &= WO_ALL; for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ if( pTerm->leftCursor==iCur && (pTerm->prereqRight & notReady)==0 && pTerm->u.leftColumn==iColumn && (pTerm->eOperator & op)!=0 ){ if( pIdx && pTerm->eOperator!=WO_ISNULL ){ Expr *pX = pTerm->pExpr; CollSeq *pColl; char idxaff; int j; Parse *pParse = pWC->pParse; idxaff = pIdx->pTable->aCol[iColumn].affinity; if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; /* Figure out the collation sequence required from an index for ** it to be useful for optimising expression pX. Store this ** value in variable pColl. */ assert(pX->pLeft); pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); assert(pColl || pParse->nErr); for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ if( NEVER(j>=pIdx->nColumn) ) return 0; } if( pColl && sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; } return pTerm; } } return 0;}/* Forward reference */static void exprAnalyze(SrcList*, WhereClause*, int);/*** Call exprAnalyze on all terms in a WHERE clause. *****/static void exprAnalyzeAll( SrcList *pTabList, /* the FROM clause */ WhereClause *pWC /* the WHERE clause to be analyzed */){ int i; for(i=pWC->nTerm-1; i>=0; i--){ exprAnalyze(pTabList, pWC, i); }}#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION/*** Check to see if the given expression is a LIKE or GLOB operator that** can be optimized using inequality constraints. Return TRUE if it is** so and false if not.**** In order for the operator to be optimizible, the RHS must be a string** literal that does not begin with a wildcard. */static int isLikeOrGlob( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* Test this expression */ int *pnPattern, /* Number of non-wildcard prefix characters */ int *pisComplete, /* True if the only wildcard is % in the last character */ int *pnoCase /* True if uppercase is equivalent to lowercase */){ const char *z; /* String on RHS of LIKE operator */ Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ ExprList *pList; /* List of operands to the LIKE operator */ int c; /* One character in z[] */ int cnt; /* Number of non-wildcard prefix characters */ char wc[3]; /* Wildcard characters */ CollSeq *pColl; /* Collating sequence for LHS */ sqlite3 *db = pParse->db; /* Database connection */ if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ return 0; }#ifdef SQLITE_EBCDIC if( *pnoCase ) return 0;#endif pList = pExpr->pList; pRight = pList->a[0].pExpr; if( pRight->op!=TK_STRING ){ return 0; } pLeft = pList->a[1].pExpr; if( pLeft->op!=TK_COLUMN ){ return 0; } pColl = sqlite3ExprCollSeq(pParse, pLeft); assert( pColl!=0 || pLeft->iColumn==-1 ); if( pColl==0 ){ /* No collation is defined for the ROWID. Use the default. */ pColl = db->pDfltColl; } if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) && (pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){ return 0; } sqlite3DequoteExpr(db, pRight); z = (char *)pRight->token.z; cnt = 0; if( z ){ while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; } } if( cnt==0 || 255==(u8)z[cnt-1] ){ return 0; } *pisComplete = z[cnt]==wc[0] && z[cnt+1]==0; *pnPattern = cnt; return 1;}#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */#ifndef SQLITE_OMIT_VIRTUALTABLE/*** Check to see if the given expression is of the form**** column MATCH expr**** If it is then return TRUE. If not, return FALSE.*/static int isMatchOfColumn( Expr *pExpr /* Test this expression */){ ExprList *pList; if( pExpr->op!=TK_FUNCTION ){ return 0; } if( pExpr->token.n!=5 || sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){ return 0; } pList = pExpr->pList; if( pList->nExpr!=2 ){ return 0; } if( pList->a[1].pExpr->op != TK_COLUMN ){ return 0; } return 1;}#endif /* SQLITE_OMIT_VIRTUALTABLE *//*** If the pBase expression originated in the ON or USING clause of** a join, then transfer the appropriate markings over to derived.*/static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ pDerived->flags |= pBase->flags & EP_FromJoin;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -