?? expr.c
字號:
** Expr.opcode for such nodes is changed to TK_COLUMN. The Expr.iTable** value is changed to the index of the referenced table in pTabList** plus the "base" value. The base value will ultimately become the** VDBE cursor number for a cursor that is pointing into the referenced** table. The Expr.iColumn value is changed to the index of the column ** of the referenced table. The Expr.iColumn value for the special** ROWID column is -1. Any INTEGER PRIMARY KEY column is tried as an** alias for ROWID.**** Also resolve function names and check the functions for proper** usage. Make sure all function names are recognized and all functions** have the correct number of arguments. Leave an error message** in pParse->zErrMsg if anything is amiss. Return the number of errors.**** If the expression contains aggregate functions then set the EP_Agg** property on the expression.*/int sqlite3ExprResolveNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */){ int savedHasAgg; if( pExpr==0 ) return 0; savedHasAgg = pNC->hasAgg; pNC->hasAgg = 0; walkExprTree(pExpr, nameResolverStep, pNC); if( pNC->nErr>0 ){ ExprSetProperty(pExpr, EP_Error); } if( pNC->hasAgg ){ ExprSetProperty(pExpr, EP_Agg); }else if( savedHasAgg ){ pNC->hasAgg = 1; } return ExprHasProperty(pExpr, EP_Error);}/*** A pointer instance of this structure is used to pass information** through walkExprTree into codeSubqueryStep().*/typedef struct QueryCoder QueryCoder;struct QueryCoder { Parse *pParse; /* The parsing context */ NameContext *pNC; /* Namespace of first enclosing query */};/*** Generate code for scalar subqueries used as an expression** and IN operators. Examples:**** (SELECT a FROM b) -- subquery** EXISTS (SELECT a FROM b) -- EXISTS subquery** x IN (4,5,11) -- IN operator with list on right-hand side** x IN (SELECT a FROM b) -- IN operator with subquery on the right**** The pExpr parameter describes the expression that contains the IN** operator or subquery.*/#ifndef SQLITE_OMIT_SUBQUERYvoid sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int testAddr = 0; /* One-time test address */ Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; /* This code must be run in its entirety every time it is encountered ** if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** ** If all of the above are false, then we can run this code just once ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ int mem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); assert( testAddr>0 || sqlite3MallocFailed() ); sqlite3VdbeAddOp(v, OP_MemInt, 1, mem); } switch( pExpr->op ){ case TK_IN: { char affinity; KeyInfo keyInfo; int addr; /* Address of OP_OpenVirtual instruction */ affinity = sqlite3ExprAffinity(pExpr->pLeft); /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)' ** expression it is handled the same way. A virtual table is ** filled with single-field index keys representing the results ** from the SELECT or the <exprlist>. ** ** If the 'x' expression is a column value, or the SELECT... ** statement returns a column value, then the affinity of that ** column is used to build the index keys. If both 'x' and the ** SELECT... statement are columns, then numeric affinity is used ** if either column has NUMERIC or INTEGER affinity. If neither ** 'x' nor the SELECT... statement are columns, then numeric affinity ** is used. */ pExpr->iTable = pParse->nTab++; addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, pExpr->iTable, 0); memset(&keyInfo, 0, sizeof(keyInfo)); keyInfo.nField = 1; sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1); if( pExpr->pSelect ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ int iParm = pExpr->iTable + (((int)affinity)<<16); ExprList *pEList; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0); pEList = pExpr->pSelect->pEList; if( pEList && pEList->nExpr>0 ){ keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft, pEList->a[0].pExpr); } }else if( pExpr->pList ){ /* Case 2: expr IN (exprlist) ** ** For each expression, build an index key from the evaluation and ** store it in the temporary table. If <expr> is a column, then use ** that columns affinity when building index keys. If <expr> is not ** a column, use numeric affinity. */ int i; ExprList *pList = pExpr->pList; struct ExprList_item *pItem; if( !affinity ){ affinity = SQLITE_AFF_NUMERIC; } keyInfo.aColl[0] = pExpr->pLeft->pColl; /* Loop through each expression in <exprlist>. */ for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; /* If the expression is not constant then we will need to ** disable the test that was generated above that makes sure ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, testAddr-1, 3); testAddr = 0; } /* Evaluate the expression and insert it into the temp table */ sqlite3ExprCode(pParse, pE2); sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, pExpr->iTable, 0); } } sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO); break; } case TK_EXISTS: case TK_SELECT: { /* This has to be a scalar SELECT. Generate code to put the ** value of this select in a memory cell and record the number ** of the memory cell in iColumn. */ static const Token one = { (u8*)"1", 0, 1 }; Select *pSel; int iMem; int sop; pExpr->iColumn = iMem = pParse->nMem++; pSel = pExpr->pSelect; if( pExpr->op==TK_SELECT ){ sop = SRT_Mem; sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0); VdbeComment((v, "# Init subquery result")); }else{ sop = SRT_Exists; sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem); VdbeComment((v, "# Init EXISTS result")); } sqlite3ExprDelete(pSel->pLimit); pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one); sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0); break; } } if( testAddr ){ sqlite3VdbeJumpHere(v, testAddr); } return;}#endif /* SQLITE_OMIT_SUBQUERY *//*** Generate an instruction that will put the integer describe by** text z[0..n-1] on the stack.*/static void codeInteger(Vdbe *v, const char *z, int n){ int i; if( sqlite3GetInt32(z, &i) ){ sqlite3VdbeAddOp(v, OP_Integer, i, 0); }else if( sqlite3FitsIn64Bits(z) ){ sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n); }else{ sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n); }}/*** Generate code into the current Vdbe to evaluate the given** expression and leave the result on the top of stack.**** This code depends on the fact that certain token values (ex: TK_EQ)** are the same as opcode values (ex: OP_Eq) that implement the corresponding** operation. Special comments in vdbe.c and the mkopcodeh.awk script in** the make process cause these values to align. Assert()s in the code** below verify that the numbers are aligned correctly.*/void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ Vdbe *v = pParse->pVdbe; int op; int stackChng = 1; /* Amount of change to stack depth */ if( v==0 ) return; if( pExpr==0 ){ sqlite3VdbeAddOp(v, OP_Null, 0, 0); return; } op = pExpr->op; switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ sqlite3VdbeAddOp(v, OP_MemLoad, pCol->iMem, 0); break; }else if( pAggInfo->useSortingIdx ){ sqlite3VdbeAddOp(v, OP_Column, pAggInfo->sortingIdx, pCol->iSorterColumn); 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->ckOffset>0 ); sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1); }else if( pExpr->iColumn>=0 ){ Table *pTab = pExpr->pTab; int iCol = pExpr->iColumn; sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, iCol); sqlite3ColumnDefault(v, pTab, iCol);#ifndef SQLITE_OMIT_FLOATING_POINT if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0); }#endif }else{ sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0); } break; } case TK_INTEGER: { codeInteger(v, (char*)pExpr->token.z, pExpr->token.n); break; } case TK_FLOAT: case TK_STRING: { assert( TK_FLOAT==OP_Real ); assert( TK_STRING==OP_String8 ); sqlite3DequoteExpr(pExpr); sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n); break; } case TK_NULL: { sqlite3VdbeAddOp(v, OP_Null, 0, 0); break; }#ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { int n; const char *z; assert( TK_BLOB==OP_HexBlob ); n = pExpr->token.n - 3; z = (char*)pExpr->token.z + 2; assert( n>=0 ); if( n==0 ){ z = ""; } sqlite3VdbeOp3(v, op, 0, 0, z, n); break; }#endif case TK_VARIABLE: { sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0); if( pExpr->token.n>1 ){ sqlite3VdbeChangeP3(v, -1, (char*)pExpr->token.z, pExpr->token.n); } break; } case TK_REGISTER: { sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iTable, 0); break; }#ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ int aff, to_op; sqlite3ExprCode(pParse, pExpr->pLeft); 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 ); sqlite3VdbeAddOp(v, to_op, 0, 0); stackChng = 0; 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 ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0); stackChng = -1; 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 ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); sqlite3VdbeAddOp(v, op, 0, 0); stackChng = -1; break; } case TK_UMINUS: { Expr *pLeft = pExpr->pLeft; assert( pLeft ); if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){ Token *p = &pLeft->token; char *z = sqlite3MPrintf("-%.*s", p->n, p->z); if( pLeft->op==TK_FLOAT ){ sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1); }else{ codeInteger(v, z, p->n+1); } sqliteFree(z); break; } /* Fall through into TK_NOT */ } case TK_BITNOT: case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); assert( TK_NOT==OP_Not ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3VdbeAddOp(v, op, 0, 0); stackChng = 0; break; } case TK_ISNULL: case TK_NOTNULL: { int dest; assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -