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:
parent
a8d6243bc7
commit
b733d03749
17
manifest
17
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
|
||||
|
@ -1 +1 @@
|
||||
3dc951951947a9188ecba1b84e48c65e34c4df16
|
||||
3626f6d4a1adb4209d5bd9e6477343b52bddbdf2
|
22
src/parse.y
22
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);
|
||||
}
|
||||
|
34
src/select.c
34
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; 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
73
test/join2.test
Normal 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
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user