From: drh Date: Wed, 9 Dec 2009 17:36:39 +0000 (+0000) Subject: The USING clause and NATURAL JOIN look at all tables to the left when X-Git-Tag: version-3.7.2~724 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2179b43465775fc438cda7631dfa7dd1644f0833;p=thirdparty%2Fsqlite.git The USING clause and NATURAL JOIN look at all tables to the left when searching for a match, not just the one table to the immediate left. Tables further to the left are preferred. Fix for ticket [f74beaabde]. Still need to add test cases to complete the ticket. FossilOrigin-Name: b558e96f0a3cd2cbbe86e44293246a4730960d52 --- diff --git a/manifest b/manifest index c0c8f77287..bbd8d3af0d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,8 @@ -C Improve\stest\scoverage\sof\sfts3.c. -D 2009-12-09T14:39:41 +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +C The\sUSING\sclause\sand\sNATURAL\sJOIN\slook\sat\sall\stables\sto\sthe\sleft\swhen\nsearching\sfor\sa\smatch,\snot\sjust\sthe\sone\stable\sto\sthe\simmediate\sleft.\nTables\sfurther\sto\sthe\sleft\sare\spreferred.\nFix\sfor\sticket\s[f74beaabde].\s\sStill\sneed\sto\sadd\stest\scases\sto\scomplete\nthe\sticket. +D 2009-12-09T17:36:40 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -162,7 +165,7 @@ F src/printf.c 644bc7d59df3dc56d6d8b9a510914bfc6b51bc69 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c d052e5c44bab34f83b3c1741aaa07478d18b5dd5 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 -F src/select.c 2f9ed7482e7a25b0b127fc41693bbdbe1caf5647 +F src/select.c 68c58dc49341472e4e5661a47a1a9e5f8a161340 F src/shell.c f4948cb6d30665d755a6b5e0ec313d1094aab828 F src/sqlite.h.in 338e1ac00faa7e3a536e7f1120827dd1f6432981 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 @@ -777,7 +780,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P a9038306c33c88120d8bef27209d8f0641c85c9b -R db340fa6c4afcd8bc8679373cdbca6c1 -U dan -Z eeb82c42887166b9ef7e8ca6456b81ff +P 56b6432f8622d53ffd3a4d9a2244114f8531ed71 +R c60687f3ab920ee77b412f18848340fb +U drh +Z 12648e9ade5661889385face890b1540 +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQFLH+AsoxKgR168RlERAqq+AJ42LhMfpcSfI/s5lEGDLv5D00O41wCfWMQf +iT/qNX5HigqUQ+DEbiPla9M= +=Wtyb +-----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index 9571b8bc18..54c0a97ffc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -56b6432f8622d53ffd3a4d9a2244114f8531ed71 \ No newline at end of file +b558e96f0a3cd2cbbe86e44293246a4730960d52 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 7555a391c2..80c2366869 100644 --- a/src/select.c +++ b/src/select.c @@ -189,6 +189,39 @@ static int columnIndex(Table *pTab, const char *zCol){ return -1; } +/* +** Search the first N tables in pSrc, from left to right, looking for a +** table that has a column named zCol. +** +** When found, set *piTab and *piCol to the table index and column index +** of the matching column and return TRUE. +** +** If not found, return FALSE. +*/ +static int tableAndColumnIndex( + SrcList *pSrc, /* Array of tables to search */ + int N, /* Number of tables in pSrc->a[] to search */ + const char *zCol, /* Name of the column we are looking for */ + int *piTab, /* Write index of pSrc->a[] here */ + int *piCol /* Write index of pSrc->a[*piTab].pTab->aCol[] here */ +){ + int i; /* For looping over tables in pSrc */ + int iCol; /* Index of column matching zCol */ + + assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ + for(i=0; ia[i].pTab, zCol); + if( iCol>=0 ){ + if( piTab ){ + *piTab = i; + *piCol = iCol; + } + return 1; + } + } + return 0; +} + /* ** This function is used to add terms implied by JOIN syntax to the ** WHERE clause expression of a SELECT statement. The new term, which @@ -203,8 +236,9 @@ static int columnIndex(Table *pTab, const char *zCol){ static void addWhereTerm( Parse *pParse, /* Parsing context */ SrcList *pSrc, /* List of tables in FROM clause */ - int iSrc, /* Index of first table to join in pSrc */ + int iLeft, /* Index of first table to join in pSrc */ int iColLeft, /* Index of column in first table */ + int iRight, /* Index of second table in pSrc */ int iColRight, /* Index of column in second table */ int isOuterJoin, /* True if this is an OUTER join */ Expr **ppWhere /* IN/OUT: The WHERE clause to add to */ @@ -214,12 +248,13 @@ static void addWhereTerm( Expr *pE2; Expr *pEq; - assert( pSrc->nSrc>(iSrc+1) ); - assert( pSrc->a[iSrc].pTab ); - assert( pSrc->a[iSrc+1].pTab ); + assert( iLeftnSrc>iRight ); + assert( pSrc->a[iLeft].pTab ); + assert( pSrc->a[iRight].pTab ); - pE1 = sqlite3CreateColumnExpr(db, pSrc, iSrc, iColLeft); - pE2 = sqlite3CreateColumnExpr(db, pSrc, iSrc+1, iColRight); + pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft); + pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight); pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0); if( pEq && isOuterJoin ){ @@ -308,11 +343,15 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ "an ON or USING clause", 0); return 1; } - for(j=0; jnCol; j++){ - char *zName = pLeftTab->aCol[j].zName; - int iRightCol = columnIndex(pRightTab, zName); - if( iRightCol>=0 ){ - addWhereTerm(pParse, pSrc, i, j, iRightCol, isOuter, &p->pWhere); + for(j=0; jnCol; j++){ + char *zName; /* Name of column in the right table */ + int iLeft; /* Matching left table */ + int iLeftCol; /* Matching column in the left table */ + + zName = pRightTab->aCol[j].zName; + if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){ + addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j, + isOuter, &p->pWhere); } } } @@ -344,15 +383,22 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ if( pRight->pUsing ){ IdList *pList = pRight->pUsing; for(j=0; jnId; j++){ - char *zName = pList->a[j].zName; - int iLeftCol = columnIndex(pLeftTab, zName); - int iRightCol = columnIndex(pRightTab, zName); - if( iLeftCol<0 || iRightCol<0 ){ + char *zName; /* Name of the term in the USING clause */ + int iLeft; /* Table on the left with matching column name */ + int iLeftCol; /* Column number of matching column on the left */ + int iRightCol; /* Column number of matching column on the right */ + + zName = pList->a[j].zName; + iRightCol = columnIndex(pRightTab, zName); + if( iRightCol<0 + || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) + ){ sqlite3ErrorMsg(pParse, "cannot join using column %s - column " "not present in both tables", zName); return 1; } - addWhereTerm(pParse, pSrc, i, iLeftCol, iRightCol, isOuter, &p->pWhere); + addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol, + isOuter, &p->pWhere); } } } @@ -3169,14 +3215,14 @@ static int selectExpander(Walker *pWalker, Select *p){ } if( i>0 && zTName==0 ){ - struct SrcList_item *pLeft = &pTabList->a[i-1]; - if( (pLeft[1].jointype & JT_NATURAL)!=0 && - columnIndex(pLeft->pTab, zName)>=0 ){ + if( (pFrom->jointype & JT_NATURAL)!=0 + && tableAndColumnIndex(pTabList, i, zName, 0, 0) + ){ /* In a NATURAL join, omit the join columns from the - ** table on the right */ + ** table to the right of the join */ continue; } - if( sqlite3IdListIndex(pLeft[1].pUsing, zName)>=0 ){ + if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){ /* In a join with a USING clause, omit columns in the ** using clause from the table on the right. */ continue;