Now supports result sets of the form "TABLE.*" with nested FROM clauses.

FossilOrigin-Name: 4cf5ed7ea198abc32f8118e79490e77f847f08c1
This commit is contained in:
drh 2013-01-03 00:45:56 +00:00
parent fb7773276b
commit 3e3f1a5b49
7 changed files with 183 additions and 84 deletions

View File

@ -1,5 +1,5 @@
C When\sresolving\sresult-set\sname\scollisions,\smake\sthem\sx:1,\sx:2,\sx:3,\setc.\ninstead\sof\sx:1,\sx:1:1,\sx:1;1;1.
D 2013-01-02T14:57:32.750
C Now\ssupports\sresult\ssets\sof\sthe\sform\s"TABLE.*"\swith\snested\sFROM\sclauses.
D 2013-01-03T00:45:56.842
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -130,7 +130,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 72a70dcfda75d3a1f81041ce4573e7afddcd8e4e
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 9b8d308979114991e5dc7cee958316e07186941d
F src/expr.c 0e41d66d868b37dbc0e041c342e0036fad27e705
F src/expr.c 4dff0b04eaaf133789279c6b8cd69175dfbb1691
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 5b7a12e2f8620e855b0478a9a6798df9967bb277
F src/func.c 8147799b048065a1590805be464d05b4913e652c
@ -172,14 +172,14 @@ F src/pragma.c 8907c559d3127729d3bcedb1fe5c59fc196d3a17
F src/prepare.c 931ad0d852a0df48f79adcba6ce79ca5f475625c
F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 3104a5e4c2cb6e3a813b7266cbd541dc91e26fad
F src/resolve.c e00f17ac321b48f022e0154e5c2fb90456b6d3a6
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c bdede5fc109ab090dd6ce5edf6090434dc41bc0e
F src/select.c 9a76144e137fbe26bad3c5ef06e0acd953de9f59
F src/shell.c 11c9611580bb2ffce3a232f31f7f8cc310df0843
F src/sqlite.h.in 39cc33bb08897c748fe3383c29ccf56585704177
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
F src/sqliteInt.h 2ce2d742e32be86bf1fc8e29c91ef91c29c32e60
F src/sqliteInt.h e998703742455b2241731424c6ec142fd8d0258f
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@ -701,7 +701,7 @@ F test/select9.test c0ca3cd87a8ebb04de2cb1402c77df55d911a0ea
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
F test/selectD.test 243db87cd12f62aca4fe3f8b9465dfeab30b4d7a
F test/selectD.test 5e05091a755b12e0afd350137c49b25f7d9bc61b
F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
@ -1031,7 +1031,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P a5f4d2b641f7fafb6f1a312efeffb10f213d2d0a
R c34797fdba8f90f34f8f47a91737b456
P ef01e30456670e6b1bc67fe41ec27e52c182efaf
R 0fd360c4969bf18ffc741f29481411d6
U drh
Z 110af146cb022182bd89fc0a02fd1d9b
Z a4217b32c27253cef4a6339df637b923

View File

@ -1 +1 @@
ef01e30456670e6b1bc67fe41ec27e52c182efaf
4cf5ed7ea198abc32f8118e79490e77f847f08c1

View File

@ -3281,6 +3281,12 @@ void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
sqlite3ExplainPush(pOut);
sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
sqlite3ExplainPop(pOut);
if( pList->a[i].zName ){
sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
}
if( pList->a[i].bSpanIsTab ){
sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
}
if( i<pList->nExpr-1 ){
sqlite3ExplainNL(pOut);
}

View File

@ -150,6 +150,35 @@ static int nameInUsingClause(IdList *pUsing, const char *zCol){
return 0;
}
/*
** Subqueries stores the original database, table and column names for their
** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
** Check to see if the zSpan given to this routine matches the zDb, zTab,
** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
** match anything.
*/
int sqlite3MatchSpanName(
const char *zSpan,
const char *zCol,
const char *zTab,
const char *zDb
){
int n;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
return 0;
}
zSpan += n+1;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
return 0;
}
zSpan += n+1;
if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
return 0;
}
return 1;
}
/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
@ -240,8 +269,7 @@ static int lookupName(
ExprList *pEList = pItem->pSelect->pEList;
int hit = 0;
for(j=0; j<pEList->nExpr; j++){
if( zTab && sqlite3StrICmp(pEList->a[j].zSpan, zTab)!=0 ) continue;
if( sqlite3StrICmp(pEList->a[j].zName, zCol)==0 ){
if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
cnt++;
cntTab = 2;
pMatch = pItem;

View File

@ -3294,6 +3294,7 @@ static int selectExpander(Walker *pWalker, Select *p){
ExprList *pEList;
struct SrcList_item *pFrom;
sqlite3 *db = pParse->db;
Expr *pE, *pRight, *pExpr;
if( db->mallocFailed ){
return WRC_Abort;
@ -3379,7 +3380,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** that need expanding.
*/
for(k=0; k<pEList->nExpr; k++){
Expr *pE = pEList->a[k].pExpr;
pE = pEList->a[k].pExpr;
if( pE->op==TK_ALL ) break;
assert( pE->op!=TK_DOT || pE->pRight!=0 );
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
@ -3399,9 +3400,10 @@ static int selectExpander(Walker *pWalker, Select *p){
&& (p->selFlags & SF_NestedFrom)==0;
for(k=0; k<pEList->nExpr; k++){
Expr *pE = a[k].pExpr;
assert( pE->op!=TK_DOT || pE->pRight!=0 );
if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
pE = a[k].pExpr;
pRight = pE->pRight;
assert( pE->op!=TK_DOT || pRight!=0 );
if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
/* This particular expression does not need to be expanded.
*/
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
@ -3416,32 +3418,42 @@ static int selectExpander(Walker *pWalker, Select *p){
/* This expression is a "*" or a "TABLE.*" and needs to be
** expanded. */
int tableSeen = 0; /* Set to 1 when TABLE matches */
char *zTName; /* text of name of TABLE */
char *zTName = 0; /* text of name of TABLE */
if( pE->op==TK_DOT ){
assert( pE->pLeft!=0 );
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
zTName = pE->pLeft->u.zToken;
}else{
zTName = 0;
}
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab;
Select *pSub = pFrom->pSelect;
char *zTabName = pFrom->zAlias;
const char *zSchemaName = 0;
if( zTabName==0 ){
zTabName = pTab->zName;
}
if( db->mallocFailed ) break;
if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
continue;
if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
int iDb;
pSub = 0;
if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
continue;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
zSchemaName = iDb>=0 ? db->aDb[i].zName : "*";
}
tableSeen = 1;
for(j=0; j<pTab->nCol; j++){
Expr *pExpr, *pRight;
char *zName = pTab->aCol[j].zName;
char *zColname; /* The computed column name */
char *zToFree; /* Malloced string that needs to be freed */
Token sColname; /* Computed column name as a token */
if( zTName && pSub
&& sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
){
continue;
}
/* If a column is marked as 'hidden' (currently only possible
** for virtual tables), do not include it in the expanded
** result-set list.
@ -3450,6 +3462,7 @@ static int selectExpander(Walker *pWalker, Select *p){
assert(IsVirtual(pTab));
continue;
}
tableSeen = 1;
if( i>0 && zTName==0 ){
if( (pFrom->jointype & JT_NATURAL)!=0
@ -3484,7 +3497,14 @@ static int selectExpander(Walker *pWalker, Select *p){
sColname.n = sqlite3Strlen30(zColname);
sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
pNew->a[pNew->nExpr-1].zSpan = sqlite3DbStrDup(db, zTabName);
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
if( pSub ){
pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
}else{
pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
zSchemaName, zTabName, zColname);
}
pX->bSpanIsTab = 1;
}
sqlite3DbFree(db, zToFree);
}

View File

@ -1777,7 +1777,8 @@ struct Expr {
** column labels. In this case, Expr.zSpan is typically the text of a
** column expression as it exists in a SELECT statement. However, if
** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
** of the table to which the column of a FROM-clause subquery refers.
** of the result column in the form: DATABASE.TABLE.COLUMN. This later
** form is used for name resolution with nested FROM clauses.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
@ -1788,7 +1789,7 @@ struct ExprList {
char *zSpan; /* Original text of the expression */
u8 sortOrder; /* 1 for DESC or 0 for ASC */
unsigned done :1; /* A flag to indicate when processing is finished */
unsigned bSpanIsTab :1; /* zSpan holds table name, not the span */
unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
u16 iOrderByCol; /* For ORDER BY, column number in result set */
u16 iAlias; /* Index into Parse.aAlias[] for zName */
} *a; /* Alloc a power of two greater or equal to nExpr */
@ -3080,6 +3081,7 @@ void sqlite3NestedParse(Parse*, const char*, ...);
void sqlite3ExpirePreparedStatements(sqlite3*);
int sqlite3CodeSubselect(Parse *, Expr *, int, int);
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
int sqlite3ResolveExprNames(NameContext*, Expr*);
void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);

View File

@ -15,64 +15,107 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test selectD-1.1 {
db eval {
CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(111,'x1');
CREATE TABLE t2(a,b); INSERT INTO t2 VALUES(222,'x2');
CREATE TABLE t3(a,b); INSERT INTO t3 VALUES(333,'x3');
CREATE TABLE t4(a,b); INSERT INTO t4 VALUES(444,'x4');
SELECT *
FROM (t1), (t2), (t3), (t4)
WHERE t4.a=t3.a+111
AND t3.a=t2.a+111
AND t2.a=t1.a+111;
for {set i 1} {$i<=2} {incr i} {
db close
forcedelete test$i.db
sqlite3 db test$i.db
if {$i==2} {
optimization_control db query-flattener off
}
} {111 x1 222 x2 333 x3 444 x4}
do_test selectD-1.2 {
db eval {
SELECT *
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {111 x1 222 x2 333 x3 444 x4}
do_test selectD-1.3 {
db eval {
UPDATE t2 SET a=111;
UPDATE t3 SET a=111;
UPDATE t4 SET a=111;
SELECT *
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 USING(a)) USING (a)) USING (a);
}
} {111 x1 x2 x3 x4}
do_test selectD-1.4 {
db eval {
UPDATE t2 SET a=111;
UPDATE t3 SET a=111;
UPDATE t4 SET a=111;
SELECT *
FROM t1 LEFT JOIN (t2 LEFT JOIN (t3 LEFT JOIN t4 USING(a))
USING (a))
USING (a);
}
} {111 x1 x2 x3 x4}
do_test selectD-1.5 {
db eval {
UPDATE t3 SET a=222;
UPDATE t4 SET a=222;
SELECT *
FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
ON t1.a=t3.a-111;
}
} {111 x1 x2 222 x3 x4}
do_test selectD-1.6 {
db eval {
UPDATE t4 SET a=333;
SELECT *
FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
ON t1.a=t3.a-111;
}
} {111 x1 x2 222 x3 {}}
do_test selectD-$i.0 {
db eval {
CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(111,'x1');
CREATE TABLE t2(a,b); INSERT INTO t2 VALUES(222,'x2');
CREATE TEMP TABLE t3(a,b); INSERT INTO t3 VALUES(333,'x3');
CREATE TABLE t4(a,b); INSERT INTO t4 VALUES(444,'x4');
}
} {}
do_test selectD-$i.1 {
db eval {
SELECT *
FROM (t1), (t2), (t3), (t4)
WHERE t4.a=t3.a+111
AND t3.a=t2.a+111
AND t2.a=t1.a+111;
}
} {111 x1 222 x2 333 x3 444 x4}
do_test selectD-$i.2.1 {
db eval {
SELECT *
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {111 x1 222 x2 333 x3 444 x4}
do_test selectD-$i.2.2 {
db eval {
SELECT t3.a
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {333}
do_test selectD-$i.2.3 {
db eval {
SELECT t3.*
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {333 x3}
do_test selectD-$i.2.3 {
db eval {
SELECT t3.*, t2.*
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {333 x3 222 x2}
do_test selectD-$i.3 {
db eval {
UPDATE t2 SET a=111;
UPDATE t3 SET a=111;
UPDATE t4 SET a=111;
SELECT *
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 USING(a)) USING (a)) USING (a);
}
} {111 x1 x2 x3 x4}
do_test selectD-$i.4 {
db eval {
UPDATE t2 SET a=111;
UPDATE t3 SET a=111;
UPDATE t4 SET a=111;
SELECT *
FROM t1 LEFT JOIN (t2 LEFT JOIN (t3 LEFT JOIN t4 USING(a))
USING (a))
USING (a);
}
} {111 x1 x2 x3 x4}
do_test selectD-$i.5 {
db eval {
UPDATE t3 SET a=222;
UPDATE t4 SET a=222;
SELECT *
FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
ON t1.a=t3.a-111;
}
} {111 x1 x2 222 x3 x4}
do_test selectD-$i.6 {
db eval {
UPDATE t4 SET a=333;
SELECT *
FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
ON t1.a=t3.a-111;
}
} {111 x1 x2 222 x3 {}}
do_test selectD-$i.7 {
db eval {
SELECT t1.*, t2.*, t3.*, t4.b
FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
ON t1.a=t3.a-111;
}
} {111 x1 111 x2 222 x3 {}}
}
finish_test