mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-10 01:02:56 +03:00
Slight simplification to the query optimizer logic associated with IN (SELECT).
FossilOrigin-Name: 2c55c3c2950cafdc256ab540f60dc4609b9c354b
This commit is contained in:
34
src/expr.c
34
src/expr.c
@@ -1568,24 +1568,22 @@ int sqlite3IsRowid(const char *z){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if we are able to the IN operator optimization on a
|
||||
** query of the form
|
||||
**
|
||||
** x IN (SELECT ...)
|
||||
**
|
||||
** Where the SELECT... clause is as specified by the parameter to this
|
||||
** routine.
|
||||
**
|
||||
** The Select object passed in has already been preprocessed and no
|
||||
** errors have been found.
|
||||
** pX is the RHS of an IN operator. If pX is a SELECT statement
|
||||
** that can be simplified to a direct table access, then return
|
||||
** a pointer to the SELECT statement. If pX is not a SELECT statement,
|
||||
** or if the SELECT statement needs to be manifested into a transient
|
||||
** table, then return NULL.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
static int isCandidateForInOpt(Select *p){
|
||||
static Select *isCandidateForInOpt(Expr *pX){
|
||||
Select *p;
|
||||
SrcList *pSrc;
|
||||
ExprList *pEList;
|
||||
Expr *pRes;
|
||||
Table *pTab;
|
||||
Expr *pRes; /* Result expression */
|
||||
if( p==0 ) return 0; /* right-hand side of IN is SELECT */
|
||||
if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
|
||||
if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
|
||||
p = pX->x.pSelect;
|
||||
if( p->pPrior ) return 0; /* Not a compound SELECT */
|
||||
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
|
||||
testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
|
||||
@@ -1601,15 +1599,15 @@ static int isCandidateForInOpt(Select *p){
|
||||
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
|
||||
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
|
||||
pTab = pSrc->a[0].pTab;
|
||||
if( NEVER(pTab==0) ) return 0;
|
||||
assert( pTab!=0 );
|
||||
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
|
||||
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
|
||||
pEList = p->pEList;
|
||||
if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
|
||||
pRes = pEList->a[0].pExpr;
|
||||
if( pRes->op!=TK_COLUMN ) return 0; /* Result is a column */
|
||||
if( pRes->iTable!=pSrc->a[0].iCursor ) return 0; /* Not a correlated subq */
|
||||
return 1;
|
||||
assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
|
||||
return p;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
@@ -1741,15 +1739,13 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||
** satisfy the query. This is preferable to generating a new
|
||||
** ephemeral table.
|
||||
*/
|
||||
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||
if( pParse->nErr==0 && isCandidateForInOpt(p) ){
|
||||
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
i16 iCol; /* Index of column <column> */
|
||||
i16 iDb; /* Database idx for pTab */
|
||||
|
||||
assert( p ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
|
Reference in New Issue
Block a user