📄 expr.c
字号:
if( pList->nAlloc<=pList->nExpr ){ struct ExprList_item *a; int n = pList->nAlloc*2 + 4; a = sqlite3DbRealloc(db, pList->a, n*sizeof(pList->a[0])); if( a==0 ){ goto no_mem; } pList->a = a; pList->nAlloc = n; } assert( pList->a!=0 ); if( pExpr || pName ){ struct ExprList_item *pItem = &pList->a[pList->nExpr++]; memset(pItem, 0, sizeof(*pItem)); pItem->zName = sqlite3NameFromToken(db, pName); pItem->pExpr = pExpr; pItem->iAlias = 0; } return pList;no_mem: /* Avoid leaking memory if malloc has failed. */ sqlite3ExprDelete(db, pExpr); sqlite3ExprListDelete(db, pList); return 0;}/*** If the expression list pEList contains more than iLimit elements,** leave an error message in pParse.*/void sqlite3ExprListCheckLength( Parse *pParse, ExprList *pEList, const char *zObject){ int mx = pParse->db->aLimit[SQLITE_LIMIT_COLUMN]; testcase( pEList && pEList->nExpr==mx ); testcase( pEList && pEList->nExpr==mx+1 ); if( pEList && pEList->nExpr>mx ){ sqlite3ErrorMsg(pParse, "too many columns in %s", zObject); }}/*** Delete an entire expression list.*/void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ int i; struct ExprList_item *pItem; if( pList==0 ) return; assert( pList->a!=0 || (pList->nExpr==0 && pList->nAlloc==0) ); assert( pList->nExpr<=pList->nAlloc ); for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){ sqlite3ExprDelete(db, pItem->pExpr); sqlite3DbFree(db, pItem->zName); } sqlite3DbFree(db, pList->a); sqlite3DbFree(db, pList);}/*** These routines are Walker callbacks. Walker.u.pi is a pointer** to an integer. These routines are checking an expression to see** if it is a constant. Set *Walker.u.pi to 0 if the expression is** not constant.**** These callback routines are used to implement the following:**** sqlite3ExprIsConstant()** sqlite3ExprIsConstantNotJoin()** sqlite3ExprIsConstantOrFunction()***/static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ /* If pWalker->u.i is 3 then any term of the expression that comes from ** the ON or USING clauses of a join disqualifies the expression ** from being considered constant. */ if( pWalker->u.i==3 && ExprHasAnyProperty(pExpr, EP_FromJoin) ){ pWalker->u.i = 0; return WRC_Abort; } switch( pExpr->op ){ /* Consider functions to be constant if all their arguments are constant ** and pWalker->u.i==2 */ case TK_FUNCTION: if( pWalker->u.i==2 ) return 0; /* Fall through */ case TK_ID: case TK_COLUMN: case TK_DOT: case TK_AGG_FUNCTION: case TK_AGG_COLUMN:#ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: case TK_EXISTS: testcase( pExpr->op==TK_SELECT ); testcase( pExpr->op==TK_EXISTS );#endif testcase( pExpr->op==TK_ID ); testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_DOT ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); pWalker->u.i = 0; return WRC_Abort; default: return WRC_Continue; }}static int selectNodeIsConstant(Walker *pWalker, Select *pSelect){ pWalker->u.i = 0; return WRC_Abort;}static int exprIsConst(Expr *p, int initFlag){ Walker w; w.u.i = initFlag; w.xExprCallback = exprNodeIsConstant; w.xSelectCallback = selectNodeIsConstant; sqlite3WalkExpr(&w, p); return w.u.i;}/*** Walk an expression tree. Return 1 if the expression is constant** and 0 if it involves variables or function calls.**** For the purposes of this function, a double-quoted string (ex: "abc")** is considered a variable but a single-quoted string (ex: 'abc') is** a constant.*/int sqlite3ExprIsConstant(Expr *p){ return exprIsConst(p, 1);}/*** Walk an expression tree. Return 1 if the expression is constant** that does no originate from the ON or USING clauses of a join.** Return 0 if it involves variables or function calls or terms from** an ON or USING clause.*/int sqlite3ExprIsConstantNotJoin(Expr *p){ return exprIsConst(p, 3);}/*** Walk an expression tree. Return 1 if the expression is constant** or a function call with constant arguments. Return and 0 if there** are any variables.**** For the purposes of this function, a double-quoted string (ex: "abc")** is considered a variable but a single-quoted string (ex: 'abc') is** a constant.*/int sqlite3ExprIsConstantOrFunction(Expr *p){ return exprIsConst(p, 2);}/*** If the expression p codes a constant integer that is small enough** to fit in a 32-bit integer, return 1 and put the value of the integer** in *pValue. If the expression is not an integer or if it is too big** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.*/int sqlite3ExprIsInteger(Expr *p, int *pValue){ int rc = 0; if( p->flags & EP_IntValue ){ *pValue = p->iTable; return 1; } switch( p->op ){ case TK_INTEGER: { rc = sqlite3GetInt32((char*)p->token.z, pValue); break; } case TK_UPLUS: { rc = sqlite3ExprIsInteger(p->pLeft, pValue); break; } case TK_UMINUS: { int v; if( sqlite3ExprIsInteger(p->pLeft, &v) ){ *pValue = -v; rc = 1; } break; } default: break; } if( rc ){ p->op = TK_INTEGER; p->flags |= EP_IntValue; p->iTable = *pValue; } return rc;}/*** Return TRUE if the given string is a row-id column name.*/int sqlite3IsRowid(const char *z){ if( sqlite3StrICmp(z, "_ROWID_")==0 ) return 1; if( sqlite3StrICmp(z, "ROWID")==0 ) return 1; if( sqlite3StrICmp(z, "OID")==0 ) return 1; return 0;}#ifdef SQLITE_TEST int sqlite3_enable_in_opt = 1;#else #define sqlite3_enable_in_opt 1#endif/*** Return true if the IN operator optimization is enabled and** the SELECT statement p exists and is of the** simple form:**** SELECT <column> FROM <table>**** If this is the case, it may be possible to use an existing table** or index instead of generating an epheremal table.*/#ifndef SQLITE_OMIT_SUBQUERYstatic int isCandidateForInOpt(Select *p){ SrcList *pSrc; ExprList *pEList; Table *pTab; if( !sqlite3_enable_in_opt ) return 0; /* IN optimization must be enabled */ if( p==0 ) return 0; /* right-hand side of IN is SELECT */ if( p->pPrior ) return 0; /* Not a compound SELECT */ if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ return 0; /* No DISTINCT keyword and no aggregate functions */ } if( p->pGroupBy ) return 0; /* Has no GROUP BY clause */ if( p->pLimit ) return 0; /* Has no LIMIT clause */ if( p->pOffset ) return 0; if( p->pWhere ) return 0; /* Has no WHERE clause */ pSrc = p->pSrc; if( pSrc==0 ) return 0; /* A single table in the FROM clause */ if( pSrc->nSrc!=1 ) return 0; if( pSrc->a[0].pSelect ) return 0; /* FROM clause is not a subquery */ pTab = pSrc->a[0].pTab; if( pTab==0 ) return 0; if( pTab->pSelect ) return 0; /* FROM clause is not a view */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ pEList = p->pEList; if( pEList->nExpr!=1 ) return 0; /* One column in the result set */ if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */ return 1;}#endif /* SQLITE_OMIT_SUBQUERY *//*** This function is used by the implementation of the IN (...) operator.** It's job is to find or create a b-tree structure that may be used** either to test for membership of the (...) set or to iterate through** its members, skipping duplicates.**** The cursor opened on the structure (database table, database index ** or ephermal table) is stored in pX->iTable before this function returns.** The returned value indicates the structure type, as follows:**** IN_INDEX_ROWID - The cursor was opened on a database table.** IN_INDEX_INDEX - The cursor was opened on a database index.** IN_INDEX_EPH - The cursor was opened on a specially created and** populated epheremal table.**** An existing structure may only be used if the SELECT is of the simple** form:**** SELECT <column> FROM <table>**** If prNotFound parameter is 0, then the structure will be used to iterate** through the set members, skipping any duplicates. In this case an** epheremal table must be used unless the selected <column> is guaranteed** to be unique - either because it is an INTEGER PRIMARY KEY or it** is unique by virtue of a constraint or implicit index.**** If the prNotFound parameter is not 0, then the structure will be used ** for fast set membership tests. In this case an epheremal table must ** be used unless <column> is an INTEGER PRIMARY KEY or an index can ** be found with <column> as its left-most column.**** When the structure is being used for set membership tests, the user** needs to know whether or not the structure contains an SQL NULL ** value in order to correctly evaluate expressions like "X IN (Y, Z)".** If there is a chance that the structure may contain a NULL value at** runtime, then a register is allocated and the register number written** to *prNotFound. If there is no chance that the structure contains a** NULL value, then *prNotFound is left unchanged.**** If a register is allocated and its location stored in *prNotFound, then** its initial value is NULL. If the structure does not remain constant** for the duration of the query (i.e. the set is a correlated sub-select), ** the value of the allocated register is reset to NULL each time the ** structure is repopulated. This allows the caller to use vdbe code ** equivalent to the following:**** if( register==NULL ){** has_null = <test if data structure contains null>** register = 1** }**** in order to avoid running the <test if data structure contains null>** test more often than is necessary.*/#ifndef SQLITE_OMIT_SUBQUERYint sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ Select *p; int eType = 0; int iTab = pParse->nTab++; int mustBeUnique = !prNotFound; /* The follwing if(...) expression is true if the SELECT is of the ** simple form: ** ** SELECT <column> FROM <table> ** ** If this is the case, it may be possible to use an existing table ** or index instead of generating an epheremal table. */ p = pX->pSelect; if( isCandidateForInOpt(p) ){ sqlite3 *db = pParse->db; Index *pIdx; Expr *pExpr = p->pEList->a[0].pExpr; int iCol = pExpr->iColumn; Vdbe *v = sqlite3GetVdbe(pParse); /* This function is only called from two places. In both cases the vdbe ** has already been allocated. So assume sqlite3GetVdbe() is always ** successful here. */ assert(v); if( iCol<0 ){ int iMem = ++pParse->nMem; int iAddr; Table *pTab = p->pSrc->a[0].pTab; int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3VdbeUsesBtree(v, iDb); iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem); sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; sqlite3VdbeJumpHere(v, iAddr); }else{ /* The collation sequence used by the comparison. If an index is to ** be used in place of a temp-table, it must be ordered according ** to this collation sequence. */ CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr); /* Check that the affinity that will be used to perform the ** comparison is the same as the affinity of the column. If ** it is not, it is not possible to use any index. */ Table *pTab = p->pSrc->a[0].pTab; char aff = comparisonAffinity(pX); int affinity_ok = (pTab->aCol[iCol].affinity==aff||aff==SQLITE_AFF_NONE); for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){ if( (pIdx->aiColumn[0]==iCol) && (pReq==sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], -1, 0)) && (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None)) ){ int iDb; int iMem = ++pParse->nMem; int iAddr; char *pKey; pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); iDb = sqlite3SchemaToIndex(db, pIdx->pSchema); sqlite3VdbeUsesBtree(v, iDb); iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem); sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pIdx->nColumn); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); eType = IN_INDEX_INDEX; sqlite3VdbeJumpHere(v, iAddr); if( prNotFound && !pTab->aCol[iCol].notNull ){ *prNotFound = ++pParse->nMem; } } } } } if( eType==0 ){ int rMayHaveNull = 0; if( prNotFound ){ *prNotFound = rMayHaveNull = ++pParse->nMem; } sqlite3CodeSubselect(pParse, pX, rMayHaveNull); eType = IN_INDEX_EPH; }else{ pX->iTable = iTab; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -