From: drh Date: Thu, 3 Jan 2013 00:45:56 +0000 (+0000) Subject: Now supports result sets of the form "TABLE.*" with nested FROM clauses. X-Git-Tag: version-3.7.16~87^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3e3f1a5b493300ec1e3569037d7cb5afbd1b9207;p=thirdparty%2Fsqlite.git Now supports result sets of the form "TABLE.*" with nested FROM clauses. FossilOrigin-Name: 4cf5ed7ea198abc32f8118e79490e77f847f08c1 --- diff --git a/manifest b/manifest index 4270211ad5..6f14f4982c 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 24c1cff51c..1c88f392e4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ef01e30456670e6b1bc67fe41ec27e52c182efaf \ No newline at end of file +4cf5ed7ea198abc32f8118e79490e77f847f08c1 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 9ca34ec7b7..5ba2616919 100644 --- a/src/expr.c +++ b/src/expr.c @@ -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( inExpr-1 ){ sqlite3ExplainNL(pOut); } diff --git a/src/resolve.c b/src/resolve.c index 317ca3d81b..e1bcbcc5c1 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -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; jnExpr; 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; diff --git a/src/select.c b/src/select.c index 7c7974e256..502c524fd6 100644 --- a/src/select.c +++ b/src/select.c @@ -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; knExpr; 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; knExpr; 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; inSrc; 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; jnCol; 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); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2a28594fe5..74fa0b31ca 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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*); diff --git a/test/selectD.test b/test/selectD.test index 8c86226434..6c01b2d5cb 100644 --- a/test/selectD.test +++ b/test/selectD.test @@ -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