mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
Allow sub-queries that use UNION ALL to be flattened, even if the parent query is a join. Still some problems on this branch.
FossilOrigin-Name: 00e4bf74d3dfb87666a2266905f7d1a2afc6eb088d22cfd4f38f048733d6b936
This commit is contained in:
64
src/select.c
64
src/select.c
@@ -3920,7 +3920,7 @@ static int flattenSubquery(
|
||||
if( pSub->pOrderBy ){
|
||||
return 0; /* Restriction (20) */
|
||||
}
|
||||
if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
|
||||
if( isAgg || (p->selFlags & SF_Distinct)!=0 || isLeftJoin>0 ){
|
||||
return 0; /* (17d1), (17d2), or (17d3) */
|
||||
}
|
||||
for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
|
||||
@@ -3947,15 +3947,10 @@ static int flattenSubquery(
|
||||
if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ex-restriction (23):
|
||||
** The only way that the recursive part of a CTE can contain a compound
|
||||
** subquery is for the subquery to be one term of a join. But if the
|
||||
** subquery is a join, then the flattening has already been stopped by
|
||||
** restriction (17d3)
|
||||
*/
|
||||
assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
|
||||
/* Restriction (23) */
|
||||
if( (p->selFlags & SF_Recursive) ) return 0;
|
||||
}
|
||||
|
||||
/***** If we reach this point, flattening is permitted. *****/
|
||||
SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
|
||||
@@ -3967,6 +3962,17 @@ static int flattenSubquery(
|
||||
testcase( i==SQLITE_DENY );
|
||||
pParse->zAuthContext = zSavedAuthContext;
|
||||
|
||||
/* Delete the transient structures associated with thesubquery */
|
||||
pSub1 = pSubitem->pSelect;
|
||||
sqlite3DbFree(db, pSubitem->zDatabase);
|
||||
sqlite3DbFree(db, pSubitem->zName);
|
||||
sqlite3DbFree(db, pSubitem->zAlias);
|
||||
pSubitem->zDatabase = 0;
|
||||
pSubitem->zName = 0;
|
||||
pSubitem->zAlias = 0;
|
||||
pSubitem->pSelect = 0;
|
||||
assert( pSubitem->pOn==0 );
|
||||
|
||||
/* If the sub-query is a compound SELECT statement, then (by restrictions
|
||||
** 17 and 18 above) it must be a UNION ALL and the parent query must
|
||||
** be of the form:
|
||||
@@ -4005,15 +4011,16 @@ static int flattenSubquery(
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
Expr *pLimit = p->pLimit;
|
||||
Select *pPrior = p->pPrior;
|
||||
Table *pItemTab = pSubitem->pTab;
|
||||
pSubitem->pTab = 0;
|
||||
p->pOrderBy = 0;
|
||||
p->pSrc = 0;
|
||||
p->pPrior = 0;
|
||||
p->pLimit = 0;
|
||||
pNew = sqlite3SelectDup(db, p, 0);
|
||||
p->pLimit = pLimit;
|
||||
p->pOrderBy = pOrderBy;
|
||||
p->pSrc = pSrc;
|
||||
p->op = TK_ALL;
|
||||
pSubitem->pTab = pItemTab;
|
||||
if( pNew==0 ){
|
||||
p->pPrior = pPrior;
|
||||
}else{
|
||||
@@ -4024,25 +4031,13 @@ static int flattenSubquery(
|
||||
SELECTTRACE(2,pParse,p,("compound-subquery flattener"
|
||||
" creates %u as peer\n",pNew->selId));
|
||||
}
|
||||
if( db->mallocFailed ) return 1;
|
||||
assert( pSubitem->pSelect==0 );
|
||||
if( db->mallocFailed ){
|
||||
pSubitem->pSelect = pSub1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin flattening the iFrom-th entry of the FROM clause
|
||||
** in the outer query.
|
||||
*/
|
||||
pSub = pSub1 = pSubitem->pSelect;
|
||||
|
||||
/* Delete the transient table structure associated with the
|
||||
** subquery
|
||||
*/
|
||||
sqlite3DbFree(db, pSubitem->zDatabase);
|
||||
sqlite3DbFree(db, pSubitem->zName);
|
||||
sqlite3DbFree(db, pSubitem->zAlias);
|
||||
pSubitem->zDatabase = 0;
|
||||
pSubitem->zName = 0;
|
||||
pSubitem->zAlias = 0;
|
||||
pSubitem->pSelect = 0;
|
||||
|
||||
/* Defer deleting the Table object associated with the
|
||||
** subquery until code generation is
|
||||
** complete, since there may still exist Expr.pTab entries that
|
||||
@@ -4075,6 +4070,7 @@ static int flattenSubquery(
|
||||
** those references with expressions that resolve to the subquery FROM
|
||||
** elements we are now copying in.
|
||||
*/
|
||||
pSub = pSub1;
|
||||
for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){
|
||||
int nSubSrc;
|
||||
u8 jointype = 0;
|
||||
@@ -4083,16 +4079,10 @@ static int flattenSubquery(
|
||||
nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */
|
||||
pSrc = pParent->pSrc; /* FROM clause of the outer query */
|
||||
|
||||
if( pSrc ){
|
||||
assert( pParent==p ); /* First time through the loop */
|
||||
jointype = pSubitem->fg.jointype;
|
||||
}else{
|
||||
assert( pParent!=p ); /* 2nd and subsequent times through the loop */
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pSrc==0 ) break;
|
||||
pParent->pSrc = pSrc;
|
||||
if( pParent==p ){
|
||||
jointype = pSubitem->fg.jointype; /* First time through the loop */
|
||||
}
|
||||
|
||||
|
||||
/* The subquery uses a single slot of the FROM clause of the outer
|
||||
** query. If the subquery has more than one element in its FROM clause,
|
||||
** then expand the outer query to make space for it to hold all elements
|
||||
|
||||
Reference in New Issue
Block a user