diff --git a/VERSION b/VERSION index 7bf4b6a8ae..e30309f735 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.6 +2.4.7 diff --git a/manifest b/manifest index 8408aba705..5cc1962ddc 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Added\sa\shyperlink\sto\sthe\sSQLite-PHP\sproject.\s(CVS\s517) -D 2002-04-03T20:50:21 +C Fix\sfor\sbug\s#2:\sAdd\ssupport\sfor\sTABLE.*\sin\sSELECT\sstatements.\s(CVS\s518) +D 2002-04-04T02:10:56 F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 -F VERSION ed0299de5b86deca846fdb0f8b99aaae85f27f47 +F VERSION bb2c45e1821c29d3e52ea953e25a4c4a2d2f15e7 F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588 F config.log 6a73d03433669b10a3f0c221198c3f26b9413914 @@ -35,10 +35,10 @@ F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 F src/pager.c f136f5ba82c896d500a10b6a2e5caea62abf716b F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e -F src/parse.y a0943e2774c7b0cab608640df1126f6c3ae39e90 +F src/parse.y d63f93b67edf9e318afea87b71d69af3334a9649 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe -F src/select.c 9323800e2937e84b52c198fffc51995d822b1779 +F src/select.c 92aef3f69e90dc065d680d88b1f075409e9249bb F src/shell.c b3454229599246b944cdb5b95753af3fca5d8bb0 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in 1dae50411aee9439860d7fbe315183c582d27197 @@ -84,7 +84,7 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05 F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435 F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274 -F test/select1.test 572d53f7b28c35a1efdce207f7579523358ba637 +F test/select1.test 114d4545c19f6cbbbcaa2a100f698757e6e36188 F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4 F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18 F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228 @@ -116,7 +116,7 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4 F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b F www/c_interface.tcl 567cda531aac9d68a61ef02e26c6b202bd856db2 -F www/changes.tcl 563071eacf1c0fc03521bf874438274d83445c78 +F www/changes.tcl 4b4a3c58c29ec56c063c6f550a3aaf70ea3bb637 F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060 F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49 @@ -131,7 +131,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 5ae7efd87f1a8e2f3e927bf373fbcb5c692d1a02 -R 97c982959534a76dbc674ad8494cc78c +P ffdeec3087e168acaa04a6331e91369e2e0f8345 +R 2030ad886be3f6f3ab16a87454cce255 U drh -Z c9be79df63e845bc5fc84485638451ca +Z 6dbde5dc0db37de113b78d968afab2db diff --git a/manifest.uuid b/manifest.uuid index 93cb863af7..b5e7916e96 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ffdeec3087e168acaa04a6331e91369e2e0f8345 \ No newline at end of file +c2320eabfe44d6eb05c02b76547e5bd48a29943c \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index 2ef406fde0..b43a5f4f64 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.59 2002/03/30 15:26:51 drh Exp $ +** @(#) $Id: parse.y,v 1.60 2002/04/04 02:10:57 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -255,6 +255,11 @@ selcollist(A) ::= sclp(P) expr(X) as ids(Y). {A = sqliteExprListAppend(P,X,&Y);} selcollist(A) ::= sclp(P) STAR. { A = sqliteExprListAppend(P, sqliteExpr(TK_ALL, 0, 0, 0), 0); } +selcollist(A) ::= sclp(P) ids(X) DOT STAR. { + Expr *pRight = sqliteExpr(TK_ALL, 0, 0, 0); + Expr *pLeft = sqliteExpr(TK_ID, 0, 0, &X); + A = sqliteExprListAppend(P, sqliteExpr(TK_DOT, pLeft, pRight, 0), 0); +} as ::= . as ::= AS. diff --git a/src/select.c b/src/select.c index d7f88f7016..611e501512 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.77 2002/03/23 00:31:29 drh Exp $ +** $Id: select.c,v 1.78 2002/04/04 02:10:57 drh Exp $ */ #include "sqliteInt.h" @@ -355,16 +355,16 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ ** (1) Fill in the pTabList->a[].pTab fields in the IdList that ** defines the set of tables that should be scanned. ** -** (2) If the columns to be extracted variable (pEList) is NULL -** (meaning that a "*" was used in the SQL statement) then -** create a fake pEList containing the names of all columns -** of all tables. +** (2) 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. ** ** 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){ - int i, j, k; + int i, j, k, rc; IdList *pTabList; ExprList *pEList; Table *pTab; @@ -410,42 +410,72 @@ static int fillInColumnList(Parse *pParse, Select *p){ } /* For every "*" that occurs in the column list, insert the names of - ** all columns in all tables. The parser inserted a special expression + ** all columns in all tables. And for every TABLE.* insert the names + ** of all columns in TABLE. The parser inserted a special expression ** with the TK_ALL operator for each "*" that it found in the column list. ** The following code just has to locate the TK_ALL expressions and expand ** each one to the list of all columns in all tables. + ** + ** The first loop just checks to see if there are any "*" operators + ** that need expanding. */ for(k=0; knExpr; k++){ - if( pEList->a[k].pExpr->op==TK_ALL ) break; + Expr *pE = pEList->a[k].pExpr; + if( pE->op==TK_ALL ) break; + if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL + && pE->pLeft && pE->pLeft->op==TK_ID ) break; } + rc = 0; if( knExpr ){ + /* + ** If we get here it means the result set contains one or more "*" + ** operators that need to be expanded. Loop through each expression + ** in the result set and expand them one by one. + */ struct ExprList_item *a = pEList->a; ExprList *pNew = 0; for(k=0; knExpr; k++){ - if( a[k].pExpr->op!=TK_ALL ){ + Expr *pE = a[k].pExpr; + if( pE->op!=TK_ALL && + (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){ + /* This particular expression does not need to be expanded. + */ pNew = sqliteExprListAppend(pNew, a[k].pExpr, 0); pNew->a[pNew->nExpr-1].zName = a[k].zName; a[k].pExpr = 0; a[k].zName = 0; }else{ + /* This expression is a "*" or a "TABLE.*" and needs to be + ** expanded. */ + int tableSeen = 0; /* Set to 1 when TABLE matches */ + Token *pName; /* text of name of TABLE */ + if( pE->op==TK_DOT && pE->pLeft ){ + pName = &pE->pLeft->token; + }else{ + pName = 0; + } for(i=0; inId; i++){ Table *pTab = pTabList->a[i].pTab; + char *zTabName = pTabList->a[i].zAlias; + if( zTabName==0 || zTabName[0]==0 ){ + zTabName = pTab->zName; + } + if( pName && (zTabName==0 || zTabName[0]==0 || + sqliteStrNICmp(pName->z, zTabName, pName->n)!=0) ){ + continue; + } + tableSeen = 1; for(j=0; jnCol; j++){ Expr *pExpr, *pLeft, *pRight; pRight = sqliteExpr(TK_ID, 0, 0, 0); if( pRight==0 ) break; pRight->token.z = pTab->aCol[j].zName; pRight->token.n = strlen(pTab->aCol[j].zName); - if( pTab->zName ){ + if( zTabName ){ pLeft = sqliteExpr(TK_ID, 0, 0, 0); if( pLeft==0 ) break; - if( pTabList->a[i].zAlias && pTabList->a[i].zAlias[0] ){ - pLeft->token.z = pTabList->a[i].zAlias; - pLeft->token.n = strlen(pTabList->a[i].zAlias); - }else{ - pLeft->token.z = pTab->zName; - pLeft->token.n = strlen(pTab->zName); - } + pLeft->token.z = zTabName; + pLeft->token.n = strlen(zTabName); pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0); if( pExpr==0 ) break; }else{ @@ -455,12 +485,18 @@ static int fillInColumnList(Parse *pParse, Select *p){ pNew = sqliteExprListAppend(pNew, pExpr, 0); } } + if( !tableSeen ){ + assert( pName!=0 ); + sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1, + pName->z, pName->n, 0); + rc = 1; + } } } sqliteExprListDelete(pEList); p->pEList = pNew; } - return 0; + return rc; } /* diff --git a/test/select1.test b/test/select1.test index 4aa36e8a6b..6a4930ad51 100644 --- a/test/select1.test +++ b/test/select1.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # -# $Id: select1.test,v 1.22 2002/03/02 17:04:09 drh Exp $ +# $Id: select1.test,v 1.23 2002/04/04 02:10:57 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -544,5 +544,86 @@ do_test select1-10.6 { } } {11 22} +# Check the ability to specify "TABLE.*" in the result set of a SELECT +# +do_test select1-11.1 { + execsql { + DELETE FROM t3; + DELETE FROM t4; + INSERT INTO t3 VALUES(1,2); + INSERT INTO t4 VALUES(3,4); + SELECT * FROM t3, t4; + } +} {1 2 3 4} +do_test select1-11.2 { + execsql2 { + SELECT * FROM t3, t4; + } +} {t3.a 1 t3.b 2 t4.a 3 t4.b 4} +do_test select1-11.3 { + execsql2 { + SELECT * FROM t3 AS x, t4 AS y; + } +} {x.a 1 x.b 2 y.a 3 y.b 4} +do_test select1-11.4 { + execsql { + SELECT t3.*, t4.b FROM t3, t4; + } +} {1 2 4} +do_test select1-11.5 { + execsql2 { + SELECT t3.*, t4.b FROM t3, t4; + } +} {t3.a 1 t3.b 2 t4.b 4} +do_test select1-11.6 { + execsql2 { + SELECT x.*, y.b FROM t3 AS x, t4 AS y; + } +} {x.a 1 x.b 2 y.b 4} +do_test select1-11.7 { + execsql { + SELECT t3.b, t4.* FROM t3, t4; + } +} {2 3 4} +do_test select1-11.8 { + execsql2 { + SELECT t3.b, t4.* FROM t3, t4; + } +} {t3.b 2 t4.a 3 t4.b 4} +do_test select1-11.9 { + execsql2 { + SELECT x.b, y.* FROM t3 AS x, t4 AS y; + } +} {x.b 2 y.a 3 y.b 4} +do_test select1-11.10 { + catchsql { + SELECT t5.* FROM t3, t4; + } +} {1 {no such table: t5}} +do_test select1-11.11 { + catchsql { + SELECT t3.* FROM t3 AS x, t4; + } +} {1 {no such table: t3}} +do_test select1-11.12 { + execsql2 { + SELECT t3.* FROM t3, (SELECT max(a), max(b) FROM t4) + } +} {t3.a 1 t3.b 2} +do_test select1-11.13 { + execsql2 { + SELECT t3.* FROM (SELECT max(a), max(b) FROM t4), t3 + } +} {t3.a 1 t3.b 2} +do_test select1-11.14 { + execsql2 { + SELECT * FROM t3, (SELECT max(a), max(b) FROM t4) + } +} {t3.a 1 t3.b 2 max(a) 3 max(b) 4} +do_test select1-11.15 { + execsql2 { + SELECT y.*, t3.* FROM t3, (SELECT max(a), max(b) FROM t4) AS y + } +} {y.max(a) 3 y.max(b) 4 t3.a 1 t3.b 2} finish_test diff --git a/www/changes.tcl b/www/changes.tcl index 9af1742f40..e4cee9f125 100644 --- a/www/changes.tcl +++ b/www/changes.tcl @@ -25,6 +25,11 @@ proc chng {date desc} { puts "

    $desc

" } +chng {2002 Apr 03 (2.4.7)} { +
  • Add the ability to put TABLE.* in the column list of a + SELECT statement.
  • +} + chng {2002 Apr 02 (2.4.6)} {
  • Bug fix: Correctly handle terms in the WHERE clause of a join that do not contain a comparison operator.