From: danielk1977 Date: Mon, 10 Dec 2007 18:51:47 +0000 (+0000) Subject: Further modifications to do with ORDER BY and compound SELECT queries. Related to... X-Git-Tag: version-3.6.10~1571 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=70517ab9a171f8cbadb58b3f062391a2253d717a;p=thirdparty%2Fsqlite.git Further modifications to do with ORDER BY and compound SELECT queries. Related to ticket #2822. (CVS 4606) FossilOrigin-Name: 0d9b0e6e3a8f8a66956878084085842e94c3cb2f --- diff --git a/manifest b/manifest index 839693fd1b..904cd28c25 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\smacro\sin\sfunc.c\sthat\scauses\sproblems\sfor\sthe\samalgamation.\s(CVS\s4605) -D 2007-12-10T18:07:21 +C Further\smodifications\sto\sdo\swith\sORDER\sBY\sand\scompound\sSELECT\squeries.\sRelated\sto\sticket\s#2822.\s(CVS\s4606) +D 2007-12-10T18:51:48 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 2c08239b55cf93c03a79cbdedf1ac89967fd6acb +F src/select.c b7408624b55f58e5aa8521edb177b26ad72f968b F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c c97be281cfc3dcb14902f45e4b16f20038eb83ff F src/sqlite.h.in 544587c10005dde0ad8f132dd9b7816b132b2bea @@ -414,7 +414,7 @@ F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e F test/select1.test 79784038f0e7df66bb420e149c6fb91e61e11fb7 F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3 F test/select3.test 47439f28862489626b483b0c718cfb0562e6f6d5 -F test/select4.test 4192e6c712194d53b4b77f094eb9d880b8d5ac0e +F test/select4.test 2dd28cfea6f50281fb29cf136cf50df8ead6a5d2 F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8 F test/select7.test 7906735805cfbee4dddc0bed4c14e68d7f5f9c5f @@ -478,6 +478,7 @@ F test/tkt2686.test 3022db0eee8ecf501f516557c77ef1c4039399cd F test/tkt2767.test 6b02308d553d194f329a469bf5c157fe724738d4 F test/tkt2817.test 709a2201a5590bf56cb97f6fb168a62282203fd1 F test/tkt2820.test 017fdee33aaef7abc092beab6088816f1942304b +F test/tkt2822.test 782d6041b9ec10c74e28768f477cba722c43d88e F test/trace.test 75ffc1b992c780d054748a656e3e7fd674f18567 F test/trans.test b73289992b46d38d9479ecc4fdc03d8edb2413dc F test/trigger1.test 7c13f39ca36f529bf856e05c7d004fc0531d48b4 @@ -597,7 +598,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P d384810a95c97b868a87d090f8dcb903cc82cbf7 -R 02ccd20331c3a0f99f895b6e82412309 -U drh -Z f800f34be093e13e0ebe3d12e796a99d +P 6adbe91efffc6b3f53dae87494430ede61d40ecc +R c5664694f29e5838b66b78cd136777a8 +U danielk1977 +Z 0cfc5f38f552087a6f749e4e8561ad47 diff --git a/manifest.uuid b/manifest.uuid index cc805b2b93..28298be38f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6adbe91efffc6b3f53dae87494430ede61d40ecc \ No newline at end of file +0d9b0e6e3a8f8a66956878084085842e94c3cb2f \ No newline at end of file diff --git a/src/select.c b/src/select.c index 09074e2c32..49273ed102 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.364 2007/12/08 21:10:20 drh Exp $ +** $Id: select.c,v 1.365 2007/12/10 18:51:48 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -1412,15 +1412,6 @@ 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 @@ -1429,9 +1420,6 @@ static int prepSelectStmt(Parse *pParse, Select *p){ ** the top-level node is filled in with column number and the iTable ** value of the top-level node is filled with iTable parameter. ** -** If there are prior SELECT clauses, they are processed first. A match -** in an earlier SELECT takes precedence over a later SELECT. -** ** Any entry that does not match is flagged as an error. The number ** of errors is returned. */ @@ -1439,91 +1427,83 @@ static int matchOrderbyToColumn( Parse *pParse, /* A place to leave error messages */ 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 rightMost /* TRUE for outermost recursive invocation */ + int iTable /* Insert this value in iTable */ ){ int nErr = 0; int i, j; - ExprList *pEList; sqlite3 *db = pParse->db; - NameContext nc; + int nExpr; if( pSelect==0 || pOrderBy==0 ) return 1; - if( rightMost ){ - assert( pSelect->pOrderBy==pOrderBy ); - for(i=0; inExpr; i++){ - pOrderBy->a[i].done = ORDERBY_MATCH_NONE; - } - } - if( pSelect->pPrior - && matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){ - return 1; - } if( sqlite3SelectResolve(pParse, pSelect, 0) ){ return 1; } - memset(&nc, 0, sizeof(nc)); - nc.pParse = pParse; - nc.pSrcList = pSelect->pSrc; - nc.pEList = pEList = pSelect->pEList; - nc.allowAgg = 1; + + nExpr = pSelect->pEList->nExpr; for(i=0; nErr==0 && inExpr; i++){ - struct ExprList_item *pItem; Expr *pE = pOrderBy->a[i].pExpr; int iCol = -1; - int match = ORDERBY_MATCH_NONE; - Expr *pDup; - if( pOrderBy->a[i].done==ORDERBY_MATCH_EXACT ){ - continue; - } if( sqlite3ExprIsInteger(pE, &iCol) ){ - if( iCol<=0 || iCol>pEList->nExpr ){ + if( iCol<=0 || iCol>nExpr ){ sqlite3ErrorMsg(pParse, "ORDER BY position %d should be between 1 and %d", - iCol, pEList->nExpr); + iCol, nExpr); nErr++; break; } - if( !rightMost ) continue; iCol--; - match = ORDERBY_MATCH_EXACT; - } - 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; + }else{ + Select *p; + for(p=pSelect; p; p=p->pPrior){ + ExprList *pEList = p->pEList; + Expr *pDup = sqlite3ExprDup(db, pE); + + NameContext nc; + + memset(&nc, 0, sizeof(nc)); + nc.pParse = pParse; + nc.pSrcList = p->pSrc; + nc.pEList = pEList; + nc.allowAgg = 1; + nc.nErr = 0; + if( sqlite3ExprResolveNames(&nc, pDup) ){ + sqlite3ErrorClear(pParse); + }else{ + struct ExprList_item *pItem; + for(j=0, pItem=pEList->a; jnExpr; j++, pItem++){ + if( sqlite3ExprCompare(pItem->pExpr, pDup) ){ + if( iCol>=0 && iCol!=j ){ + sqlite3ErrorMsg( + pParse, "ORDER BY term number %d is ambiguous", i+1 + ); + }else{ + iCol = j; + } + } } } + sqlite3ExprDelete(pDup); } - sqlite3ExprDelete(pDup); } - if( match ){ + + if( iCol<0 ){ + sqlite3ErrorMsg(pParse, + "ORDER BY term number %d does not match any result column", i+1); + }else{ pE->op = TK_COLUMN; pE->iTable = iTable; pE->iAgg = -1; - 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++; - break; + pOrderBy->a[i].done = 1; + } + + if( pParse->nErr ){ + return pParse->nErr; } } - return nErr; + + return SQLITE_OK; } #endif /* #ifndef SQLITE_OMIT_COMPOUND_SELECT */ @@ -1788,7 +1768,7 @@ static int multiSelect( ** intermediate results. */ unionTab = pParse->nTab++; - if( pOrderBy && matchOrderbyToColumn(pParse, p, pOrderBy, unionTab,1) ){ + if( pOrderBy && matchOrderbyToColumn(pParse, p, pOrderBy, unionTab) ){ rc = 1; goto multi_select_end; } @@ -1885,7 +1865,7 @@ static int multiSelect( */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; - if( pOrderBy && matchOrderbyToColumn(pParse,p,pOrderBy,tab1,1) ){ + if( pOrderBy && matchOrderbyToColumn(pParse,p,pOrderBy,tab1) ){ rc = 1; goto multi_select_end; } diff --git a/test/select4.test b/test/select4.test index e26b89414f..713abe7556 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.21 2007/12/08 21:10:20 drh Exp $ +# $Id: select4.test,v 1.22 2007/12/10 18:51:48 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -572,13 +572,14 @@ do_test select4-9.7 { } ;# ifcapable subquery do_test select4-9.8 { - execsql2 { + catchsql { SELECT 0 AS x, 1 AS y UNION SELECT 2 AS y, -3 AS x ORDER BY x LIMIT 1; } -} {x 0 y 1} +} {1 {ORDER BY term number 1 is ambiguous}} + do_test select4-9.9.1 { execsql2 { SELECT 1 AS a, 2 AS b UNION ALL SELECT 3 AS b, 4 AS a diff --git a/test/tkt2822.test b/test/tkt2822.test new file mode 100644 index 0000000000..beff84ccf3 --- /dev/null +++ b/test/tkt2822.test @@ -0,0 +1,102 @@ +# 2007 Dec 4 +# +# 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 is to test that the issues surrounding expressions in +# ORDER BY clauses on compound SELECT statements raised by ticket +# #2822 have been dealt with. +# +# $Id: tkt2822.test,v 1.1 2007/12/10 18:51:48 danielk1977 Exp $ +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Test plan: +# +# tkt2820-1.* - Simple identifier as ORDER BY expression. +# tkt2820-2.* - More complex ORDER BY expressions. + +do_test tkt2820-1.1 { + execsql { + CREATE TABLE t1(a, b, c); + CREATE TABLE t2(c, b, a); + + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t2 VALUES(3, 2, 1); + } +} {} + +# If an ORDER BY expression matches two different columns, it is an error. +# +do_test tkt2820-1.2 { + catchsql { + SELECT a, b FROM t1 UNION ALL SELECT b, a FROM t2 ORDER BY a; + } +} {1 {ORDER BY term number 1 is ambiguous}} +do_test tkt2820-1.3 { + catchsql { + SELECT a, b, c FROM t2 UNION ALL SELECT c, b, a FROM t1 ORDER BY a; + } +} {1 {ORDER BY term number 1 is ambiguous}} + +# But not if it matches the same column in two or more of the +# compounded SELECT statements. +# +do_test tkt2820-1.4 { + execsql { + SELECT a, b, c FROM t2 UNION ALL SELECT a, b, c FROM t1 ORDER BY a; + } +} {1 2 3 1 2 3} + +do_test tkt2820-1.5 { + execsql { + SELECT a, b FROM t2 UNION ALL SELECT c, b FROM t1 ORDER BY c; + } +} {1 2 3 2} + +# If a match cannot be found in any SELECT, return an error. +# +do_test tkt2820-1.6 { + catchsql { + SELECT * FROM t2 UNION ALL SELECT * FROM t1 ORDER BY d; + } +} {1 {ORDER BY term number 1 does not match any result column}} + + +do_test tkt2820-2.1 { + execsql { + SELECT a+1, b+1 FROM t1 UNION ALL SELECT a, c FROM t2 ORDER BY a+1; + } +} {1 3 2 3} +do_test tkt2820-2.2 { + catchsql { + SELECT a+1, b+1 FROM t1 UNION ALL SELECT a, c FROM t2 ORDER BY a+2; + } +} {1 {ORDER BY term number 1 does not match any result column}} +do_test tkt2820-2.3 { + catchsql { + SELECT a+1, b+1 FROM t1 UNION ALL SELECT c, a+1 FROM t2 ORDER BY a+1; + } +} {1 {ORDER BY term number 1 is ambiguous}} + +do_test tkt2820-2.4 { + execsql { + SELECT t1.a, b+1 FROM t1 UNION ALL SELECT c, a+1 FROM t2 ORDER BY a; + } +} {1 3 3 2} +do_test tkt2820-2.5 { + execsql { + SELECT t1.a, b+1 FROM t1 UNION ALL SELECT c, a+1 FROM t2 ORDER BY t1.a; + } +} {1 3 3 2} + +finish_test +