📄 expr.c
字号:
/*** Generate code to copy content from registers iFrom...iFrom+nReg-1** over to iTo..iTo+nReg-1.*/void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){ int i; if( iFrom==iTo ) return; for(i=0; i<nReg; i++){ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, iFrom+i, iTo+i); }}/*** Return true if any register in the range iFrom..iTo (inclusive)** is used as part of the column cache.*/static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ int i; for(i=0; i<pParse->nColCache; i++){ int r = pParse->aColCache[i].iReg; if( r>=iFrom && r<=iTo ) return 1; } return 0;}/*** Theres is a value in register iCurrent. We ultimately want** the value to be in register iTarget. It might be that** iCurrent and iTarget are the same register.**** We are going to modify the value, so we need to make sure it** is not a cached register. If iCurrent is a cached register,** then try to move the value over to iTarget. If iTarget is a** cached register, then clear the corresponding cache line.**** Return the register that the value ends up in.*/int sqlite3ExprWritableRegister(Parse *pParse, int iCurrent, int iTarget){ int i; assert( pParse->pVdbe!=0 ); if( !usedAsColumnCache(pParse, iCurrent, iCurrent) ){ return iCurrent; } if( iCurrent!=iTarget ){ sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, iCurrent, iTarget); } for(i=0; i<pParse->nColCache; i++){ if( pParse->aColCache[i].iReg==iTarget ){ pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache]; pParse->iColCache = pParse->nColCache; } } return iTarget;}/*** If the last instruction coded is an ephemeral copy of any of** the registers in the nReg registers beginning with iReg, then** convert the last instruction from OP_SCopy to OP_Copy.*/void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){ int addr; VdbeOp *pOp; Vdbe *v; v = pParse->pVdbe; addr = sqlite3VdbeCurrentAddr(v); pOp = sqlite3VdbeGetOp(v, addr-1); assert( pOp || pParse->db->mallocFailed ); if( pOp && pOp->opcode==OP_SCopy && pOp->p1>=iReg && pOp->p1<iReg+nReg ){ pOp->opcode = OP_Copy; }}/*** Generate code to store the value of the iAlias-th alias in register** target. The first time this is called, pExpr is evaluated to compute** the value of the alias. The value is stored in an auxiliary register** and the number of that register is returned. On subsequent calls,** the register number is returned without generating any code.**** Note that in order for this to work, code must be generated in the** same order that it is executed.**** Aliases are numbered starting with 1. So iAlias is in the range** of 1 to pParse->nAlias inclusive. **** pParse->aAlias[iAlias-1] records the register number where the value** of the iAlias-th alias is stored. If zero, that means that the** alias has not yet been computed.*/static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){ sqlite3 *db = pParse->db; int iReg; if( pParse->aAlias==0 ){ pParse->aAlias = sqlite3DbMallocZero(db, sizeof(pParse->aAlias[0])*pParse->nAlias ); if( db->mallocFailed ) return 0; } assert( iAlias>0 && iAlias<=pParse->nAlias ); iReg = pParse->aAlias[iAlias-1]; if( iReg==0 ){ if( pParse->disableColCache ){ iReg = sqlite3ExprCodeTarget(pParse, pExpr, target); }else{ iReg = ++pParse->nMem; sqlite3ExprCode(pParse, pExpr, iReg); pParse->aAlias[iAlias-1] = iReg; } } return iReg;}/*** Generate code into the current Vdbe to evaluate the given** expression. Attempt to store the results in register "target".** Return the register where results are stored.**** With this routine, there is no guarantee that results will** be stored in target. The result might be stored in some other** register if it is convenient to do so. The calling function** must check the return code and move the results to the desired** register.*/int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; /* The VM under construction */ int op; /* The opcode being coded */ int inReg = target; /* Results stored in register inReg */ int regFree1 = 0; /* If non-zero free this temporary register */ int regFree2 = 0; /* If non-zero free this temporary register */ int r1, r2, r3, r4; /* Various register numbers */ sqlite3 *db; db = pParse->db; assert( v!=0 || db->mallocFailed ); assert( target>0 && target<=pParse->nMem ); if( v==0 ) return 0; if( pExpr==0 ){ op = TK_NULL; }else{ op = pExpr->op; } switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ assert( pCol->iMem>0 ); inReg = pCol->iMem; break; }else if( pAggInfo->useSortingIdx ){ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdx, pCol->iSorterColumn, target); break; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ assert( pParse->ckBase>0 ); inReg = pExpr->iColumn + pParse->ckBase; }else{ testcase( (pExpr->flags & EP_AnyAff)!=0 ); inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, pExpr->iColumn, pExpr->iTable, target, pExpr->flags & EP_AnyAff); } break; } case TK_INTEGER: { codeInteger(v, pExpr, 0, target); break; } case TK_FLOAT: { codeReal(v, (char*)pExpr->token.z, pExpr->token.n, 0, target); break; } case TK_STRING: { sqlite3DequoteExpr(db, pExpr); sqlite3VdbeAddOp4(v,OP_String8, 0, target, 0, (char*)pExpr->token.z, pExpr->token.n); break; } case TK_NULL: { sqlite3VdbeAddOp2(v, OP_Null, 0, target); break; }#ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { int n; const char *z; char *zBlob; assert( pExpr->token.n>=3 ); assert( pExpr->token.z[0]=='x' || pExpr->token.z[0]=='X' ); assert( pExpr->token.z[1]=='\'' ); assert( pExpr->token.z[pExpr->token.n-1]=='\'' ); n = pExpr->token.n - 3; z = (char*)pExpr->token.z + 2; zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n); sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC); break; }#endif case TK_VARIABLE: { sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iTable, target); if( pExpr->token.n>1 ){ sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n); } break; } case TK_REGISTER: { inReg = pExpr->iTable; break; } case TK_AS: { inReg = codeAlias(pParse, pExpr->iTable, pExpr->pLeft, target); break; }#ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ int aff, to_op; inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); aff = sqlite3AffinityType(&pExpr->token); to_op = aff - SQLITE_AFF_TEXT + OP_ToText; assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT ); assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE ); assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); testcase( to_op==OP_ToText ); testcase( to_op==OP_ToBlob ); testcase( to_op==OP_ToNumeric ); testcase( to_op==OP_ToInt ); testcase( to_op==OP_ToReal ); if( inReg!=target ){ sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } sqlite3VdbeAddOp1(v, to_op, inReg); testcase( usedAsColumnCache(pParse, inReg, inReg) ); sqlite3ExprCacheAffinityChange(pParse, inReg, 1); break; }#endif /* SQLITE_OMIT_CAST */ case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { assert( TK_LT==OP_Lt ); assert( TK_LE==OP_Le ); assert( TK_GT==OP_Gt ); assert( TK_GE==OP_Ge ); assert( TK_EQ==OP_Eq ); assert( TK_NE==OP_Ne ); testcase( op==TK_LT ); testcase( op==TK_LE ); testcase( op==TK_GT ); testcase( op==TK_GE ); testcase( op==TK_EQ ); testcase( op==TK_NE ); codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_AND: case TK_OR: case TK_PLUS: case TK_STAR: case TK_MINUS: case TK_REM: case TK_BITAND: case TK_BITOR: case TK_SLASH: case TK_LSHIFT: case TK_RSHIFT: case TK_CONCAT: { assert( TK_AND==OP_And ); assert( TK_OR==OP_Or ); assert( TK_PLUS==OP_Add ); assert( TK_MINUS==OP_Subtract ); assert( TK_REM==OP_Remainder ); assert( TK_BITAND==OP_BitAnd ); assert( TK_BITOR==OP_BitOr ); assert( TK_SLASH==OP_Divide ); assert( TK_LSHIFT==OP_ShiftLeft ); assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_CONCAT==OP_Concat ); testcase( op==TK_AND ); testcase( op==TK_OR ); testcase( op==TK_PLUS ); testcase( op==TK_MINUS ); testcase( op==TK_REM ); testcase( op==TK_BITAND ); testcase( op==TK_BITOR ); testcase( op==TK_SLASH ); testcase( op==TK_LSHIFT ); testcase( op==TK_RSHIFT ); testcase( op==TK_CONCAT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); sqlite3VdbeAddOp3(v, op, r2, r1, target); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_UMINUS: { Expr *pLeft = pExpr->pLeft; assert( pLeft ); if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){ if( pLeft->op==TK_FLOAT ){ codeReal(v, (char*)pLeft->token.z, pLeft->token.n, 1, target); }else{ codeInteger(v, pLeft, 1, target); } }else{ regFree1 = r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Integer, 0, r1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); testcase( regFree2==0 ); } inReg = target; break; } case TK_BITNOT: case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); assert( TK_NOT==OP_Not ); testcase( op==TK_BITNOT ); testcase( op==TK_NOT ); inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); testcase( inReg==target ); testcase( usedAsColumnCache(pParse, inReg, inReg) ); inReg = sqlite3ExprWritableRegister(pParse, inReg, target); sqlite3VdbeAddOp1(v, op, inReg); break; } case TK_ISNULL: case TK_NOTNULL: { int addr; assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_ISNULL ); testcase( op==TK_NOTNULL ); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); addr = sqlite3VdbeAddOp1(v, op, r1); sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeJumpHere(v, addr); break; } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; if( pInfo==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate: %T", &pExpr->span); }else{ inReg = pInfo->aFunc[pExpr->iAgg].iMem; } break; } case TK_CONST_FUNC: case TK_FUNCTION: { ExprList *pList = pExpr->pList; int nExpr = pList ? pList->nExpr : 0; FuncDef *pDef; int nId; const char *zId; int constMask = 0; int i; u8 enc = ENC(db); CollSeq *pColl = 0; testcase( op==TK_CONST_FUNC ); testcase( op==TK_FUNCTION ); zId = (char*)pExpr->token.z; nId = pExpr->token.n; pDef = sqlite3FindFunction(db, zId, nId, nExpr, enc, 0); assert( pDef!=0 ); if( pList ){ nExpr = pList->nExpr; r1 = sqlite3GetTempRange(pParse, nExpr); sqlite3ExprCodeExprList(pParse, pList, r1, 1); }else{ nExpr = r1 = 0; }#ifndef SQLITE_OMIT_VIRTUALTABLE /* Possibly overload the function if the first argument is ** a virtual table column. ** ** For infix functions (LIKE, GLOB, REGEXP, and MATCH) use the ** second argument, not the first, as the argument to test to ** see if it is a column in a virtual table. This is done because ** the left operand of infix functions (the operand we want to ** control overloading) ends up as the second argument to the ** function. Th
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -