Enhance the ORDER BY clause so that an integer term means to sort by the

corresponding column. (CVS 602)

FossilOrigin-Name: 7acbf84b492202d8b5a05276a95b475027eb5f58
This commit is contained in:
drh 2002-06-02 16:09:01 +00:00
parent 1288c9561d
commit e4de1feb3e
7 changed files with 187 additions and 35 deletions

View File

@ -1,5 +1,5 @@
C Multiplying\sNULL\sby\szero\sgives\sNULL,\snot\szero.\s\sI\smisread\sthe\stest\sdata\nand\scoded\sit\swrong.\s\sThis\scheck-in\sfixes\sthe\sproblem.\s(CVS\s601)
D 2002-06-01T21:41:10
C Enhance\sthe\sORDER\sBY\sclause\sso\sthat\san\sinteger\sterm\smeans\sto\ssort\sby\sthe\ncorresponding\scolumn.\s(CVS\s602)
D 2002-06-02T16:09:02
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@ -23,7 +23,7 @@ F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
F src/build.c 36e42718a7a94f554ea39508993378482f5335c7
F src/delete.c a2b098cbbf518e6b641847e26de85827793bc523
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
F src/expr.c 6bb74762c3d86b1665b32a6a388a70eeaaca93f8
F src/expr.c 4ee07b536119e7ee4f572e1ca83ad86c1aef0058
F src/func.c 061a520a122da7e4f9dcac15697bb996aac7d5df
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
@ -37,11 +37,11 @@ F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
F src/parse.y c681da701bf142967325b8791f22418e2d81552d
F src/printf.c d8032ee18b860c812eeff596c9bebfdacb7930fd
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c 9a9f76d7d647284f41616bc120003961bea403ef
F src/select.c ad9061b4735ccd79fc073415979882cd5c424c71
F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b
F src/sqliteInt.h 55824b7c87dcead71801354f90e4f1b1481f1d1e
F src/sqliteInt.h 8ec47ae045cf8525c2bcc1a650853d814ca7675c
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
F src/test1.c 09d95048b66ce6dcd2bae90f443589043d7d631e
@ -87,10 +87,10 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
F test/select1.test a19a8026b5c2c5bdf5384d761f3d446954b7ebf9
F test/select1.test 0d708cec567104653ec9aa49fecf3444a2e7d150
F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
F test/select4.test 32018b97fde7202dcb906748836fcd79410604d3
F test/select4.test 9b5c87b7a372172d65928cf860bcd5a54694c775
F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
F test/select6.test efb8d0c07a440441db87db2c4ade6904e1407e85
F test/sort.test 3b996ce7ca385f9cd559944ac0f4027a23aa546b
@ -136,7 +136,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P da61aa1d238539dff9c43fd9f464d311e28d669f
R f5c3f541431552f938b5386e692916f8
P df9cc852ad02dbec5558d3915a0303f7e7b79b2b
R d820e9b413015f44b726f7ec86a28058
U drh
Z 64d47e65013a776dcf32882cb49edbc6
Z 52b5b2062ca7af0b018c152f36b11673

View File

@ -1 +1 @@
df9cc852ad02dbec5558d3915a0303f7e7b79b2b
7acbf84b492202d8b5a05276a95b475027eb5f58

View File

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.66 2002/05/31 15:51:25 drh Exp $
** $Id: expr.c,v 1.67 2002/06/02 16:09:02 drh Exp $
*/
#include "sqliteInt.h"
@ -335,6 +335,41 @@ int sqliteExprIsConstant(Expr *p){
return 0;
}
/*
** If the given expression codes a constant integer, return 1 and put
** the value of the integer in *pValue. If the expression is not an
** integer, return 0 and leave *pValue unchanged.
*/
int sqliteExprIsInteger(Expr *p, int *pValue){
switch( p->op ){
case TK_INTEGER: {
*pValue = atoi(p->token.z);
return 1;
}
case TK_STRING: {
char *z = p->token.z;
int n = p->token.n;
if( n>0 && z=='-' ){ z++; n--; }
while( n>0 && *z && isdigit(*z) ){ z++; n--; }
if( n==0 ){
*pValue = atoi(p->token.z);
return 1;
}
break;
}
case TK_UMINUS: {
int v;
if( sqliteExprIsInteger(p->pLeft, &v) ){
*pValue = -v;
return 1;
}
break;
}
default: break;
}
return 0;
}
/*
** Return TRUE if the given string is a row-id column name.
*/

View File

@ -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.89 2002/05/31 15:51:25 drh Exp $
** $Id: select.c,v 1.90 2002/06/02 16:09:02 drh Exp $
*/
#include "sqliteInt.h"
@ -790,7 +790,7 @@ 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 this value in iTable */
int iTable, /* Insert this value in iTable */
int mustComplete /* If TRUE all ORDER BYs must match */
){
int nErr = 0;
@ -812,9 +812,21 @@ static int matchOrderbyToColumn(
pEList = pSelect->pEList;
for(i=0; i<pOrderBy->nExpr; i++){
Expr *pE = pOrderBy->a[i].pExpr;
int match = 0;
int iCol = -1;
if( pOrderBy->a[i].done ) continue;
for(j=0; j<pEList->nExpr; j++){
if( sqliteExprIsInteger(pE, &iCol) ){
if( iCol<=0 || iCol>pEList->nExpr ){
char zBuf[200];
sprintf(zBuf,"ORDER BY position %d should be between 1 and %d",
iCol, pEList->nExpr);
sqliteSetString(&pParse->zErrMsg, zBuf, 0);
pParse->nErr++;
nErr++;
break;
}
iCol--;
}
for(j=0; iCol<0 && j<pEList->nExpr; j++){
if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){
char *zName, *zLabel;
zName = pEList->a[j].zName;
@ -822,22 +834,21 @@ static int matchOrderbyToColumn(
zLabel = sqliteStrNDup(pE->token.z, pE->token.n);
sqliteDequote(zLabel);
if( sqliteStrICmp(zName, zLabel)==0 ){
match = 1;
iCol = j;
}
sqliteFree(zLabel);
}
if( match==0 && sqliteExprCompare(pE, pEList->a[j].pExpr) ){
match = 1;
}
if( match ){
pE->op = TK_COLUMN;
pE->iColumn = j;
pE->iTable = iTable;
pOrderBy->a[i].done = 1;
break;
if( iCol<0 && sqliteExprCompare(pE, pEList->a[j].pExpr) ){
iCol = j;
}
}
if( !match && mustComplete ){
if( iCol>=0 ){
pE->op = TK_COLUMN;
pE->iColumn = iCol;
pE->iTable = iTable;
pOrderBy->a[i].done = 1;
}
if( iCol<0 && mustComplete ){
char zBuf[30];
sprintf(zBuf,"%d",i+1);
sqliteSetString(&pParse->zErrMsg, "ORDER BY term number ", zBuf,
@ -1520,10 +1531,22 @@ int sqliteSelect(
for(i=0; i<pOrderBy->nExpr; i++){
Expr *pE = pOrderBy->a[i].pExpr;
if( sqliteExprIsConstant(pE) ){
sqliteSetString(&pParse->zErrMsg,
"ORDER BY expressions should not be constant", 0);
pParse->nErr++;
goto select_end;
int iCol;
if( sqliteExprIsInteger(pE, &iCol)==0 ){
sqliteSetString(&pParse->zErrMsg,
"ORDER BY terms must not be non-integer constants", 0);
pParse->nErr++;
goto select_end;
}else if( iCol<=0 || iCol>pEList->nExpr ){
char zBuf[2000];
sprintf(zBuf,"ORDER BY column number %d out of range - should be "
"between 1 and %d", iCol, pEList->nExpr);
sqliteSetString(&pParse->zErrMsg, zBuf, 0);
pParse->nErr++;
goto select_end;
}
sqliteExprDelete(pE);
pE = pOrderBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr);
}
if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pE) ){
goto select_end;

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.118 2002/05/27 12:24:49 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.119 2002/06/02 16:09:02 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
@ -841,6 +841,7 @@ void sqliteCommitTransaction(Parse*);
void sqliteRollbackTransaction(Parse*);
char *sqlite_mprintf(const char *, ...);
int sqliteExprIsConstant(Expr*);
int sqliteExprIsInteger(Expr*, int*);
void sqliteGenerateRowDelete(Vdbe*, Table*, int, int);
void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*);
void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);

View File

@ -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.29 2002/05/29 23:22:23 drh Exp $
# $Id: select1.test,v 1.30 2002/06/02 16:09:03 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -285,7 +285,52 @@ do_test select1-4.5 {
catchsql {
SELECT f1 FROM test1 ORDER BY 8.4;
}
} {1 {ORDER BY expressions should not be constant}}
} {1 {ORDER BY terms must not be non-integer constants}}
do_test select1-4.6 {
catchsql {
SELECT f1 FROM test1 ORDER BY '8.4';
}
} {1 {ORDER BY terms must not be non-integer constants}}
do_test select1-4.7 {
catchsql {
SELECT f1 FROM test1 ORDER BY 'xyz';
}
} {1 {ORDER BY terms must not be non-integer constants}}
do_test select1-4.8 {
execsql {
CREATE TABLE t5(a,b);
INSERT INTO t5 VALUES(1,10);
INSERT INTO t5 VALUES(2,9);
SELECT * FROM t5 ORDER BY 1;
}
} {1 10 2 9}
do_test select1-4.9 {
execsql {
SELECT * FROM t5 ORDER BY 2;
}
} {2 9 1 10}
do_test select1-4.10 {
catchsql {
SELECT * FROM t5 ORDER BY 3;
}
} {1 {ORDER BY column number 3 out of range - should be between 1 and 2}}
do_test select1-4.11 {
execsql {
INSERT INTO t5 VALUES(3,10);
SELECT * FROM t5 ORDER BY 2, 1 DESC;
}
} {2 9 3 10 1 10}
do_test select1-4.12 {
execsql {
SELECT * FROM t5 ORDER BY 1 DESC, b;
}
} {3 10 2 9 1 10}
do_test select1-4.13 {
execsql {
SELECT * FROM t5 ORDER BY b DESC, 1;
}
} {1 10 3 10 2 9}
# ORDER BY ignored on an aggregate query
#

View File

@ -12,7 +12,7 @@
# focus of this file is testing UNION, INTERSECT and EXCEPT operators
# in SELECT statements.
#
# $Id: select4.test,v 1.9 2002/05/31 15:51:26 drh Exp $
# $Id: select4.test,v 1.10 2002/06/02 16:09:03 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -209,6 +209,54 @@ do_test select4-5.2e {
}} msg]
lappend v $msg
} {0 {0 1 2 3 4 5 5 6 7 8}}
do_test select4-5.2f {
catchsql {
SELECT DISTINCT log FROM t1
UNION ALL
SELECT n FROM t1 WHERE log=3
ORDER BY log;
}
} {0 {0 1 2 3 4 5 5 6 7 8}}
do_test select4-5.2g {
catchsql {
SELECT DISTINCT log FROM t1
UNION ALL
SELECT n FROM t1 WHERE log=3
ORDER BY 1;
}
} {0 {0 1 2 3 4 5 5 6 7 8}}
do_test select4-5.2h {
catchsql {
SELECT DISTINCT log FROM t1
UNION ALL
SELECT n FROM t1 WHERE log=3
ORDER BY 2;
}
} {1 {ORDER BY position 2 should be between 1 and 1}}
do_test select4-5.2i {
catchsql {
SELECT DISTINCT 1, log FROM t1
UNION ALL
SELECT 2, n FROM t1 WHERE log=3
ORDER BY 2, 1;
}
} {0 {1 0 1 1 1 2 1 3 1 4 1 5 2 5 2 6 2 7 2 8}}
do_test select4-5.2j {
catchsql {
SELECT DISTINCT 1, log FROM t1
UNION ALL
SELECT 2, n FROM t1 WHERE log=3
ORDER BY 1, 2 DESC;
}
} {0 {1 5 1 4 1 3 1 2 1 1 1 0 2 8 2 7 2 6 2 5}}
do_test select4-5.2k {
catchsql {
SELECT DISTINCT 1, log FROM t1
UNION ALL
SELECT 2, n FROM t1 WHERE log=3
ORDER BY n, 1;
}
} {0 {1 0 1 1 1 2 1 3 1 4 1 5 2 5 2 6 2 7 2 8}}
do_test select4-5.3 {
set v [catch {execsql {
SELECT DISTINCT log, n FROM t1