Further modifications to do with ORDER BY and compound SELECT queries. Related to ticket #2822. (CVS 4606)
FossilOrigin-Name: 0d9b0e6e3a8f8a66956878084085842e94c3cb2f
This commit is contained in:
parent
6ed4b78123
commit
70517ab9a1
17
manifest
17
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
|
||||
|
@ -1 +1 @@
|
||||
6adbe91efffc6b3f53dae87494430ede61d40ecc
|
||||
0d9b0e6e3a8f8a66956878084085842e94c3cb2f
|
120
src/select.c
120
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; i<pOrderBy->nExpr; 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 && i<pOrderBy->nExpr; 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; j<pEList->nExpr; 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; j<pEList->nExpr; 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
102
test/tkt2822.test
Normal file
102
test/tkt2822.test
Normal file
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user