Enhance the query flattener to handle subqueries that are joins.
All regressions pass but new tests need to be added before release. Ticket #272. (CVS 948) FossilOrigin-Name: ad57693e9f1b83a8cc4d028264b35018a9a4a701
This commit is contained in:
parent
6a3ea0e6ef
commit
c31c2eb82c
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C VDBE\scursors\snumbers\sfor\stables\sin\sa\sjoin\sdo\snot\shave\sto\sbe\sconsecutive.\nThis\sis\sone\sstep\son\sthe\sroad\sto\sfixing\sticket\s#272.\s(CVS\s947)
|
||||
D 2003-05-02T14:32:13
|
||||
C Enhance\sthe\squery\sflattener\sto\shandle\ssubqueries\sthat\sare\sjoins.\nAll\sregressions\spass\sbut\snew\stests\sneed\sto\sbe\sadded\sbefore\srelease.\nTicket\s#272.\s(CVS\s948)
|
||||
D 2003-05-02T16:04:17
|
||||
F Makefile.in 004acec253ecdde985c8ecd5b7c9accdb210378f
|
||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
@ -43,7 +43,7 @@ F src/parse.y 39b5240cb78047dc56d6d37c398baed7ba556779
|
||||
F src/pragma.c 118fe400d71b7fdcc03580d5eab6bb5aa00772a5
|
||||
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
|
||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||
F src/select.c 493360f3003719ad61d49863c4f5db0bad9022cb
|
||||
F src/select.c 3fe63e3a29df661ba72a67eecd77e8ee82801def
|
||||
F src/shell.c 6f59240f69e65a1c4e1d06492eb9238092defc34
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e
|
||||
@ -127,7 +127,7 @@ F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f
|
||||
F test/update.test 198360dfa14e65354dbcc66d5b98d8070780e42b
|
||||
F test/vacuum.test 4d8c8af30338577af03e563bc815d7898ae65258
|
||||
F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246
|
||||
F test/view.test 8b3b0b30674865af2c87acbdf945e369f92012a5
|
||||
F test/view.test 408fa464da35cf9c1fd9054c988f7e755a1cb0b6
|
||||
F test/where.test d719129a052280fe245a2ddcbd09bcc0b8c17ce4
|
||||
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||
F tool/lemon.c 14fedcde9cf70aa6040b89de164cf8f56f92a4b9
|
||||
@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
|
||||
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
|
||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||
P 6d019e0baa3219614a9bc5b550a0f9fe3f7e731a
|
||||
R f7e61e2db6268bcec64f93ca941fa9e1
|
||||
P be7aed2011b4af868b6a0c370c3d41354ae0cdf4
|
||||
R ed36fbd16d08ea65dbe969ae9a7bbf4c
|
||||
U drh
|
||||
Z affbf408d9fd8c226a5447c7e8084f51
|
||||
Z 80e0fdd6a1502d3a16e3bb09c6a28adb
|
||||
|
@ -1 +1 @@
|
||||
be7aed2011b4af868b6a0c370c3d41354ae0cdf4
|
||||
ad57693e9f1b83a8cc4d028264b35018a9a4a701
|
79
src/select.c
79
src/select.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.136 2003/05/02 14:32:13 drh Exp $
|
||||
** $Id: select.c,v 1.137 2003/05/02 16:04:17 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -1555,7 +1555,7 @@ substExprList(ExprList *pList, int iTable, ExprList *pEList){
|
||||
**
|
||||
** (2) The subquery is not an aggregate or the outer query is not a join.
|
||||
**
|
||||
** (3) The subquery is not a join.
|
||||
** (3) (No longer a restriction)
|
||||
**
|
||||
** (4) The subquery is not DISTINCT or the outer query is not a join.
|
||||
**
|
||||
@ -1613,7 +1613,7 @@ static int flattenSubquery(
|
||||
if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
|
||||
pSubSrc = pSub->pSrc;
|
||||
assert( pSubSrc );
|
||||
if( pSubSrc->nSrc!=1 ) return 0;
|
||||
if( pSubSrc->nSrc==0 ) return 0;
|
||||
if( (pSub->isDistinct || pSub->nLimit>=0) && (pSrc->nSrc>1 || isAgg) ){
|
||||
return 0;
|
||||
}
|
||||
@ -1623,8 +1623,52 @@ static int flattenSubquery(
|
||||
/* If we reach this point, it means flattening is permitted for the
|
||||
** iFrom-th entry of the FROM clause in the outer query.
|
||||
*/
|
||||
|
||||
/* Move all of the FROM elements of the subquery into the
|
||||
** the FROM clause of the outer query. Before doing this, remember
|
||||
** the cursor number for the original outer query FROM element in
|
||||
** iParent. The iParent cursor will never be used. Subsequent code
|
||||
** will scan expressions looking for iParent references and replace
|
||||
** those references with expressions that resolve to the subquery FROM
|
||||
** elements we are now copying in.
|
||||
*/
|
||||
iParent = pSrc->a[iFrom].iCursor;
|
||||
pSrc->a[iFrom].iCursor = pSubSrc->a[0].iCursor;
|
||||
{
|
||||
int nSubSrc = pSubSrc->nSrc;
|
||||
|
||||
if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
|
||||
sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
|
||||
}
|
||||
sqliteFree(pSrc->a[iFrom].zName);
|
||||
sqliteFree(pSrc->a[iFrom].zAlias);
|
||||
if( nSubSrc>1 ){
|
||||
int extra = nSubSrc - 1;
|
||||
for(i=1; i<nSubSrc; i++){
|
||||
pSrc = sqliteSrcListAppend(pSrc, 0, 0);
|
||||
}
|
||||
p->pSrc = pSrc;
|
||||
for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){
|
||||
pSrc->a[i] = pSrc->a[i-extra];
|
||||
}
|
||||
}
|
||||
for(i=0; i<nSubSrc; i++){
|
||||
pSrc->a[i+iFrom] = pSubSrc->a[i];
|
||||
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Now begin substituting subquery result set expressions for
|
||||
** references to the iParent in the outer query.
|
||||
**
|
||||
** Example:
|
||||
**
|
||||
** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
|
||||
** \ \_____________ subquery __________/ /
|
||||
** \_____________________ outer query ______________________________/
|
||||
**
|
||||
** We look at every expression in the outer query and every place we see
|
||||
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
|
||||
*/
|
||||
substExprList(p->pEList, iParent, pSub->pEList);
|
||||
pList = p->pEList;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
@ -1672,8 +1716,15 @@ static int flattenSubquery(
|
||||
p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* The flattened query is distinct if either the inner or the
|
||||
** outer query is distinct.
|
||||
*/
|
||||
p->isDistinct = p->isDistinct || pSub->isDistinct;
|
||||
|
||||
/* Transfer the limit expression from the subquery to the outer
|
||||
** query.
|
||||
*/
|
||||
if( pSub->nLimit>=0 ){
|
||||
if( p->nLimit<0 ){
|
||||
p->nLimit = pSub->nLimit;
|
||||
@ -1683,14 +1734,9 @@ static int flattenSubquery(
|
||||
}
|
||||
p->nOffset += pSub->nOffset;
|
||||
|
||||
if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
|
||||
sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
|
||||
}
|
||||
pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab;
|
||||
pSubSrc->a[0].pTab = 0;
|
||||
assert( pSrc->a[iFrom].pSelect==pSub );
|
||||
pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect;
|
||||
pSubSrc->a[0].pSelect = 0;
|
||||
/* Finially, delete what is left of the subquery and return
|
||||
** success.
|
||||
*/
|
||||
sqliteSelectDelete(pSub);
|
||||
return 1;
|
||||
}
|
||||
@ -2079,19 +2125,24 @@ int sqliteSelect(
|
||||
*/
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
const char *zSavedAuthContext;
|
||||
int needRestoreContext;
|
||||
|
||||
if( pTabList->a[i].pSelect==0 ) continue;
|
||||
if( pTabList->a[i].zName!=0 ){
|
||||
zSavedAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = pTabList->a[i].zName;
|
||||
needRestoreContext = 1;
|
||||
}else{
|
||||
needRestoreContext = 0;
|
||||
}
|
||||
sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable,
|
||||
pTabList->a[i].iCursor, p, i, &isAgg);
|
||||
if( pTabList->a[i].zName!=0 ){
|
||||
if( needRestoreContext ){
|
||||
pParse->zAuthContext = zSavedAuthContext;
|
||||
}
|
||||
pTabList = p->pSrc;
|
||||
pWhere = p->pWhere;
|
||||
if( eDest==SRT_Callback ){
|
||||
if( eDest!=SRT_Union && eDest!=SRT_Except && eDest!=SRT_Discard ){
|
||||
pOrderBy = p->pOrderBy;
|
||||
}
|
||||
pGroupBy = p->pGroupBy;
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing VIEW statements.
|
||||
#
|
||||
# $Id: view.test,v 1.14 2003/05/02 14:32:15 drh Exp $
|
||||
# $Id: view.test,v 1.15 2003/05/02 16:04:17 drh Exp $
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
@ -197,11 +197,49 @@ do_test view-5.1 {
|
||||
do_test view-5.2 {
|
||||
execsql {
|
||||
CREATE VIEW v5 AS
|
||||
SELECT t1.x, t2.y FROM t1 JOIN t2 USING(a);
|
||||
SELECT t1.x AS v, t2.y AS w FROM t1 JOIN t2 USING(a);
|
||||
SELECT * FROM v5;
|
||||
}
|
||||
} {1 22 4 55}
|
||||
|
||||
# Verify that the view v5 gets flattened. see sqliteFlattenSubquery().
|
||||
# Ticket #272
|
||||
do_test view-5.3 {
|
||||
lsearch [execsql {
|
||||
EXPLAIN SELECT * FROM v5;
|
||||
}] OpenTemp
|
||||
} {-1}
|
||||
do_test view-5.4 {
|
||||
execsql {
|
||||
SELECT * FROM v5 AS a, t2 AS b WHERE a.w=b.y;
|
||||
}
|
||||
} {1 22 22 2 4 55 55 5}
|
||||
do_test view-5.5 {
|
||||
lsearch [execsql {
|
||||
EXPLAIN SELECT * FROM v5 AS a, t2 AS b WHERE a.w=b.y;
|
||||
}] OpenTemp
|
||||
} {-1}
|
||||
do_test view-5.6 {
|
||||
execsql {
|
||||
SELECT * FROM t2 AS b, v5 AS a WHERE a.w=b.y;
|
||||
}
|
||||
} {22 2 1 22 55 5 4 55}
|
||||
do_test view-5.7 {
|
||||
lsearch [execsql {
|
||||
EXPLAIN SELECT * FROM t2 AS b, v5 AS a WHERE a.w=b.y;
|
||||
}] OpenTemp
|
||||
} {-1}
|
||||
do_test view-5.8 {
|
||||
execsql {
|
||||
SELECT * FROM t1 AS a, v5 AS b, t2 AS c WHERE a.x=b.v AND b.w=c.y;
|
||||
}
|
||||
} {1 2 3 4 1 22 22 2 4 5 6 7 4 55 55 5}
|
||||
do_test view-5.9 {
|
||||
lsearch [execsql {
|
||||
EXPLAIN SELECT * FROM t1 AS a, v5 AS b, t2 AS c WHERE a.x=b.v AND b.w=c.y;
|
||||
}] OpenTemp
|
||||
} {-1}
|
||||
|
||||
do_test view-6.1 {
|
||||
execsql {
|
||||
SELECT min(x), min(a), min(b), min(c), min(a+b+c) FROM v2;
|
||||
|
Loading…
x
Reference in New Issue
Block a user