📄 select.c
字号:
p->pRightmost->usesVirt = 1; } createSortingIndex(pParse, p, pOrderBy); assert( p->pEList ); } /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff); if( rc ){ goto multi_select_end; } /* Code the current SELECT statement */ switch( p->op ){ case TK_EXCEPT: op = SRT_Except; break; case TK_UNION: op = SRT_Union; break; case TK_ALL: op = SRT_Table; break; } p->pPrior = 0; p->pOrderBy = 0; p->disallowOrderBy = pOrderBy!=0; pLimit = p->pLimit; p->pLimit = 0; pOffset = p->pOffset; p->pOffset = 0; rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff); p->pPrior = pPrior; p->pOrderBy = pOrderBy; sqlite3ExprDelete(p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; p->iLimit = -1; p->iOffset = -1; if( rc ){ goto multi_select_end; } /* Convert the data in the temporary table into whatever form ** it is that we currently need. */ if( eDest!=priorOp || unionTab!=iParm ){ int iCont, iBreak, iStart; assert( p->pEList ); if( eDest==SRT_Callback ){ generateColumnNames(pParse, 0, p->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak); computeLimitRegisters(pParse, p); iStart = sqlite3VdbeCurrentAddr(v); rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, pOrderBy, -1, eDest, iParm, iCont, iBreak, 0); if( rc ){ rc = 1; goto multi_select_end; } sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp(v, OP_Next, unionTab, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp(v, OP_Close, unionTab, 0); } break; } case TK_INTERSECT: { int tab1, tab2; int iCont, iBreak, iStart; Expr *pLimit, *pOffset; int addr; /* INTERSECT is different from the others since it requires ** two temporary tables. Hence it has its own case. Begin ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; if( pOrderBy && matchOrderbyToColumn(pParse,p,pOrderBy,tab1,1) ){ rc = 1; goto multi_select_end; } createSortingIndex(pParse, p, pOrderBy); addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0); assert( p->addrOpenVirt[0] == -1 ); p->addrOpenVirt[0] = addr; p->pRightmost->usesVirt = 1; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff); if( rc ){ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0); assert( p->addrOpenVirt[1] == -1 ); p->addrOpenVirt[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; pOffset = p->pOffset; p->pOffset = 0; rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff); p->pPrior = pPrior; sqlite3ExprDelete(p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; if( rc ){ goto multi_select_end; } /* Generate code to take the intersection of the two temporary ** tables. */ assert( p->pEList ); if( eDest==SRT_Callback ){ generateColumnNames(pParse, 0, p->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak); computeLimitRegisters(pParse, p); iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0); sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont); rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, pOrderBy, -1, eDest, iParm, iCont, iBreak, 0); if( rc ){ rc = 1; goto multi_select_end; } sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp(v, OP_Next, tab1, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp(v, OP_Close, tab2, 0); sqlite3VdbeAddOp(v, OP_Close, tab1, 0); break; } } /* Make sure all SELECTs in the statement have the same number of elements ** in their result sets. */ assert( p->pEList && pPrior->pEList ); if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" " do not have the same number of result columns", selectOpName(p->op)); rc = 1; goto multi_select_end; } /* Set the number of columns in temporary tables */ nCol = p->pEList->nExpr; while( nSetP2 ){ sqlite3VdbeChangeP2(v, aSetP2[--nSetP2], nCol); } /* Compute collating sequences used by either the ORDER BY clause or ** by any temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. Invoke the ** ORDER BY processing if there is an ORDER BY clause. ** ** This section is run by the right-most SELECT statement only. ** SELECT statements to the left always skip this part. The right-most ** SELECT might also skip this part if it has no ORDER BY clause and ** no temp tables are required. */ if( pOrderBy || p->usesVirt ){ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ Select *pLoop; /* For looping through SELECT statements */ CollSeq **apColl; CollSeq **aCopy; assert( p->pRightmost==p ); pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*2*sizeof(CollSeq*) + nCol); if( !pKeyInfo ){ rc = SQLITE_NOMEM; goto multi_select_end; } pKeyInfo->enc = pParse->db->enc; pKeyInfo->nField = nCol; for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){ *apColl = multiSelectCollSeq(pParse, p, i); if( 0==*apColl ){ *apColl = pParse->db->pDfltColl; } } for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ for(i=0; i<2; i++){ int addr = pLoop->addrOpenVirt[i]; if( addr<0 ){ /* If [0] is unused then [1] is also unused. So we can ** always safely abort as soon as the first unused slot is found */ assert( pLoop->addrOpenVirt[1]<0 ); break; } sqlite3VdbeChangeP2(v, addr, nCol); sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO); } } if( pOrderBy ){ struct ExprList_item *pOTerm = pOrderBy->a; int nExpr = pOrderBy->nExpr; int addr; u8 *pSortOrder; aCopy = (CollSeq**)&pKeyInfo[1]; pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nExpr]; memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*)); apColl = pKeyInfo->aColl; for(i=0; i<pOrderBy->nExpr; i++, pOTerm++, apColl++, pSortOrder++){ Expr *pExpr = pOTerm->pExpr; char *zName = pOTerm->zName; assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol ); if( zName ){ *apColl = sqlite3LocateCollSeq(pParse, zName, -1); }else{ *apColl = aCopy[pExpr->iColumn]; } *pSortOrder = pOTerm->sortOrder; } assert( p->pRightmost==p ); assert( p->addrOpenVirt[2]>=0 ); addr = p->addrOpenVirt[2]; sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2); pKeyInfo->nField = pOrderBy->nExpr; sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); pKeyInfo = 0; generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm); } sqliteFree(pKeyInfo); }multi_select_end: return rc;}#endif /* SQLITE_OMIT_COMPOUND_SELECT */#ifndef SQLITE_OMIT_VIEW/*** Scan through the expression pExpr. Replace every reference to** a column in table number iTable with a copy of the iColumn-th** entry in pEList. (But leave references to the ROWID column ** unchanged.)**** This routine is part of the flattening procedure. A subquery** whose result set is defined by pEList appears as entry in the** FROM clause of a SELECT such that the VDBE cursor assigned to that** FORM clause entry is iTable. This routine make the necessary ** changes to pExpr so that it refers directly to the source table** of the subquery rather the result set of the subquery.*/static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */static void substSelect(Select *, int, ExprList *); /* Forward Decl */static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){ if( pExpr==0 ) return; if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){ if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else{ Expr *pNew; assert( pEList!=0 && pExpr->iColumn<pEList->nExpr ); assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 ); pNew = pEList->a[pExpr->iColumn].pExpr; assert( pNew!=0 ); pExpr->op = pNew->op; assert( pExpr->pLeft==0 ); pExpr->pLeft = sqlite3ExprDup(pNew->pLeft); assert( pExpr->pRight==0 ); pExpr->pRight = sqlite3ExprDup(pNew->pRight); assert( pExpr->pList==0 ); pExpr->pList = sqlite3ExprListDup(pNew->pList); pExpr->iTable = pNew->iTable; pExpr->iColumn = pNew->iColumn; pExpr->iAgg = pNew->iAgg; sqlite3TokenCopy(&pExpr->token, &pNew->token); sqlite3TokenCopy(&pExpr->span, &pNew->span); pExpr->pSelect = sqlite3SelectDup(pNew->pSelect); pExpr->flags = pNew->flags; } }else{ substExpr(pExpr->pLeft, iTable, pEList); substExpr(pExpr->pRight, iTable, pEList); substSelect(pExpr->pSelect, iTable, pEList); substExprList(pExpr->pList, iTable, pEList); }}static void substExprList(ExprList *pList, int iTable, ExprList *pEList){ int i; if( pList==0 ) return; for(i=0; i<pList->nExpr; i++){ substExpr(pList->a[i].pExpr, iTable, pEList); }}static void substSelect(Select *p, int iTable, ExprList *pEList){ if( !p ) return; substExprList(p->pEList, iTable, pEList); substExprList(p->pGroupBy, iTable, pEList); substExprList(p->pOrderBy, iTable, pEList); substExpr(p->pHaving, iTable, pEList); substExpr(p->pWhere, iTable, pEList);}#endif /* !defined(SQLITE_OMIT_VIEW) */#ifndef SQLITE_OMIT_VIEW/*** This routine attempts to flatten subqueries in order to speed** execution. It returns 1 if it makes changes and 0 if no flattening** occurs.**** To understand the concept of flattening, consider the following** query:**** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5**** The default way of implementing this query is to execute the** subquery first and store the results in a temporary table, then** run the outer query on that temporary table. This requires two** passes over the data. Furthermore, because the temporary table** has no indices, the WHERE clause on the outer query cannot be** optimized.**** This routine attempts to rewrite queries such as the above into** a single flat select, like this:**** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5**** The code generated for this simpification gives the same result** but only has to scan the data once. And because indices might ** exist on the table t1, a complete scan of the data might be** avoided.**** Flattening is only attempted if all of the following are true:**** (1) The subquery and the outer query do not both use aggregates.**** (2) The subquery is not an aggregate or the outer query is not a join.**** (3) The subquery is not the right operand of a left outer join, or** the subquery is not itself a join. (Ticket #306)**** (4) The subquery is not DISTINCT or the outer query is not a join.**** (5) The subquery is not DISTINCT or the outer query does not use** aggregates.**** (6) The subquery does not use aggregates or the outer query is not** DISTINCT.**** (7) The subquery has a FROM clause.**** (8) The subquery does not use LIMIT or the outer query is not a join.**** (9) The subquery does not use LIMIT or the outer query does not use** aggregates.**** (10) The subquery does not use aggregates or the outer query does not** use LIMIT.**** (11) The subquery and the outer query do not both have ORDER BY clauses.**** (12) The subquery is not the right term of a LEFT OUTER JOIN or the** subquery has no WHERE clause. (added by ticket #350)**** In this routine, the "p" parameter is a pointer to the outer query.** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.**** If flattening is not attempted, this routine is a no-op and returns 0.** If flattening is attempted this routine returns 1.**** All of the expression analysis must occur on both the outer query and** the subquery before this routine runs.*/static int flattenSubquery( Parse *pParse, /* The parsing context */ Select *p, /* The parent or outer SELECT statemen
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -