From: drh Date: Sat, 8 Dec 2007 21:10:20 +0000 (+0000) Subject: Better resolution of ORDER BY terms in compound queries. Candidate X-Git-Tag: version-3.6.10~1575 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4c77431448a12c6912a78a5e2777e8bf4f2434e6;p=thirdparty%2Fsqlite.git Better resolution of ORDER BY terms in compound queries. Candidate solution for ticket #2822. Needs more testing and documentation before going final. (CVS 4602) FossilOrigin-Name: 62a78d212c53a9cb1759d03134653a75f3a086b6 --- diff --git a/manifest b/manifest index afc3495cf8..b3f574e4a8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Strengthen\sthe\stests\sfor\saggregate\sfunctions\sin\sGROUP\sBY\sclauses.\nChanges\sto\stest\scases\sonly.\s\sNo\schanges\sto\scode.\s(CVS\s4601) -D 2007-12-08T18:01:31 +C Better\sresolution\sof\sORDER\sBY\sterms\sin\scompound\squeries.\s\sCandidate\nsolution\sfor\sticket\s#2822.\s\sNeeds\smore\stesting\sand\sdocumentation\nbefore\sgoing\sfinal.\s(CVS\s4602) +D 2007-12-08T21:10:20 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -131,7 +131,7 @@ F src/pragma.c 0246032dbe681dded8710ac43eaf654eead1434e F src/prepare.c f811fdb6fd4a82cca673a6e1d5b041d6caf567f1 F src/printf.c c94a2571a828b927c64f5e3ed3584da8a91fcaec F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da -F src/select.c 7c0ab94b8f287eb94fdb1eb101be603832ecfc34 +F src/select.c 2c08239b55cf93c03a79cbdedf1ac89967fd6acb F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c c97be281cfc3dcb14902f45e4b16f20038eb83ff F src/sqlite.h.in 544587c10005dde0ad8f132dd9b7816b132b2bea @@ -411,10 +411,10 @@ F test/rowid.test d125991eea1ffdea800d48471afd8fc4acc10b01 F test/safety.test 4a06934e45d03b8b50ebcd8d174eb0367d2fd851 F test/schema.test a8b000723375fd42c68d310091bdbd744fde647c F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e -F test/select1.test 7603a4d406ea00516233e26539d2fac0cc85e732 +F test/select1.test d091e1c8ad23c9bd6d7d55d2dd16b08e68e16f63 F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3 F test/select3.test 47439f28862489626b483b0c718cfb0562e6f6d5 -F test/select4.test 305ba0a6e97efc5544def5e5cb49b54e1bf87fd9 +F test/select4.test 4192e6c712194d53b4b77f094eb9d880b8d5ac0e F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8 F test/select7.test 7906735805cfbee4dddc0bed4c14e68d7f5f9c5f @@ -597,7 +597,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 1d6a9f5fafb862fb31c8589fa118a5672bad6abd -R 378bf8f52e8d83775a501365b0bea297 +P 4be8e6765bf8bc48747b2542f2ed77066fb9dcb9 +R adfe92f0c9624e9b76a7c1a73370b4bd U drh -Z 0788daae7a5c65291d88fcc1de49b7ff +Z af9ac541bec9448e79940f97cacc1ce8 diff --git a/manifest.uuid b/manifest.uuid index 4d2c50d955..9daf060857 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4be8e6765bf8bc48747b2542f2ed77066fb9dcb9 \ No newline at end of file +62a78d212c53a9cb1759d03134653a75f3a086b6 \ No newline at end of file diff --git a/src/select.c b/src/select.c index f16bb636bf..09074e2c32 100644 --- a/src/select.c +++ b/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.363 2007/11/23 13:42:52 drh Exp $ +** $Id: select.c,v 1.364 2007/12/08 21:10:20 drh Exp $ */ #include "sqliteInt.h" @@ -1412,6 +1412,15 @@ static int prepSelectStmt(Parse *pParse, Select *p){ return rc; } +/* +** During the process of matching ORDER BY terms to columns of the +** result set, the Exprlist.a[].done flag can be set to one of the +** following values: +*/ +#define ORDERBY_MATCH_NONE 0 /* No match found */ +#define ORDERBY_MATCH_PARTIAL 1 /* A good match, but not perfect */ +#define ORDERBY_MATCH_EXACT 2 /* An exact match seen */ + #ifndef SQLITE_OMIT_COMPOUND_SELECT /* ** This routine associates entries in an ORDER BY expression list with @@ -1431,33 +1440,43 @@ static int matchOrderbyToColumn( Select *pSelect, /* Match to result columns of this SELECT */ ExprList *pOrderBy, /* The ORDER BY values to match against columns */ int iTable, /* Insert this value in iTable */ - int mustComplete /* If TRUE all ORDER BYs must match */ + int rightMost /* TRUE for outermost recursive invocation */ ){ int nErr = 0; int i, j; ExprList *pEList; sqlite3 *db = pParse->db; + NameContext nc; if( pSelect==0 || pOrderBy==0 ) return 1; - if( mustComplete ){ - for(i=0; inExpr; i++){ pOrderBy->a[i].done = 0; } + if( rightMost ){ + assert( pSelect->pOrderBy==pOrderBy ); + for(i=0; inExpr; i++){ + pOrderBy->a[i].done = ORDERBY_MATCH_NONE; + } } - if( prepSelectStmt(pParse, pSelect) ){ + if( pSelect->pPrior + && matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){ return 1; } - if( pSelect->pPrior ){ - if( matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){ - return 1; - } + if( sqlite3SelectResolve(pParse, pSelect, 0) ){ + return 1; } - pEList = pSelect->pEList; - for(i=0; inExpr; i++){ + memset(&nc, 0, sizeof(nc)); + nc.pParse = pParse; + nc.pSrcList = pSelect->pSrc; + nc.pEList = pEList = pSelect->pEList; + nc.allowAgg = 1; + for(i=0; nErr==0 && inExpr; i++){ struct ExprList_item *pItem; Expr *pE = pOrderBy->a[i].pExpr; int iCol = -1; - char *zLabel; + int match = ORDERBY_MATCH_NONE; + Expr *pDup; - if( pOrderBy->a[i].done ) continue; + if( pOrderBy->a[i].done==ORDERBY_MATCH_EXACT ){ + continue; + } if( sqlite3ExprIsInteger(pE, &iCol) ){ if( iCol<=0 || iCol>pEList->nExpr ){ sqlite3ErrorMsg(pParse, @@ -1466,34 +1485,38 @@ static int matchOrderbyToColumn( nErr++; break; } - if( !mustComplete ) continue; + if( !rightMost ) continue; iCol--; + match = ORDERBY_MATCH_EXACT; } - if( iCol<0 && (zLabel = sqlite3NameFromToken(db, &pE->token))!=0 ){ - for(j=0, pItem=pEList->a; jnExpr; j++, pItem++){ - char *zName; - int isMatch; - if( pItem->zName ){ - zName = sqlite3DbStrDup(db, pItem->zName); - }else{ - zName = sqlite3NameFromToken(db, &pItem->pExpr->token); - } - isMatch = zName && sqlite3StrICmp(zName, zLabel)==0; - sqlite3_free(zName); - if( isMatch ){ - iCol = j; - break; + if( !match && pParse->nErr==0 && (pDup = sqlite3ExprDup(db, pE))!=0 ){ + nc.nErr = 0; + assert( pParse->zErrMsg==0 ); + if( sqlite3ExprResolveNames(&nc, pDup) ){ + sqlite3ErrorClear(pParse); + }else{ + for(j=0, pItem=pEList->a; jnExpr; j++, pItem++){ + if( sqlite3ExprCompare(pItem->pExpr, pDup) ){ + iCol = j; + match = ORDERBY_MATCH_PARTIAL; + break; + } } } - sqlite3_free(zLabel); + sqlite3ExprDelete(pDup); } - if( iCol>=0 ){ + if( match ){ pE->op = TK_COLUMN; - pE->iColumn = iCol; pE->iTable = iTable; pE->iAgg = -1; - pOrderBy->a[i].done = 1; - }else if( mustComplete ){ + if( pOrderBy->a[i].done!=ORDERBY_MATCH_NONE && pE->iColumn!=iCol ){ + sqlite3ErrorMsg(pParse, + "ORDER BY term number %d is ambiguous", i+1); + nErr++; + } + pE->iColumn = iCol; + pOrderBy->a[i].done = match; + }else if( rightMost && pOrderBy->a[i].done==ORDERBY_MATCH_NONE ){ sqlite3ErrorMsg(pParse, "ORDER BY term number %d does not match any result column", i+1); nErr++; @@ -2720,11 +2743,11 @@ int sqlite3SelectResolve( sqlite3ExprResolveNames(&sNC, p->pHaving) ){ return SQLITE_ERROR; } - if( p->pPrior==0 ){ - if( processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") || - processOrderGroupBy(&sNC, pGroupBy, "GROUP") ){ - return SQLITE_ERROR; - } + if( p->pPrior==0 && processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") ){ + return SQLITE_ERROR; + } + if( processOrderGroupBy(&sNC, pGroupBy, "GROUP") ){ + return SQLITE_ERROR; } if( pParse->db->mallocFailed ){ diff --git a/test/select1.test b/test/select1.test index 0393145e79..6ed92c7330 100644 --- a/test/select1.test +++ b/test/select1.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # -# $Id: select1.test,v 1.54 2007/07/23 22:51:15 drh Exp $ +# $Id: select1.test,v 1.55 2007/12/08 21:10:20 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -517,7 +517,7 @@ do_test select1-6.10 { do_test select1-6.11 { set v [catch {execsql2 { SELECT f1 FROM test1 UNION SELECT f2+100 FROM test1 - ORDER BY f2+100; + ORDER BY f2+101; }} msg] lappend v $msg } {1 {ORDER BY term number 1 does not match any result column}} diff --git a/test/select4.test b/test/select4.test index 5c3b808ab8..e26b89414f 100644 --- a/test/select4.test +++ b/test/select4.test @@ -12,7 +12,7 @@ # focus of this file is testing UNION, INTERSECT and EXCEPT operators # in SELECT statements. # -# $Id: select4.test,v 1.20 2006/06/20 11:01:09 danielk1977 Exp $ +# $Id: select4.test,v 1.21 2007/12/08 21:10:20 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -283,7 +283,7 @@ do_test select4-5.2b { SELECT DISTINCT log AS xyzzy FROM t1 UNION ALL SELECT n FROM t1 WHERE log=3 - ORDER BY 'xyzzy'; + ORDER BY "xyzzy"; }} msg] lappend v $msg } {0 {0 1 2 3 4 5 5 6 7 8}} @@ -292,7 +292,7 @@ do_test select4-5.2c { SELECT DISTINCT log FROM t1 UNION ALL SELECT n FROM t1 WHERE log=3 - ORDER BY 'xyzzy'; + ORDER BY "xyzzy"; }} msg] lappend v $msg } {1 {ORDER BY term number 1 does not match any result column}} @@ -301,7 +301,7 @@ do_test select4-5.2d { SELECT DISTINCT log FROM t1 INTERSECT SELECT n FROM t1 WHERE log=3 - ORDER BY 'xyzzy'; + ORDER BY "xyzzy"; }} msg] lappend v $msg } {1 {ORDER BY term number 1 does not match any result column}}