📄 expr.c
字号:
return eType;}#endif/*** 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 rMayHaveNull){ 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; sqlite3VdbeAddOp1(v, OP_If, mem); testAddr = sqlite3VdbeAddOp2(v, OP_Integer, 1, mem); assert( testAddr>0 || pParse->db->mallocFailed ); } switch( pExpr->op ){ case TK_IN: { char affinity; KeyInfo keyInfo; int addr; /* Address of OP_OpenEphemeral instruction */ if( rMayHaveNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull); } 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 = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, 1); memset(&keyInfo, 0, sizeof(keyInfo)); keyInfo.nField = 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. */ SelectDest dest; ExprList *pEList; sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affinity = (int)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); if( sqlite3Select(pParse, pExpr->pSelect, &dest) ){ return; } pEList = pExpr->pSelect->pEList; if( pEList && pEList->nExpr>0 ){ keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(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; int r1, r2, r3; if( !affinity ){ affinity = SQLITE_AFF_NONE; } keyInfo.aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); /* Loop through each expression in <exprlist>. */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); 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 && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, testAddr-1, 2); testAddr = 0; } /* Evaluate the expression and insert it into the temp table */ pParse->disableColCache++; r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); assert( pParse->disableColCache>0 ); pParse->disableColCache--; sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); sqlite3ExprCacheAffinityChange(pParse, r3, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2); } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_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; SelectDest dest; pSel = pExpr->pSelect; sqlite3SelectDestInit(&dest, 0, ++pParse->nMem); if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iParm); VdbeComment((v, "Init subquery result")); }else{ dest.eDest = SRT_Exists; sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm); VdbeComment((v, "Init EXISTS result")); } sqlite3ExprDelete(pParse->db, pSel->pLimit); pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one); if( sqlite3Select(pParse, pSel, &dest) ){ return; } pExpr->iColumn = dest.iParm; break; } } if( testAddr ){ sqlite3VdbeJumpHere(v, testAddr-1); } return;}#endif /* SQLITE_OMIT_SUBQUERY *//*** Duplicate an 8-byte value*/static char *dup8bytes(Vdbe *v, const char *in){ char *out = sqlite3DbMallocRaw(sqlite3VdbeDb(v), 8); if( out ){ memcpy(out, in, 8); } return out;}/*** Generate an instruction that will put the floating point** value described by z[0..n-1] into register iMem.**** The z[] string will probably not be zero-terminated. But the ** z[n] character is guaranteed to be something that does not look** like the continuation of the number.*/static void codeReal(Vdbe *v, const char *z, int n, int negateFlag, int iMem){ assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed ); if( z ){ double value; char *zV; assert( !isdigit(z[n]) ); sqlite3AtoF(z, &value); if( sqlite3IsNaN(value) ){ sqlite3VdbeAddOp2(v, OP_Null, 0, iMem); }else{ if( negateFlag ) value = -value; zV = dup8bytes(v, (char*)&value); sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL); } }}/*** Generate an instruction that will put the integer describe by** text z[0..n-1] into register iMem.**** The z[] string will probably not be zero-terminated. But the ** z[n] character is guaranteed to be something that does not look** like the continuation of the number.*/static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){ const char *z; if( pExpr->flags & EP_IntValue ){ int i = pExpr->iTable; if( negFlag ) i = -i; sqlite3VdbeAddOp2(v, OP_Integer, i, iMem); }else if( (z = (char*)pExpr->token.z)!=0 ){ int i; int n = pExpr->token.n; assert( !isdigit(z[n]) ); if( sqlite3GetInt32(z, &i) ){ if( negFlag ) i = -i; sqlite3VdbeAddOp2(v, OP_Integer, i, iMem); }else if( sqlite3FitsIn64Bits(z, negFlag) ){ i64 value; char *zV; sqlite3Atoi64(z, &value); if( negFlag ) value = -value; zV = dup8bytes(v, (char*)&value); sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64); }else{ codeReal(v, z, n, negFlag, iMem); } }}/*** Generate code that will extract the iColumn-th column from** table pTab and store the column value in a register. An effort** is made to store the column value in register iReg, but this is** not guaranteed. The location of the column value is returned.**** There must be an open cursor to pTab in iTable when this routine** is called. If iColumn<0 then code is generated that extracts the rowid.**** This routine might attempt to reuse the value of the column that** has already been loaded into a register. The value will always** be used if it has not undergone any affinity changes. But if** an affinity change has occurred, then the cached value will only be** used if allowAffChng is true.*/int sqlite3ExprCodeGetColumn( Parse *pParse, /* Parsing and code generating context */ Table *pTab, /* Description of the table we are reading from */ int iColumn, /* Index of the table column */ int iTable, /* The cursor pointing to the table */ int iReg, /* Store results here */ int allowAffChng /* True if prior affinity changes are OK */){ Vdbe *v = pParse->pVdbe; int i; struct yColCache *p; for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){ if( p->iTable==iTable && p->iColumn==iColumn && (!p->affChange || allowAffChng) ){#if 0 sqlite3VdbeAddOp0(v, OP_Noop); VdbeComment((v, "OPT: tab%d.col%d -> r%d", iTable, iColumn, p->iReg));#endif return p->iReg; } } assert( v!=0 ); if( iColumn<0 ){ int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid; sqlite3VdbeAddOp2(v, op, iTable, iReg); }else if( pTab==0 ){ sqlite3VdbeAddOp3(v, OP_Column, iTable, iColumn, iReg); }else{ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg); sqlite3ColumnDefault(v, pTab, iColumn);#ifndef SQLITE_OMIT_FLOATING_POINT if( pTab->aCol[iColumn].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); }#endif } if( pParse->disableColCache==0 ){ i = pParse->iColCache; p = &pParse->aColCache[i]; p->iTable = iTable; p->iColumn = iColumn; p->iReg = iReg; p->affChange = 0; i++; if( i>=ArraySize(pParse->aColCache) ) i = 0; if( i>pParse->nColCache ) pParse->nColCache = i; pParse->iColCache = i; } return iReg;}/*** Clear all column cache entries associated with the vdbe** cursor with cursor number iTable.*/void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){ if( iTable<0 ){ pParse->nColCache = 0; pParse->iColCache = 0; }else{ int i; for(i=0; i<pParse->nColCache; i++){ if( pParse->aColCache[i].iTable==iTable ){ testcase( i==pParse->nColCache-1 ); pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache]; pParse->iColCache = pParse->nColCache; } } }}/*** Record the fact that an affinity change has occurred on iCount** registers starting with iStart.*/void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){ int iEnd = iStart + iCount - 1; int i; for(i=0; i<pParse->nColCache; i++){ int r = pParse->aColCache[i].iReg; if( r>=iStart && r<=iEnd ){ pParse->aColCache[i].affChange = 1; } }}/*** Generate code to move content from registers iFrom...iFrom+nReg-1** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.*/void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ int i; if( iFrom==iTo ) return; sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); for(i=0; i<pParse->nColCache; i++){ int x = pParse->aColCache[i].iReg; if( x>=iFrom && x<iFrom+nReg ){ pParse->aColCache[i].iReg += iTo-iFrom; } }}/*** 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){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -