diff --git a/manifest b/manifest index 96fce36a74..3c9e01d403 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refinements\sto\sthe\sname\sresolution\slogic.\s\sChange\sthe\sname\sof\sthe\nkeywordhash.c\sfile\sto\skeywordhash.h.\s(CVS\s2229) -D 2005-01-18T04:00:43 +C Continue\srefactoring\sname\sresolution.\s\sFix\sfor\sticket\s#1047.\s(CVS\s2230) +D 2005-01-18T14:45:48 F Makefile.in ffd81f5e926d40b457071b4de8d7c1fa18f39b5a F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -31,7 +31,7 @@ F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea F src/btree.c 97101cce85304edbaedafc5f39ab12e2dc78b076 F src/btree.h 74d19cf40ab49fd69abe9e4e12a6c321ad86c497 -F src/build.c 4b7a2c308973df3ec26ceda6e3dadc07eecf031b +F src/build.c 608ea54aab8f561da99c8a40c3ab6b26b7fc91e9 F src/cursor.c f883813759742068890b1f699335872bfa8fdf41 F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f F src/delete.c 728a02e5b5c62d294f8cdbdb21dbaa3e188983ab @@ -57,10 +57,10 @@ F src/parse.y ceba179b9703657180963568f54b0e75f33e36e1 F src/pragma.c ac594f74c90ffec043c43e49358719ffeb491eec F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 -F src/select.c 37b9ddb9688a98c521d092dc38c811ec72191b14 +F src/select.c 767e9d0f0652ff8d319c13cc72a8eef4098ce30e F src/shell.c 591364a0e9ca4ce53873e21e0294476c0c2b4770 F src/sqlite.h.in 0d5e48e506845b74a845c9470e01d3f472b59611 -F src/sqliteInt.h a208bf0f51e6d7616c083313fa7cf5313efd346a +F src/sqliteInt.h c6414179a23cab108b4b07e8665f30829ce47f2a F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c fd27457b228118be96524dae285146c76efe032b F src/test1.c 2e27b110ba5aa16977bad1cc2388553479d73793 @@ -156,7 +156,7 @@ F test/minmax.test e7048476940df0af11d0f2cf687572f557cd0b29 F test/misc1.test 744f60d1025fa978708b96cb222a07a1feb1524a F test/misc2.test bc852f1622d98b610d1f3e2ceb36ed7271256050 F test/misc3.test 928a2f1e1189924ed14e1ae074e34f40688bdf94 -F test/misc4.test 7edc2542eadd98555c2d25c222b88a93124975ae +F test/misc4.test 33fd2ef6e9443acd73257a8f49aee0baec125888 F test/misuse.test 600738a8e611989bc5f544303f5e311c5f228084 F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0 F test/null.test 5a945790ef21b24fd602fe2c7a23847b903f8687 @@ -269,7 +269,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl c3b50d3ac31c54be2a1af9b488a89d22f1e6e746 -P 4a7534396a72ccb300303df28798bb2c50293782 -R f8f7d8c77656eb3939f3657d425a82a6 +P 0142ae6f0004bf18a1c2d8e49c09d2a9a27d6369 +R b2406c5f3bd45a3ced07f6eb72e28967 U drh -Z 295a57dfb9d4d3f564ec7f21c6307f77 +Z 4a32c7e963fbc8acd621a17d2d1e7a76 diff --git a/manifest.uuid b/manifest.uuid index 8174dd4e38..f991883223 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0142ae6f0004bf18a1c2d8e49c09d2a9a27d6369 \ No newline at end of file +88d4834fec7583a9b6400a1ce5b928c1f8a390dd \ No newline at end of file diff --git a/src/build.c b/src/build.c index 7e304ef644..84cdc6cfba 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.293 2005/01/18 04:00:44 drh Exp $ +** $Id: build.c,v 1.294 2005/01/18 14:45:48 drh Exp $ */ #include "sqliteInt.h" #include @@ -1578,10 +1578,10 @@ void sqlite3CreateView( ** of errors. If an error is seen leave an error message in pParse->zErrMsg. */ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ - ExprList *pEList; - Select *pSel; - Table *pSelTab; - int nErr = 0; + Table *pSelTab; /* A fake table from which we get the result set */ + Select *pSel; /* Copy of the SELECT that implements the view */ + int nErr = 0; /* Number of errors encountered */ + int n; /* Temporarily holds the number of cursors assigned */ assert( pTable ); @@ -1606,23 +1606,19 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ } /* If we get this far, it means we need to compute the table names. + ** Note that the call to sqlite3ResultSetOfSelect() will expand any + ** "*" elements in the results set of the view and will assign cursors + ** to the elements of the FROM clause. But we do not want these changes + ** to be permanent. So the computation is done on a copy of the SELECT + ** statement that defines the view. */ - assert( pTable->pSelect ); /* If nCol==0, then pTable must be a VIEW */ - pSel = pTable->pSelect; - - /* Note that the call to sqlite3ResultSetOfSelect() will expand any - ** "*" elements in this list. But we will need to restore the list - ** back to its original configuration afterwards, so we save a copy of - ** the original in pEList. - */ - pEList = pSel->pEList; - pSel->pEList = sqlite3ExprListDup(pEList); - if( pSel->pEList==0 ){ - pSel->pEList = pEList; - return 1; /* Malloc failed */ - } + assert( pTable->pSelect ); + pSel = sqlite3SelectDup(pTable->pSelect); + n = pParse->nTab; + sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel); + pParse->nTab = n; if( pSelTab ){ assert( pTable->aCol==0 ); pTable->nCol = pSelTab->nCol; @@ -1635,9 +1631,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ pTable->nCol = 0; nErr++; } - sqlite3SelectUnbind(pSel); - sqlite3ExprListDelete(pSel->pEList); - pSel->pEList = pEList; + sqlite3SelectDelete(pSel); return nErr; } #endif /* SQLITE_OMIT_VIEW */ @@ -2584,9 +2578,12 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){ */ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; - for(i=0; inSrc; i++){ - if( pList->a[i].iCursor<0 ){ - pList->a[i].iCursor = pParse->nTab++; + struct SrcList_item *pItem; + for(i=0, pItem=pList->a; inSrc; i++, pItem++){ + if( pItem->iCursor>=0 ) break; + pItem->iCursor = pParse->nTab++; + if( pItem->pSelect ){ + sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); } } } diff --git a/src/select.c b/src/select.c index c1d2dc9b43..d228097f1b 100644 --- a/src/select.c +++ b/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.224 2005/01/18 04:00:44 drh Exp $ +** $Id: select.c,v 1.225 2005/01/18 14:45:48 drh Exp $ */ #include "sqliteInt.h" @@ -654,6 +654,7 @@ static const char *columnType(Parse *pParse, SrcList *pTabList, Expr *pExpr){ int j; if( pExpr==0 || pTabList==0 ) return 0; + sqlite3ExprResolveNames(pParse, pTabList, 0, pExpr, 1, 0); switch( pExpr->op ){ case TK_COLUMN: { Table *pTab; @@ -803,7 +804,7 @@ static const char *selectOpName(int id){ /* ** Forward declaration */ -static int fillInColumnList(Parse*, Select*); +static int prepSelectStmt(Parse*, Select*); /* ** Given a SELECT statement, generate a Table structure that describes @@ -815,7 +816,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ ExprList *pEList; Column *aCol, *pCol; - if( fillInColumnList(pParse, pSelect) ){ + if( prepSelectStmt(pParse, pSelect) ){ return 0; } pTab = sqliteMalloc( sizeof(Table) ); @@ -870,20 +871,24 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ } /* -** For the given SELECT statement, do three things. +** Prepare a SELECT statement for processing by doing the following +** things: ** -** (1) Fill in the pTabList->a[].pTab fields in the SrcList that -** defines the set of tables that should be scanned. For views, +** (1) Make sure VDBE cursor numbers have been assigned to every +** element of the FROM clause. +** +** (2) Fill in the pTabList->a[].pTab fields in the SrcList that +** defines FROM clause. When views appear in the FROM clause, ** fill pTabList->a[].pSelect with a copy of the SELECT statement ** that implements the view. A copy is made of the view's SELECT ** statement so that we can freely modify or delete that statement ** without worrying about messing up the presistent representation ** of the view. ** -** (2) Add terms to the WHERE clause to accomodate the NATURAL keyword +** (3) Add terms to the WHERE clause to accomodate the NATURAL keyword ** on joins and the ON and USING clause of joins. ** -** (3) Scan the list of columns in the result set (pEList) looking +** (4) Scan the list of columns in the result set (pEList) looking ** for instances of the "*" operator or the TABLE.* operator. ** If found, expand each "*" to be every column in every table ** and TABLE.* to be every column in TABLE. @@ -891,7 +896,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ ** Return 0 on success. If there are problems, leave an error message ** in pParse and return non-zero. */ -static int fillInColumnList(Parse *pParse, Select *p){ +static int prepSelectStmt(Parse *pParse, Select *p){ int i, j, k, rc; SrcList *pTabList; ExprList *pEList; @@ -902,11 +907,20 @@ static int fillInColumnList(Parse *pParse, Select *p){ pTabList = p->pSrc; pEList = p->pEList; - /* Look up every table in the table list. + /* Make sure cursor numbers have been assigned to all entries in + ** the FROM clause of the SELECT statement. + */ + sqlite3SrcListAssignCursors(pParse, p->pSrc); + + /* Look up every table named in the FROM clause of the select. If + ** an entry of the FROM clause is a subquery instead of a table or view, + ** then create a transient table structure to describe the subquery. */ for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ - if( pFrom->pTab ){ - /* This routine has run before! No need to continue */ + if( pFrom->pTab!=0 ){ + /* This statement has already been prepared. There is no need + ** to go further. */ + assert( i==0 ); return 0; } if( pFrom->zName==0 ){ @@ -1125,7 +1139,7 @@ static int matchOrderbyToColumn( if( mustComplete ){ for(i=0; inExpr; i++){ pOrderBy->a[i].done = 0; } } - if( fillInColumnList(pParse, pSelect) ){ + if( prepSelectStmt(pParse, pSelect) ){ return 1; } if( pSelect->pPrior ){ @@ -1263,7 +1277,7 @@ static int openTempIndex(Parse *pParse, Select *p, int iTab, int keyAsData){ Vdbe *v = pParse->pVdbe; int addr; - if( fillInColumnList(pParse, p) ){ + if( prepSelectStmt(pParse, p) ){ return 0; } nColumn = p->pEList->nExpr; @@ -2307,21 +2321,13 @@ int sqlite3Select( pHaving = p->pHaving; isDistinct = p->isDistinct; - /* Allocate VDBE cursors for each table in the FROM clause - */ - sqlite3SrcListAssignCursors(pParse, pTabList); - /* ** Do not even attempt to generate any code if we have already seen ** errors before this routine starts. */ if( pParse->nErr>0 ) goto select_end; - /* Expand any "*" terms in the result set. (For example the "*" in - ** "SELECT * FROM t1") The fillInColumnlist() routine also does some - ** other housekeeping - see the header comment for details. - */ - if( fillInColumnList(pParse, p) ){ + if( prepSelectStmt(pParse, p) ){ goto select_end; } pWhere = p->pWhere; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b85b28d713..0c2bf93ad8 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.355 2005/01/18 04:00:44 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.356 2005/01/18 14:45:48 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -977,8 +977,6 @@ struct Select { ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ u8 isDistinct; /* True if the DISTINCT keyword is present */ - u8 isAgg; /* True if uses aggregate functions */ - u8 namesResolved; /* True if processed by sqlite3ExprResolve() */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ diff --git a/test/misc4.test b/test/misc4.test index 2698341550..cc8e0f09d8 100644 --- a/test/misc4.test +++ b/test/misc4.test @@ -13,7 +13,7 @@ # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc4.test,v 1.9 2005/01/11 15:28:33 drh Exp $ +# $Id: misc4.test,v 1.10 2005/01/18 14:45:49 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -99,4 +99,24 @@ do_test misc4-3.1 { } {{} {} 1 x 1 z} } ;# ifcapable compound +# Ticket #1047. Make sure column types are preserved in subqueries. +# +do_test misc4-4.1 { + execsql { + create table a(key varchar, data varchar); + create table b(key varchar, period integer); + insert into a values('01','data01'); + insert into a values('+1','data+1'); + + insert into b values ('01',1); + insert into b values ('01',2); + insert into b values ('+1',3); + insert into b values ('+1',4); + + select a.*, x.* + from a, (select key,sum(period) from b group by key) as x + where a.key=x.key; + } +} {01 data01 01 3.0 +1 data+1 +1 7.0} + finish_test