📄 expr.c
字号:
int eType = 0; int iTab = pParse->nTab++; /* 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. */ if( sqlite3_enable_in_opt && (p=pX->pSelect)!=0 && !p->pPrior && !p->isDistinct && !p->isAgg && !p->pGroupBy && p->pSrc && p->pSrc->nSrc==1 && !p->pSrc->a[0].pSelect && p->pSrc->a[0].pTab && !p->pSrc->a[0].pTab->pSelect && p->pEList->nExpr==1 && p->pEList->a[0].pExpr->op==TK_COLUMN && !p->pLimit && !p->pOffset && !p->pWhere ){ 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( eType==0 ){ sqlite3CodeSubselect(pParse, pX); eType = IN_INDEX_EPH; }else{ pX->iTable = iTab; } 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 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 */ 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, 0, 0, 0, 0) ){ 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; if( !affinity ){ affinity = SQLITE_AFF_NONE; } keyInfo.aColl[0] = pExpr->pLeft->pColl; /* 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++; sqlite3ExprCode(pParse, pE2, r1); assert( pParse->disableColCache>0 ); pParse->disableColCache--; sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); sqlite3ExprCacheAffinityChange(pParse, r1, 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(pSel->pLimit); pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one); if( sqlite3Select(pParse, pSel, &dest, 0, 0, 0, 0) ){ 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( 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, const char *z, int n, int negFlag, int iMem){ assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed ); if( z ){ int i; 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 curs
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -