The right-hand side of an AS in a SELECT can be used within expressions of

the WHERE, ORDER BY, GROUP BY, and/or HAVING clauses. (CVS 350)

FossilOrigin-Name: 3684beab0f8a71ebdf453871bbde7a9ab1f65385
This commit is contained in:
drh
2002-01-22 03:13:42 +00:00
parent 555fcb489b
commit a2e00042a1
13 changed files with 155 additions and 57 deletions
+1 -1
View File
@@ -1 +1 @@
2.2.3
2.2.4
+16 -16
View File
@@ -1,9 +1,9 @@
C Version\s2.2.3\s(CVS\s450)
D 2002-01-16T21:05:00
C The\sright-hand\sside\sof\san\sAS\sin\sa\sSELECT\scan\sbe\sused\swithin\sexpressions\sof\nthe\sWHERE,\sORDER\sBY,\sGROUP\sBY,\sand/or\sHAVING\sclauses.\s(CVS\s350)
D 2002-01-22T03:13:42
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
F Makefile.template 3e26a3b9e7aee1b811deaf673e8d8973bdb3f22d
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
F VERSION da55054c39447bab51e716c492a9fa987086fa17
F VERSION 2af606990ed9af7308a6e04cd7c9efd550f4e7be
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
@@ -21,9 +21,9 @@ F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c c796e387da340cb628dc1e41f684fc20253f561e
F src/btree.h 9ead7f54c270d8a554e59352ca7318fdaf411390
F src/build.c d44fbcfaf0eacd33a4686aa4dda8fc770b640421
F src/delete.c f7690efc09ad6a2f1f3f0490e1b0cbb676bb95cf
F src/expr.c 8169261ac56e96c860407a8773ca10b779e32328
F src/build.c bf8456b56011bb3761f11ff4a14121cfbbbd78da
F src/delete.c cc200609f927ee8fefdda5d11d3f3b2288493c0f
F src/expr.c 3c4359f9a00791f73569547bb11ce0f0fa5da631
F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
F src/insert.c 813c37719866c583e6ca7660f94f10230f4e385d
@@ -36,18 +36,18 @@ F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe
F src/parse.y f3fc4fb5766393003577bd175eb611495f6efd9f
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
F src/random.c f6b36bec5ebd3edb3440224bf5bf811fe4ac9a1b
F src/select.c bddd8b5d07ffdae0d798c10b20dc7167469a3904
F src/select.c f944a94d5004a1b87a5c6b1e41c29ac94488b42a
F src/shell.c 539a41d4121ed371d438d57d829e53056a54471c
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
F src/sqliteInt.h 2382456c76bd66d0255d385820af1c72c961540c
F src/sqliteInt.h 576b7b8165b2d78204412227e242cded54188bd5
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
F src/update.c 5cb326ed4bace89cbad7d919b828da6c2a9064e4
F src/update.c f30a47928fb7e894221eab2a81c8fa2653f96fb0
F src/util.c 3958a14a2dbfb13fa5f779976b4d0daf9ab49bb1
F src/vdbe.c 158bab65e4eafceb75a83f616caafa2c58f00242
F src/vdbe.h e5cc6fb13d1905a4339db4d6dba4ab393c0765fa
@@ -77,9 +77,9 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
F test/rowid.test cb023f2df36886e1fc4cdfd32eaba05cf7db4331
F test/select1.test 7423a9dbb81b6d282b13cbe10be64d1216dec155
F test/select1.test 391a1e1a0527391d1bfa2daab279bf6be21da011
F test/select2.test ed2c1882857106b85478f54f67000e14966be4c4
F test/select3.test 5e1fe8e5a4e63fb2827ab3b89527e0fd4ae35259
F test/select3.test 3a053d8fd29e10b55f468644641098b5c9adbc06
F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
F test/sort.test 462c1161eee1abaa7cc93990e0b34d5fdb70ce19
@@ -105,11 +105,11 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
F www/c_interface.tcl 82a026b1681757f13b3f62e035f3a31407c1d353
F www/changes.tcl 21116410e94d5f0852b49880ddf65f390423f24c
F www/changes.tcl 0f1348ff7203706633953211c7b4bb73bd6a723f
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
F www/download.tcl 1ea61f9d89a2a5a9b2cee36b0d5cf97321bdefe0
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/faq.tcl 324ec51080e5c3d62ccce4fb22a8b839eaded694
F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9
F www/formatchng.tcl d96e5e937dcbbebd481720aa08745ca5a906a63f
F www/index.tcl 571c585a5c0b577db2fe7cb88cf1f12cccd96ceb
F www/lang.tcl 6843fd3f85cba95fd199a350533ce742c706603c
@@ -119,7 +119,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P f74d61aaf3fec06cde2c4a6f1465f86ac9058ad2
R 0e682a68cf7bb91386b1d3da8599787d
P a4fe893ce7cdec0d8a4f8cdc640b8967dce7763e
R 42174a8584ff6b02199355782a39f765
U drh
Z d05a6c87487d5a9de2ff07f77b94d69d
Z 43f0669b77399b52f2f84c6f1b77e1c1
+1 -1
View File
@@ -1 +1 @@
a4fe893ce7cdec0d8a4f8cdc640b8967dce7763e
3684beab0f8a71ebdf453871bbde7a9ab1f65385
+1 -13
View File
@@ -25,7 +25,7 @@
** ROLLBACK
** PRAGMA
**
** $Id: build.c,v 1.64 2002/01/10 14:31:49 drh Exp $
** $Id: build.c,v 1.65 2002/01/22 03:13:42 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -127,18 +127,6 @@ Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
return pNew;
}
/*
** Recursively delete an expression tree.
*/
void sqliteExprDelete(Expr *p){
if( p==0 ) return;
if( p->pLeft ) sqliteExprDelete(p->pLeft);
if( p->pRight ) sqliteExprDelete(p->pRight);
if( p->pList ) sqliteExprListDelete(p->pList);
if( p->pSelect ) sqliteSelectDelete(p->pSelect);
sqliteFree(p);
}
/*
** Locate the in-memory structure that describes
** a particular database table given the name
+2 -2
View File
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.22 2001/12/21 14:30:43 drh Exp $
** $Id: delete.c,v 1.23 2002/01/22 03:13:42 drh Exp $
*/
#include "sqliteInt.h"
@@ -70,7 +70,7 @@ void sqliteDeleteFrom(
*/
if( pWhere ){
sqliteExprResolveInSelect(pParse, pWhere);
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
goto delete_from_cleanup;
}
if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
+55 -8
View File
@@ -12,10 +12,25 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.37 2002/01/06 17:07:40 drh Exp $
** $Id: expr.c,v 1.38 2002/01/22 03:13:42 drh Exp $
*/
#include "sqliteInt.h"
/*
** Recursively delete an expression tree.
*/
void sqliteExprDelete(Expr *p){
if( p==0 ) return;
if( p->op!=TK_AS ){
if( p->pLeft ) sqliteExprDelete(p->pLeft);
if( p->pRight ) sqliteExprDelete(p->pRight);
}
if( p->pList ) sqliteExprListDelete(p->pList);
if( p->pSelect ) sqliteSelectDelete(p->pSelect);
sqliteFree(p);
}
/*
** Walk an expression tree. Return 1 if the expression is constant
** and 0 if it involves variables.
@@ -116,10 +131,24 @@ static int sqliteIsRowid(const char *z){
** Unknown columns or tables provoke an error. The function returns
** the number of errors seen and leaves an error message on pParse->zErrMsg.
*/
int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
int sqliteExprResolveIds(
Parse *pParse, /* The parser context */
IdList *pTabList, /* List of tables used to resolve column names */
ExprList *pEList, /* List of expressions used to resolve "AS" */
Expr *pExpr /* The expression to be analyzed. */
){
if( pExpr==0 || pTabList==0 ) return 0;
switch( pExpr->op ){
/* A lone identifier */
/* A lone identifier. Try and match it as follows:
**
** 1. To the name of a column of one of the tables in pTabList
**
** 2. To the right side of an AS keyword in the column list of
** a SELECT statement. (For example, match against 'x' in
** "SELECT a+b AS 'x' FROM t1".)
**
** 3. One of the special names "ROWID", "OID", or "_ROWID_".
*/
case TK_ID: {
int cnt = 0; /* Number of matches */
int i; /* Loop counter */
@@ -139,13 +168,28 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
}else{
pExpr->iColumn = j;
}
pExpr->op = TK_COLUMN;
}
}
}
if( cnt==0 && pEList!=0 ){
int j;
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqliteStrICmp(zAs, z)==0 ){
cnt++;
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pExpr->op = TK_AS;
pExpr->iColumn = j;
pExpr->pLeft = pEList->a[j].pExpr;
}
}
}
if( cnt==0 && sqliteIsRowid(z) ){
pExpr->iColumn = -1;
pExpr->iTable = pParse->nTab;
cnt = 1 + (pTabList->nId>1);
pExpr->op = TK_COLUMN;
}
sqliteFree(z);
if( cnt==0 ){
@@ -159,7 +203,6 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
pParse->nErr++;
return 1;
}
pExpr->op = TK_COLUMN;
break;
}
@@ -240,7 +283,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
case TK_IN: {
Vdbe *v = sqliteGetVdbe(pParse);
if( v==0 ) return 1;
if( sqliteExprResolveIds(pParse, pTabList, pExpr->pLeft) ){
if( sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){
return 1;
}
if( pExpr->pSelect ){
@@ -309,18 +352,18 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
/* For all else, just recursively walk the tree */
default: {
if( pExpr->pLeft
&& sqliteExprResolveIds(pParse, pTabList, pExpr->pLeft) ){
&& sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){
return 1;
}
if( pExpr->pRight
&& sqliteExprResolveIds(pParse, pTabList, pExpr->pRight) ){
&& sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pRight) ){
return 1;
}
if( pExpr->pList ){
int i;
ExprList *pList = pExpr->pList;
for(i=0; i<pList->nExpr; i++){
if( sqliteExprResolveIds(pParse, pTabList, pList->a[i].pExpr) ){
if( sqliteExprResolveIds(pParse,pTabList,pEList,pList->a[i].pExpr) ){
return 1;
}
}
@@ -704,6 +747,10 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeResolveLabel(v, lbl);
break;
}
case TK_AS: {
sqliteExprCode(pParse, pExpr->pLeft);
break;
}
}
return;
}
+7 -7
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.53 2002/01/04 03:09:30 drh Exp $
** $Id: select.c,v 1.54 2002/01/22 03:13:42 drh Exp $
*/
#include "sqliteInt.h"
@@ -698,7 +698,7 @@ int sqliteSelect(
WhereInfo *pWInfo;
Vdbe *v;
int isAgg = 0; /* True for select lists like "count(*)" */
ExprList *pEList; /* List of columns to extract. NULL means "*" */
ExprList *pEList; /* List of columns to extract. */
IdList *pTabList; /* List of tables to select from */
Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
@@ -798,7 +798,7 @@ int sqliteSelect(
** Resolve the column names and do a semantics check on all the expressions.
*/
for(i=0; i<pEList->nExpr; i++){
if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){
if( sqliteExprResolveIds(pParse, pTabList, 0, pEList->a[i].pExpr) ){
return 1;
}
if( sqliteExprCheck(pParse, pEList->a[i].pExpr, 1, &isAgg) ){
@@ -806,7 +806,7 @@ int sqliteSelect(
}
}
if( pWhere ){
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
if( sqliteExprResolveIds(pParse, pTabList, pEList, pWhere) ){
return 1;
}
if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
@@ -816,7 +816,7 @@ int sqliteSelect(
if( pOrderBy ){
for(i=0; i<pOrderBy->nExpr; i++){
Expr *pE = pOrderBy->a[i].pExpr;
if( sqliteExprResolveIds(pParse, pTabList, pE) ){
if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){
return 1;
}
if( sqliteExprCheck(pParse, pE, isAgg, 0) ){
@@ -827,7 +827,7 @@ int sqliteSelect(
if( pGroupBy ){
for(i=0; i<pGroupBy->nExpr; i++){
Expr *pE = pGroupBy->a[i].pExpr;
if( sqliteExprResolveIds(pParse, pTabList, pE) ){
if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){
return 1;
}
if( sqliteExprCheck(pParse, pE, isAgg, 0) ){
@@ -842,7 +842,7 @@ int sqliteSelect(
pParse->nErr++;
return 1;
}
if( sqliteExprResolveIds(pParse, pTabList, pHaving) ){
if( sqliteExprResolveIds(pParse, pTabList, pEList, pHaving) ){
return 1;
}
if( sqliteExprCheck(pParse, pHaving, isAgg, 0) ){
+2 -2
View File
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.77 2002/01/16 21:00:27 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.78 2002/01/22 03:13:42 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
@@ -517,7 +517,7 @@ char *sqliteTableNameFromToken(Token*);
int sqliteExprCheck(Parse*, Expr*, int, int*);
int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
int sqliteExprResolveIds(Parse*, IdList*, ExprList*, Expr*);
void sqliteExprResolveInSelect(Parse*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
void sqliteParseInfoReset(Parse*);
+3 -3
View File
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.26 2002/01/14 02:56:25 drh Exp $
** $Id: update.c,v 1.27 2002/01/22 03:13:42 drh Exp $
*/
#include "sqliteInt.h"
@@ -84,7 +84,7 @@ void sqliteUpdate(
sqliteExprResolveInSelect(pParse, pChanges->a[i].pExpr);
}
if( pWhere ){
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
goto update_cleanup;
}
if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
@@ -93,7 +93,7 @@ void sqliteUpdate(
}
chngRecno = 0;
for(i=0; i<pChanges->nExpr; i++){
if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){
if( sqliteExprResolveIds(pParse, pTabList, 0, pChanges->a[i].pExpr) ){
goto update_cleanup;
}
if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
+35 -1
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.16 2001/12/16 20:05:06 drh Exp $
# $Id: select1.test,v 1.17 2002/01/22 03:13:43 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -467,4 +467,38 @@ do_test select1-9.5 {
} {f1 f2}
unset r
# Check for ORDER BY clauses that refer to an AS name in the column list
#
do_test select1-10.1 {
execsql {
SELECT f1 AS x FROM test1 ORDER BY x
}
} {11 33}
do_test select1-10.2 {
execsql {
SELECT f1 AS x FROM test1 ORDER BY -x
}
} {33 11}
do_test select1-10.3 {
execsql {
SELECT f1-23 AS x FROM test1 ORDER BY abs(x)
}
} {10 -12}
do_test select1-10.4 {
execsql {
SELECT f1-23 AS x FROM test1 ORDER BY -abs(x)
}
} {-12 10}
do_test select1-10.5 {
execsql {
SELECT f1-22 AS x, f2-22 as y FROM test1
}
} {-11 0 11 22}
do_test select1-10.6 {
execsql {
SELECT f1-22 AS x, f2-22 as y FROM test1 WHERE x>0 AND y<50
}
} {11 22}
finish_test
+24 -1
View File
@@ -12,7 +12,7 @@
# focus of this file is testing aggregate functions and the
# GROUP BY and HAVING clauses of SELECT statements.
#
# $Id: select3.test,v 1.3 2001/09/16 00:13:28 drh Exp $
# $Id: select3.test,v 1.4 2002/01/22 03:13:43 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -69,6 +69,21 @@ do_test select3-2.4 {
do_test select3-2.5 {
execsql {SELECT log*2+1, avg(n)-min(n) FROM t1 GROUP BY log ORDER BY log}
} {1 0 3 0 5 0.5 7 1.5 9 3.5 11 7}
do_test select3-2.6 {
execsql {
SELECT log*2+1 as x, count(*) FROM t1 GROUP BY x ORDER BY x
}
} {1 1 3 1 5 2 7 4 9 8 11 15}
do_test select3-2.7 {
execsql {
SELECT log*2+1 AS x, count(*) AS y FROM t1 GROUP BY x ORDER BY y
}
} {1 1 3 1 5 2 7 4 9 8 11 15}
do_test select3-2.8 {
execsql {
SELECT log*2+1 AS x, count(*) AS y FROM t1 GROUP BY x ORDER BY 10-(x+y)
}
} {11 15 9 8 7 4 5 2 3 1 1 1}
# Cannot have a HAVING without a GROUP BY
#
@@ -98,6 +113,14 @@ do_test select3-4.3 {
ORDER BY max(n)
}
} {3 4 4 8 5 15}
do_test select3-4.4 {
execsql {
SELECT log AS x, count(*) AS y FROM t1
GROUP BY x
HAVING y>=4
ORDER BY max(n)
}
} {3 4 4 8 5 15}
do_test select3-5.1 {
execsql {
+6
View File
@@ -17,6 +17,12 @@ proc chng {date desc} {
puts "<DD><P><UL>$desc</UL></P></DD>"
}
chng {2002 Jan ?? (2.2.4)} {
<li>The label to the right of an AS in the column list of a SELECT can now
be used as part of an expression in the WHERE, ORDER BY, GROUP BY, and/or
HAVING clauses.</li>
}
chng {2002 Jan 16 (2.2.3)} {
<li>Fix warning messages in VC++ 7.0. (Patches from nicolas352001)</li>
<li>Make the library thread-safe. (The code is there and appears to work
+2 -2
View File
@@ -1,7 +1,7 @@
#
# Run this script to generated a faq.html output file
#
set rcsid {$Id: faq.tcl,v 1.6 2002/01/16 21:00:28 drh Exp $}
set rcsid {$Id: faq.tcl,v 1.7 2002/01/22 03:13:43 drh Exp $}
puts {<html>
<head>
@@ -161,7 +161,7 @@ faq {
on my SparcStation.
} {
<p>The x86 processor on your linux box is little-endian (meaning that
the least signification byte of integers comes first) but the Sparc is
the least significant byte of integers comes first) but the Sparc is
big-endian (the most significant bytes comes first). SQLite databases
created on a little-endian architecture cannot be used on a big-endian
machine and vice versa.</p>