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
This commit is contained in:
drh 2004-01-24 20:18:12 +00:00
parent a8d6243bc7
commit b733d03749
6 changed files with 125 additions and 27 deletions

View File

@ -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

View File

@ -1 +1 @@
3dc951951947a9188ecba1b84e48c65e34c4df16
3626f6d4a1adb4209d5bd9e6477343b52bddbdf2

View File

@ -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);
}

View File

@ -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; i<pTab->nCol; 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; j<i; j++){
if( sqliteStrICmp(aCol[j].zName, aCol[i].zName)==0 ){
int n;
char zBuf[30];
sprintf(zBuf,"_%d",++cnt);
n = strlen(zBuf);
sqliteSetNString(&aCol[i].zName, pR->token.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);

73
test/join2.test Normal file
View File

@ -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

View File

@ -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 {