-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
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
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
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
** 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"
**
** (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.
**
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;
}
/* 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++){
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;
}
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;
}
*/
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;
# 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
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;