@@ -4726,7 +4726,7 @@ int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
4726
4726
pParse -> checkSchema = 1 ;
4727
4727
return SQLITE_ERROR ;
4728
4728
}
4729
- pFrom -> pIBIndex = pIdx ;
4729
+ pFrom -> u2 . pIBIndex = pIdx ;
4730
4730
return SQLITE_OK ;
4731
4731
}
4732
4732
@@ -4935,8 +4935,18 @@ static int resolveFromTermToCte(
4935
4935
if ( cannotBeFunction (pParse , pFrom ) ) return 2 ;
4936
4936
4937
4937
assert ( pFrom -> pTab == 0 );
4938
- pFrom -> pTab = pTab = sqlite3DbMallocZero (db , sizeof (Table ));
4938
+ pTab = sqlite3DbMallocZero (db , sizeof (Table ));
4939
4939
if ( pTab == 0 ) return 2 ;
4940
+ if ( pCte -> pUse == 0 ){
4941
+ pCte -> pUse = sqlite3DbMallocZero (db , sizeof (pCte -> pUse [0 ]));
4942
+ if ( pCte -> pUse == 0
4943
+ || sqlite3ParserAddCleanup (pParse ,sqlite3DbFree ,pCte -> pUse )== 0
4944
+ ){
4945
+ sqlite3DbFree (db , pTab );
4946
+ return 2 ;
4947
+ }
4948
+ }
4949
+ pFrom -> pTab = pTab ;
4940
4950
pTab -> nTabRef = 1 ;
4941
4951
pTab -> zName = sqlite3DbStrDup (db , pCte -> zName );
4942
4952
pTab -> iPKey = -1 ;
@@ -4945,6 +4955,9 @@ static int resolveFromTermToCte(
4945
4955
pFrom -> pSelect = sqlite3SelectDup (db , pCte -> pSelect , 0 );
4946
4956
if ( db -> mallocFailed ) return 2 ;
4947
4957
assert ( pFrom -> pSelect );
4958
+ pFrom -> fg .isCte = 1 ;
4959
+ pFrom -> u2 .pCteUse = pCte -> pUse ;
4960
+ pCte -> pUse -> nUse ++ ;
4948
4961
4949
4962
/* Check if this is a recursive CTE. */
4950
4963
pRecTerm = pSel = pFrom -> pSelect ;
@@ -6153,6 +6166,7 @@ int sqlite3Select(
6153
6166
*/
6154
6167
for (i = 0 ; i < pTabList -> nSrc ; i ++ ){
6155
6168
SrcItem * pItem = & pTabList -> a [i ];
6169
+ SrcItem * pPrior ;
6156
6170
SelectDest dest ;
6157
6171
Select * pSub ;
6158
6172
#if !defined(SQLITE_OMIT_SUBQUERY ) || !defined(SQLITE_OMIT_VIEW )
@@ -6212,6 +6226,7 @@ int sqlite3Select(
6212
6226
** inside the subquery. This can help the subquery to run more efficiently.
6213
6227
*/
6214
6228
if ( OptimizationEnabled (db , SQLITE_PushDown )
6229
+ && (pItem -> fg .isCte == 0 || pItem -> u2 .pCteUse -> nUse <=1 )
6215
6230
&& pushDownWhereTerms (pParse , pSub , p -> pWhere , pItem -> iCursor ,
6216
6231
(pItem -> fg .jointype & JT_OUTER )!= 0 )
6217
6232
){
@@ -6232,16 +6247,18 @@ int sqlite3Select(
6232
6247
6233
6248
/* Generate code to implement the subquery
6234
6249
**
6235
- ** The subquery is implemented as a co-routine if the subquery is
6236
- ** guaranteed to be the outer loop (so that it does not need to be
6237
- ** computed more than once)
6250
+ ** The subquery is implemented as a co-routine if:
6251
+ ** (1) the subquery is guaranteed to be the outer loop (so that
6252
+ ** it does not need to be computed more than once), and
6253
+ ** (2) the subquery is not a CTE that is used more then once.
6238
6254
**
6239
- ** TODO: Are there other reasons beside (1) to use a co-routine
6255
+ ** TODO: Are there other reasons beside (1) and (2) to use a co-routine
6240
6256
** implementation?
6241
6257
*/
6242
6258
if ( i == 0
6243
6259
&& (pTabList -> nSrc == 1
6244
6260
|| (pTabList -> a [1 ].fg .jointype & (JT_LEFT |JT_CROSS ))!= 0 ) /* (1) */
6261
+ && (pItem -> fg .isCte == 0 || pItem -> u2 .pCteUse -> nUse < 2 ) /* (2) */
6245
6262
){
6246
6263
/* Implement a co-routine that will return a single row of the result
6247
6264
** set on each invocation.
@@ -6261,16 +6278,30 @@ int sqlite3Select(
6261
6278
sqlite3VdbeEndCoroutine (v , pItem -> regReturn );
6262
6279
sqlite3VdbeJumpHere (v , addrTop - 1 );
6263
6280
sqlite3ClearTempRegCache (pParse );
6281
+ }else if ( pItem -> fg .isCte && pItem -> u2 .pCteUse -> addrM9e > 0 ){
6282
+ /* This is a CTE for which materialization code has already been
6283
+ ** generated. Invoke the subroutine to compute the materialization,
6284
+ ** the make the pItem->iCursor be a copy of the ephemerial table that
6285
+ ** holds the result of the materialization. */
6286
+ CteUse * pCteUse = pItem -> u2 .pCteUse ;
6287
+ sqlite3VdbeAddOp2 (v , OP_Gosub , pCteUse -> regRtn , pCteUse -> addrM9e );
6288
+ if ( pItem -> iCursor != pCteUse -> iCur ){
6289
+ sqlite3VdbeAddOp2 (v , OP_OpenDup , pItem -> iCursor , pCteUse -> iCur );
6290
+ }
6291
+ pSub -> nSelectRow = pCteUse -> nRowEst ;
6292
+ }else if ( (pPrior = isSelfJoinView (pTabList , pItem ))!= 0 ){
6293
+ /* This view has already been materialized by a prior entry in
6294
+ ** this same FROM clause. Reuse it. */
6295
+ if ( pPrior -> addrFillSub ){
6296
+ sqlite3VdbeAddOp2 (v , OP_Gosub , pPrior -> regReturn , pPrior -> addrFillSub );
6297
+ }
6298
+ sqlite3VdbeAddOp2 (v , OP_OpenDup , pItem -> iCursor , pPrior -> iCursor );
6299
+ pSub -> nSelectRow = pPrior -> pSelect -> nSelectRow ;
6264
6300
}else {
6265
- /* Generate a subroutine that will fill an ephemeral table with
6266
- ** the content of this subquery. pItem->addrFillSub will point
6267
- ** to the address of the generated subroutine. pItem->regReturn
6268
- ** is a register allocated to hold the subroutine return address
6269
- */
6301
+ /* Generate a subroutine that will materialize the view. */
6270
6302
int topAddr ;
6271
6303
int onceAddr = 0 ;
6272
6304
int retAddr ;
6273
- SrcItem * pPrior ;
6274
6305
6275
6306
testcase ( pItem -> addrFillSub == 0 ); /* Ticket c52b09c7f38903b1311 */
6276
6307
pItem -> regReturn = ++ pParse -> nMem ;
@@ -6285,22 +6316,22 @@ int sqlite3Select(
6285
6316
}else {
6286
6317
VdbeNoopComment ((v , "materialize \"%s\"" , pItem -> pTab -> zName ));
6287
6318
}
6288
- pPrior = isSelfJoinView (pTabList , pItem );
6289
- if ( pPrior ){
6290
- sqlite3VdbeAddOp2 (v , OP_OpenDup , pItem -> iCursor , pPrior -> iCursor );
6291
- assert ( pPrior -> pSelect != 0 );
6292
- pSub -> nSelectRow = pPrior -> pSelect -> nSelectRow ;
6293
- }else {
6294
- sqlite3SelectDestInit (& dest , SRT_EphemTab , pItem -> iCursor );
6295
- ExplainQueryPlan ((pParse , 1 , "MATERIALIZE %u" , pSub -> selId ));
6296
- sqlite3Select (pParse , pSub , & dest );
6297
- }
6319
+ sqlite3SelectDestInit (& dest , SRT_EphemTab , pItem -> iCursor );
6320
+ ExplainQueryPlan ((pParse , 1 , "MATERIALIZE %u" , pSub -> selId ));
6321
+ sqlite3Select (pParse , pSub , & dest );
6298
6322
pItem -> pTab -> nRowLogEst = pSub -> nSelectRow ;
6299
6323
if ( onceAddr ) sqlite3VdbeJumpHere (v , onceAddr );
6300
6324
retAddr = sqlite3VdbeAddOp1 (v , OP_Return , pItem -> regReturn );
6301
6325
VdbeComment ((v , "end %s" , pItem -> pTab -> zName ));
6302
6326
sqlite3VdbeChangeP1 (v , topAddr , retAddr );
6303
6327
sqlite3ClearTempRegCache (pParse );
6328
+ if ( pItem -> fg .isCte ){
6329
+ CteUse * pCteUse = pItem -> u2 .pCteUse ;
6330
+ pCteUse -> addrM9e = pItem -> addrFillSub ;
6331
+ pCteUse -> regRtn = pItem -> regReturn ;
6332
+ pCteUse -> iCur = pItem -> iCursor ;
6333
+ pCteUse -> nRowEst = pSub -> nSelectRow ;
6334
+ }
6304
6335
}
6305
6336
if ( db -> mallocFailed ) goto select_end ;
6306
6337
pParse -> nHeight -= sqlite3SelectExprHeight (p );
0 commit comments