From b733d037497c92f8f92d782b156b765ee9102c49 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 24 Jan 2004 20:18:12 +0000 Subject: [PATCH] Add the ability to group FROM terms using parentheses. Names of columns in a join no longer include the table name. (CVS 1197) FossilOrigin-Name: 3626f6d4a1adb4209d5bd9e6477343b52bddbdf2 --- manifest | 17 +++++------ manifest.uuid | 2 +- src/parse.y | 22 ++++++++++---- src/select.c | 34 +++++++++++++++------- test/join2.test | 73 +++++++++++++++++++++++++++++++++++++++++++++++ test/select6.test | 4 +-- 6 files changed, 125 insertions(+), 27 deletions(-) create mode 100644 test/join2.test diff --git a/manifest b/manifest index 521ec18235..c6d822a639 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypo.\s\sTicket\s#577.\s(CVS\s1196) -D 2004-01-22T23:38:22 +C Add\sthe\sability\sto\sgroup\sFROM\sterms\susing\sparentheses.\s\sNames\sof\scolumns\sin\na\sjoin\sno\slonger\sinclude\sthe\stable\sname.\s(CVS\s1197) +D 2004-01-24T20:18:13 F Makefile.in 0515ff9218ad8d5a8f6220f0494b8ef94c67013b F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -42,11 +42,11 @@ F src/os.c 681ec36217bc7c795d55d9a63ff79a8614ddee8c F src/os.h 8d02b622153d2df442da1ec37cdd6b1bd9804a25 F src/pager.c 289328d8efba620eae99f6c2f6062710838a3eb4 F src/pager.h 5da62c83443f26b1792cfd72c96c422f91aadd31 -F src/parse.y e41722d11148f34f034716652c1668ffb0ef2905 +F src/parse.y 7a121554c0c0c0150a77ab05417b01fa44813ac4 F src/pragma.c 89d62c31c6f0a43376fe8d20549b87a6d30c467a F src/printf.c 292a7bfc5a815cb6465e32b2d5c9fe9bd43b27f0 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe -F src/select.c 131b1af582c48a72f92eee9f3dfc669687faa1c8 +F src/select.c b5bc89a56d3d9162559bc173b7d5110f20249057 F src/shell.c 3b067edc098c45caca164bcad1fa79192c3ec5ae F src/sqlite.h.in c70d8533cd5a5ae8af580597dbc726693ef82de9 F src/sqliteInt.h c5b727d5d07b88654c204c0fc1ae79c9f635a008 @@ -96,6 +96,7 @@ F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f F test/intpkey.test 9320af48415c594afd4e15f8ef0daa272e05502e F test/ioerr.test 5dbaf09f96b56ee01cf3edd762b96eb4ad2c9ca4 F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd +F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8 F test/limit.test fa2a8b3fe377ebe60e0bc9a6a35af9ac4eb3d2b3 F test/lock.test 3d1855ba930732566f569d680e828656bd5b7f5c F test/main.test 6a851b5992c4881a725a3d9647e629199df8de9d @@ -121,7 +122,7 @@ F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4 F test/select3.test 445a1a3dde4e2fd32541b311f55da5e2f8079d76 F test/select4.test e7e9a32fa745246cb99fadbeb63af4843a17925b F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac -F test/select6.test 670026a06c358cc867ace7b1de6020e43adc7245 +F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf F test/sort.test ba07b107c16070208e6aab3cadea66ba079d85ba F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4 @@ -180,7 +181,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P df3509e13dc05751b7a5af07b57bca449fe5244c -R a1c0ec9ce95261bea04d82449f802c30 +P 3dc951951947a9188ecba1b84e48c65e34c4df16 +R c11f9dd26aca5e351dec881862f5d549 U drh -Z 57b555ec3a70e65302149e827f2f3589 +Z 2a2e36c650f4fa8bf25792ffa5a54e26 diff --git a/manifest.uuid b/manifest.uuid index 09ac4c5902..a96c152005 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3dc951951947a9188ecba1b84e48c65e34c4df16 \ No newline at end of file +3626f6d4a1adb4209d5bd9e6477343b52bddbdf2 \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index 05f9dff8d5..736d8dfc1b 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.106 2004/01/15 03:30:25 drh Exp $ +** @(#) $Id: parse.y,v 1.107 2004/01/24 20:18:13 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -366,7 +366,8 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). { else { sqliteIdListDelete(U); } } } -seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). { +seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP + as(Z) on_opt(N) using_opt(U). { A = sqliteSrcListAppend(X,0,0); A->a[A->nSrc-1].pSelect = S; if( Z.n ) sqliteSrcListAddAlias(A,&Z); @@ -380,6 +381,17 @@ seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). { } } +// A seltablist_paren nonterminal represents anything in a FROM that +// is contained inside parentheses. This can be either a subquery or +// a grouping of table and subqueries. +// +%type seltablist_paren {Select*} +%destructor seltablist_paren {sqliteSelectDelete($$);} +seltablist_paren(A) ::= select(S). {A = S;} +seltablist_paren(A) ::= seltablist(F). { + A = sqliteSelectNew(0,F,0,0,0,0,0,-1,0); +} + %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} dbnm(A) ::= DOT nm(X). {A = X;} @@ -666,16 +678,14 @@ expr(A) ::= expr(X) NOT IN LP select(Y) RP(E). { } expr(A) ::= expr(X) IN nm(Y) dbnm(D). { SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D); - ExprList *pList = sqliteExprListAppend(0, sqliteExpr(TK_ALL,0,0,0), 0); A = sqliteExpr(TK_IN, X, 0, 0); - if( A ) A->pSelect = sqliteSelectNew(pList,pSrc,0,0,0,0,0,-1,0); + if( A ) A->pSelect = sqliteSelectNew(0,pSrc,0,0,0,0,0,-1,0); sqliteExprSpan(A,&X->span,D.z?&D:&Y); } expr(A) ::= expr(X) NOT IN nm(Y) dbnm(D). { SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D); - ExprList *pList = sqliteExprListAppend(0, sqliteExpr(TK_ALL,0,0,0), 0); A = sqliteExpr(TK_IN, X, 0, 0); - if( A ) A->pSelect = sqliteSelectNew(pList,pSrc,0,0,0,0,0,-1,0); + if( A ) A->pSelect = sqliteSelectNew(0,pSrc,0,0,0,0,0,-1,0); A = sqliteExpr(TK_NOT, A, 0, 0); sqliteExprSpan(A,&X->span,D.z?&D:&Y); } diff --git a/src/select.c b/src/select.c index fde9270cab..735e16122f 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.148 2004/01/19 04:57:53 jplyon Exp $ +** $Id: select.c,v 1.149 2004/01/24 20:18:13 drh Exp $ */ #include "sqliteInt.h" @@ -42,6 +42,9 @@ Select *sqliteSelectNew( sqliteExprDelete(pHaving); sqliteExprListDelete(pOrderBy); }else{ + if( pEList==0 ){ + pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL,0,0,0), 0); + } pNew->pEList = pEList; pNew->pSrc = pSrc; pNew->pWhere = pWhere; @@ -777,8 +780,9 @@ static int fillInColumnList(Parse*, Select*); */ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ Table *pTab; - int i; + int i, j; ExprList *pEList; + Column *aCol; if( fillInColumnList(pParse, pSelect) ){ return 0; @@ -791,17 +795,27 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ pEList = pSelect->pEList; pTab->nCol = pEList->nExpr; assert( pTab->nCol>0 ); - pTab->aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol ); + pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol ); for(i=0; inCol; i++){ - Expr *p; + Expr *p, *pR; if( pEList->a[i].zName ){ - pTab->aCol[i].zName = sqliteStrDup(pEList->a[i].zName); - }else if( (p=pEList->a[i].pExpr)->span.z && p->span.z[0] ){ + aCol[i].zName = sqliteStrDup(pEList->a[i].zName); + }else if( (p=pEList->a[i].pExpr)->op==TK_DOT + && (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){ + int cnt; + sqliteSetNString(&aCol[i].zName, pR->token.z, pR->token.n, 0); + for(j=cnt=0; jtoken.z, pR->token.n, zBuf, n,0); + j = -1; + } + } + }else if( p->span.z && p->span.z[0] ){ sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0); - }else if( p->op==TK_DOT && p->pRight && p->pRight->token.z && - p->pRight->token.z[0] ){ - sqliteSetNString(&pTab->aCol[i].zName, - p->pRight->token.z, p->pRight->token.n, 0); }else{ char zBuf[30]; sprintf(zBuf, "column%d", i+1); diff --git a/test/join2.test b/test/join2.test new file mode 100644 index 0000000000..8829be38f1 --- /dev/null +++ b/test/join2.test @@ -0,0 +1,73 @@ +# 2002 May 24 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for joins, including outer joins. +# +# $Id: join2.test,v 1.1 2004/01/24 20:18:13 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_test join2-1.1 { + execsql { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,11); + INSERT INTO t1 VALUES(2,22); + INSERT INTO t1 VALUES(3,33); + SELECT * FROM t1; + } +} {1 11 2 22 3 33} +do_test join2-1.2 { + execsql { + CREATE TABLE t2(b,c); + INSERT INTO t2 VALUES(11,111); + INSERT INTO t2 VALUES(33,333); + INSERT INTO t2 VALUES(44,444); + SELECT * FROM t2; + } +} {11 111 33 333 44 444}; +do_test join2-1.3 { + execsql { + CREATE TABLE t3(c,d); + INSERT INTO t3 VALUES(111,1111); + INSERT INTO t3 VALUES(444,4444); + INSERT INTO t3 VALUES(555,5555); + SELECT * FROM t3; + } +} {111 1111 444 4444 555 5555} + +do_test join2-1.4 { + execsql { + SELECT * FROM + t1 NATURAL JOIN t2 NATURAL JOIN t3 + } +} {1 11 111 1111} +do_test join2-1.5 { + execsql { + SELECT * FROM + t1 NATURAL JOIN t2 NATURAL LEFT OUTER JOIN t3 + } +} {1 11 111 1111 3 33 333 {}} +do_test join2-1.6 { + execsql { + SELECT * FROM + t1 NATURAL LEFT OUTER JOIN t2 NATURAL JOIN t3 + } +} {1 11 111 1111} +do_test join2-1.6 { + execsql { + SELECT * FROM + t1 NATURAL LEFT OUTER JOIN (t2 NATURAL JOIN t3) + } +} {1 11 111 1111 2 22 {} {} 3 33 {} {}} + +finish_test diff --git a/test/select6.test b/test/select6.test index d47cdc65f0..bb57b7c48d 100644 --- a/test/select6.test +++ b/test/select6.test @@ -12,7 +12,7 @@ # focus of this file is testing SELECT statements that contain # subqueries in their FROM clause. # -# $Id: select6.test,v 1.10 2003/05/02 16:44:25 drh Exp $ +# $Id: select6.test,v 1.11 2004/01/24 20:18:13 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -163,7 +163,7 @@ do_test sqlite6-3.2 { FROM (SELECT count(*) as p , b as q FROM t2 GROUP BY q) AS a, (SELECT max(a) as r, b as s FROM t2 GROUP BY s) as b WHERE a.q=b.s ORDER BY a.q) - ORDER BY [a.q] + ORDER BY q } } {1 1 1 2 2 3 3 4 7 4 8 15 5 5 20} do_test select6-3.3 {