diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/select.c | 74 | ||||
-rw-r--r-- | src/sqliteInt.h | 1 | ||||
-rw-r--r-- | src/update.c | 1 | ||||
-rw-r--r-- | src/vdbe.h | 1 |
4 files changed, 52 insertions, 25 deletions
diff --git a/src/select.c b/src/select.c index 886ac336f..8f3e5bb9a 100644 --- a/src/select.c +++ b/src/select.c @@ -6855,6 +6855,52 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){ } /* +** Return TRUE (non-zero) if the i-th entry in the pTabList SrcList can +** be implemented as a co-routine. The i-th entry is guaranteed to be +** a subquery. +** +** The subquery is implemented as a co-routine if all of the following are +** true: +** +** (1) Either of the following are true: +** (1a) The subquery must be the outer loop because it is either +** (i) the only term in the FROM clause, or because (ii) it +** is the left-most term and a CROSS JOIN or similar requires +** it to be the outer loop. subquery and there is nothing +** (1b) There is nothing that would prevent the subquery from +** being an outer loop and the SQLITE_PREPARE_SAFESQL flag +** is not set. +** (2) The subquery is not a CTE that should be materialized +** (3) The subquery is not part of a left operand for a RIGHT JOIN +** (4) The SQLITE_Coroutine optimization disable flag is not set +*/ +static int fromClauseTermCanBeCoroutine( + Parse *pParse, /* Parsing context */ + SrcList *pTabList, /* FROM clause */ + int i /* Which term of the FROM clause */ +){ + SrcItem *pItem = &pTabList->a[i]; + if( pItem->fg.isCte && pItem->u2.pCteUse->eM10d==M10d_Yes ) return 0;/* (2) */ + if( pTabList->a[0].fg.jointype & JT_LTORJ ) return 0; /* (3) */ + if( OptimizationDisabled(pParse->db, SQLITE_Coroutines) ) return 0; /* (4) */ + if( i==0 ){ + if( pTabList->nSrc==1 ) return 1; /* (1a-i) */ + if( pTabList->a[1].fg.jointype & JT_CROSS ) return 1; /* (1a-ii) */ + if( pParse->prepFlags & SQLITE_PREPARE_SAFEOPT ) return 0; + return 1; + } + if( pParse->prepFlags & SQLITE_PREPARE_SAFEOPT ) return 0; + while( 1 /*exit-by-break*/ ){ + if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; + if( i==0 ) break; + i--; + pItem--; + if( pItem->pSelect!=0 ) return 0; + } + return 1; +} + +/* ** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. @@ -7241,35 +7287,19 @@ int sqlite3Select( pParse->zAuthContext = pItem->zName; /* Generate code to implement the subquery - ** - ** The subquery is implemented as a co-routine if all of the following are - ** true: - ** - ** (1) the subquery is guaranteed to be the outer loop (so that - ** it does not need to be computed more than once), and - ** (2) the subquery is not a CTE that should be materialized - ** (3) the subquery is not part of a left operand for a RIGHT JOIN */ - if( i==0 - && (pTabList->nSrc==1 - || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0) /* (1) */ - && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */ - && (pTabList->a[0].fg.jointype & JT_LTORJ)==0 /* (3) */ - ){ + if( fromClauseTermCanBeCoroutine(pParse, pTabList, i) ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - int addrExplain; -#endif pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%!S", pItem)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); - ExplainQueryPlan2(addrExplain, (pParse, 1, "CO-ROUTINE %!S", pItem)); + ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; @@ -7277,10 +7307,6 @@ int sqlite3Select( sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); - /* For SQLITE_SCANSTAT_NCYCLE, all instructions from the - ** OP_InitCoroutine coded above until this point are attributed to - ** the CO-ROUTINE query element. */ - sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain-1, -1); }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ /* This is a CTE for which materialization code has already been ** generated. Invoke the subroutine to compute the materialization, @@ -7335,6 +7361,7 @@ int sqlite3Select( if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1); VdbeComment((v, "end %!S", pItem)); + sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); sqlite3VdbeJumpHere(v, topAddr); sqlite3ClearTempRegCache(pParse); if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ @@ -7344,9 +7371,6 @@ int sqlite3Select( pCteUse->iCur = pItem->iCursor; pCteUse->nRowEst = pSub->nSelectRow; } - /* For SQLITE_SCANSTAT_NCYCLE, all instructions from the - ** OP_Explain to here are attibuted to the MATERIALIZE element. */ - sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5a19058bd..393237358 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1844,6 +1844,7 @@ struct sqlite3 { #define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ #define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ +#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* diff --git a/src/update.c b/src/update.c index 809b30653..0612b2708 100644 --- a/src/update.c +++ b/src/update.c @@ -268,6 +268,7 @@ static void updateFromSelect( if( pSelect ) pSelect->selFlags |= SF_OrderByReqd; sqlite3SelectDestInit(&dest, eDest, iEph); dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1); + pParse->prepFlags |= SQLITE_PREPARE_SAFEOPT; sqlite3Select(pParse, pSelect, &dest); sqlite3SelectDelete(db, pSelect); } diff --git a/src/vdbe.h b/src/vdbe.h index 3caf1f787..17a301bd8 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -169,6 +169,7 @@ typedef struct VdbeOpList VdbeOpList; ** Additional non-public SQLITE_PREPARE_* flags */ #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ +#define SQLITE_PREPARE_SAFEOPT 0x40 /* Use only safe optimizations */ #define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */ /* |