Fix for correlated subqueries where the parent is an aggregate. Ticket #1105. (CVS 2318)
FossilOrigin-Name: f0d3ca10c5bccf8fca7143028ebb3e604c0e3f20
This commit is contained in:
parent
7bec505e26
commit
a58fdfb162
22
manifest
22
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sthe\s(highly\sexperimental)\somit_readlock\spragma\sthat\sdisables\sthe\suse\r\nof\sreadlocks\son\sread-only\sdatabases\sthat\sare\sconnected\susing\sATTACH.\s(CVS\s2317)
|
||||
D 2005-02-06T02:45:42
|
||||
C Fix\sfor\scorrelated\ssubqueries\swhere\sthe\sparent\sis\san\saggregate.\sTicket\s#1105.\s(CVS\s2318)
|
||||
D 2005-02-08T07:50:41
|
||||
F Makefile.in d928187101fa3d78426cf48ca30e39d0fb714e57
|
||||
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
||||
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
|
||||
@ -35,7 +35,7 @@ F src/build.c fcb437bcda09a57b3fe898dff5ff558e7536621b
|
||||
F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f
|
||||
F src/delete.c 4b94395b52a8f7785acd71135c2ce54f3f5550b3
|
||||
F src/experimental.c 8cc66b2be6a011055d75ef19ed2584bcfbb585ad
|
||||
F src/expr.c 1b6b6b16bcb6a6dcc4a5df451d9e652f84b269ae
|
||||
F src/expr.c b9ffd249cef8cd0f2d3681da8daf9a4292dcd005
|
||||
F src/func.c f096b6771cc0aaa11790aca95773a50a8f74ba73
|
||||
F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f
|
||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||
@ -57,10 +57,10 @@ F src/parse.y ee046c1ea30425a817285e52fb1993c2f955e766
|
||||
F src/pragma.c 809b95acd9af67297a5f923a1a57d82179e0ad3a
|
||||
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
|
||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||
F src/select.c 6217e1f72cee7e173b21b252fd42a052f3b4decc
|
||||
F src/select.c 37dd84fd228db14e9006e3eafb389f08d823502f
|
||||
F src/shell.c 3cb0ef124ed9cd582ce89aec59ff7c659bc6e61b
|
||||
F src/sqlite.h.in c85f6bad9ca7de29f505fe886646cfff7df4c55e
|
||||
F src/sqliteInt.h 5fa59fd8369ec403bbdf35a9b6fbf7f60bd77cdb
|
||||
F src/sqliteInt.h 9a53c5b5c591526e22b89deed38467cb8875b121
|
||||
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
||||
F src/tclsqlite.c 101994a2c4c0eaa69f1de9bfe4a02167f6049e7d
|
||||
F src/test1.c feac8a742aca920c8ab18a43b3208ae3a834fe9d
|
||||
@ -74,7 +74,7 @@ F src/update.c b6f4668c11059f86b71581187d09197fa28ec4be
|
||||
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
|
||||
F src/util.c 1b7b9a127b66743ab6cba8d44597aeb570723c99
|
||||
F src/vacuum.c 4dbe45a5c41674a04ac45a7586031583386ab119
|
||||
F src/vdbe.c 5acf43749f44b0813d47f4b1801538f4aaa7ddbb
|
||||
F src/vdbe.c d9ec62c9f63768b4d4f8513b25aded8faf2de17b
|
||||
F src/vdbe.h bb9186484f749a839c6c43953e79a6530253f7cd
|
||||
F src/vdbeInt.h e80721cd8ff611789e20743eec43363a9fb5a48e
|
||||
F src/vdbeapi.c 467caa6e6fb9247528b1c7ab9132ae1b4748e8ac
|
||||
@ -181,7 +181,7 @@ F test/select5.test 2d414f712bff8e590091e08f9b7287600731be00
|
||||
F test/select6.test 6e5a1a70a788cdbe515d1252dd0917d7e9d1d71e
|
||||
F test/select7.test 8f3362336c10d828ab6fe9c1b8897b484da8b592
|
||||
F test/sort.test 312eade533cb3c7667110ccfa6e818db1078fd6c
|
||||
F test/subquery.test e607b55276d2536e17e75896cd245ec1c8838f1d
|
||||
F test/subquery.test 958bf1752c6b1c5c0b45b243fc74899f2037821e
|
||||
F test/subselect.test 3f3f7a940dc3195c3139f4d530385cb54665d614
|
||||
F test/table.test a2a58cae70ef2511cbf27d40fb8f570106a2677e
|
||||
F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
|
||||
@ -270,7 +270,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc
|
||||
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
|
||||
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
||||
F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd
|
||||
P 515e5033a5482f55e7edb66d69ff3da7e234ff2e
|
||||
R 46e8e0ae6e4ce5a599c5b024b5c2e241
|
||||
U drh
|
||||
Z dd83c9ab3e3ce7d0c16a2d058d1f0afb
|
||||
P 2155448d2128119f74241da0ea07d6713b71765c
|
||||
R 606c27806bb193ef40535820164d7cb2
|
||||
U danielk1977
|
||||
Z ab8a5b2917edd9042037cd2b7cc41ebd
|
||||
|
@ -1 +1 @@
|
||||
2155448d2128119f74241da0ea07d6713b71765c
|
||||
f0d3ca10c5bccf8fca7143028ebb3e604c0e3f20
|
131
src/expr.c
131
src/expr.c
@ -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.192 2005/02/05 12:48:48 danielk1977 Exp $
|
||||
** $Id: expr.c,v 1.193 2005/02/08 07:50:41 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -189,6 +189,7 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
|
||||
pNew->op = op;
|
||||
pNew->pLeft = pLeft;
|
||||
pNew->pRight = pRight;
|
||||
pNew->iAgg = -1;
|
||||
if( pToken ){
|
||||
assert( pToken->dyn==0 );
|
||||
pNew->span = pNew->token = *pToken;
|
||||
@ -589,26 +590,47 @@ void sqlite3ExprListDelete(ExprList *pList){
|
||||
** The return value from this routine is 1 to abandon the tree walk
|
||||
** and 0 to continue.
|
||||
*/
|
||||
static int walkExprList(ExprList *, int (*)(void *, Expr*), void *);
|
||||
static int walkExprTree(Expr *pExpr, int (*xFunc)(void*,Expr*), void *pArg){
|
||||
ExprList *pList;
|
||||
int rc;
|
||||
if( pExpr==0 ) return 0;
|
||||
rc = (*xFunc)(pArg, pExpr);
|
||||
if( rc==0 ){
|
||||
if( walkExprTree(pExpr->pLeft, xFunc, pArg) ) return 1;
|
||||
if( walkExprTree(pExpr->pRight, xFunc, pArg) ) return 1;
|
||||
pList = pExpr->pList;
|
||||
if( pList ){
|
||||
int i;
|
||||
struct ExprList_item *pItem;
|
||||
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
|
||||
if( walkExprTree(pItem->pExpr, xFunc, pArg) ) return 1;
|
||||
}
|
||||
}
|
||||
if( walkExprList(pExpr->pList, xFunc, pArg) ) return 1;
|
||||
}
|
||||
return rc>1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Call walkExprTree() for every expression in list p.
|
||||
*/
|
||||
static int walkExprList(ExprList *p, int (*xFunc)(void *, Expr*), void *pArg){
|
||||
int i;
|
||||
struct ExprList_item *pItem;
|
||||
if( !p ) return 0;
|
||||
for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){
|
||||
if( walkExprTree(pItem->pExpr, xFunc, pArg) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Call walkExprTree() for every expression in Select p, not including
|
||||
** expressions that are part of sub-selects in any FROM clause or the LIMIT
|
||||
** or OFFSET expressions..
|
||||
*/
|
||||
static int walkSelectExpr(Select *p, int (*xFunc)(void *, Expr*), void *pArg){
|
||||
walkExprList(p->pEList, xFunc, pArg);
|
||||
walkExprTree(p->pWhere, xFunc, pArg);
|
||||
walkExprList(p->pGroupBy, xFunc, pArg);
|
||||
walkExprTree(p->pHaving, xFunc, pArg);
|
||||
walkExprList(p->pOrderBy, xFunc, pArg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine is designed as an xFunc for walkExprTree().
|
||||
**
|
||||
@ -1356,8 +1378,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
op = pExpr->op;
|
||||
switch( op ){
|
||||
case TK_COLUMN: {
|
||||
if( pParse->useAgg ){
|
||||
sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
|
||||
if( !pParse->fillAgg && pExpr->iAgg>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg);
|
||||
}else if( pExpr->iColumn>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
|
||||
#ifndef NDEBUG
|
||||
@ -1968,49 +1990,64 @@ static int appendAggInfo(Parse *pParse){
|
||||
static int analyzeAggregate(void *pArg, Expr *pExpr){
|
||||
int i;
|
||||
AggExpr *aAgg;
|
||||
Parse *pParse = (Parse*)pArg;
|
||||
NameContext *pNC = (NameContext *)pArg;
|
||||
Parse *pParse = pNC->pParse;
|
||||
SrcList *pSrcList = pNC->pSrcList;
|
||||
|
||||
switch( pExpr->op ){
|
||||
case TK_COLUMN: {
|
||||
aAgg = pParse->aAgg;
|
||||
for(i=0; i<pParse->nAgg; i++){
|
||||
if( aAgg[i].isAgg ) continue;
|
||||
if( aAgg[i].pExpr->iTable==pExpr->iTable
|
||||
&& aAgg[i].pExpr->iColumn==pExpr->iColumn ){
|
||||
break;
|
||||
for(i=0; pSrcList && i<pSrcList->nSrc; i++){
|
||||
if( pExpr->iTable==pSrcList->a[i].iCursor ){
|
||||
aAgg = pParse->aAgg;
|
||||
for(i=0; i<pParse->nAgg; i++){
|
||||
if( aAgg[i].isAgg ) continue;
|
||||
if( aAgg[i].pExpr->iTable==pExpr->iTable
|
||||
&& aAgg[i].pExpr->iColumn==pExpr->iColumn ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=pParse->nAgg ){
|
||||
i = appendAggInfo(pParse);
|
||||
if( i<0 ) return 1;
|
||||
pParse->aAgg[i].isAgg = 0;
|
||||
pParse->aAgg[i].pExpr = pExpr;
|
||||
}
|
||||
pExpr->iAgg = i;
|
||||
pExpr->iAggCtx = pNC->nDepth;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( i>=pParse->nAgg ){
|
||||
i = appendAggInfo(pParse);
|
||||
if( i<0 ) return 1;
|
||||
pParse->aAgg[i].isAgg = 0;
|
||||
pParse->aAgg[i].pExpr = pExpr;
|
||||
}
|
||||
pExpr->iAgg = i;
|
||||
return 1;
|
||||
}
|
||||
case TK_AGG_FUNCTION: {
|
||||
aAgg = pParse->aAgg;
|
||||
for(i=0; i<pParse->nAgg; i++){
|
||||
if( !aAgg[i].isAgg ) continue;
|
||||
if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){
|
||||
break;
|
||||
if( pNC->nDepth==0 ){
|
||||
aAgg = pParse->aAgg;
|
||||
for(i=0; i<pParse->nAgg; i++){
|
||||
if( !aAgg[i].isAgg ) continue;
|
||||
if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=pParse->nAgg ){
|
||||
u8 enc = pParse->db->enc;
|
||||
i = appendAggInfo(pParse);
|
||||
if( i<0 ) return 1;
|
||||
pParse->aAgg[i].isAgg = 1;
|
||||
pParse->aAgg[i].pExpr = pExpr;
|
||||
pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
|
||||
pExpr->token.z, pExpr->token.n,
|
||||
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
||||
}
|
||||
pExpr->iAgg = i;
|
||||
return 1;
|
||||
}
|
||||
if( i>=pParse->nAgg ){
|
||||
u8 enc = pParse->db->enc;
|
||||
i = appendAggInfo(pParse);
|
||||
if( i<0 ) return 1;
|
||||
pParse->aAgg[i].isAgg = 1;
|
||||
pParse->aAgg[i].pExpr = pExpr;
|
||||
pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
|
||||
pExpr->token.z, pExpr->token.n,
|
||||
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
||||
}
|
||||
pExpr->iAgg = i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( pExpr->pSelect ){
|
||||
pNC->nDepth++;
|
||||
walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC);
|
||||
pNC->nDepth--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2025,10 +2062,10 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
|
||||
** If errors are seen, leave an error message in zErrMsg and return
|
||||
** the number of errors.
|
||||
*/
|
||||
int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
|
||||
int nErr = pParse->nErr;
|
||||
walkExprTree(pExpr, analyzeAggregate, pParse);
|
||||
return pParse->nErr - nErr;
|
||||
int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
|
||||
int nErr = pNC->pParse->nErr;
|
||||
walkExprTree(pExpr, analyzeAggregate, pNC);
|
||||
return pNC->pParse->nErr - nErr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
41
src/select.c
41
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.239 2005/02/05 12:48:48 danielk1977 Exp $
|
||||
** $Id: select.c,v 1.240 2005/02/08 07:50:41 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -1241,6 +1241,7 @@ static int matchOrderbyToColumn(
|
||||
pE->op = TK_COLUMN;
|
||||
pE->iColumn = iCol;
|
||||
pE->iTable = iTable;
|
||||
pE->iAgg = -1;
|
||||
pOrderBy->a[i].done = 1;
|
||||
}
|
||||
if( iCol<0 && mustComplete ){
|
||||
@ -2095,6 +2096,9 @@ static int flattenSubquery(
|
||||
*/
|
||||
p->isDistinct = p->isDistinct || pSub->isDistinct;
|
||||
|
||||
/*
|
||||
** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
|
||||
*/
|
||||
if( pSub->pLimit ){
|
||||
p->pLimit = pSub->pLimit;
|
||||
pSub->pLimit = 0;
|
||||
@ -2412,7 +2416,6 @@ int sqlite3SelectResolve(
|
||||
** saveAggregateInfo() and restoreAggregateInfo().
|
||||
*/
|
||||
struct AggregateInfo {
|
||||
u8 useAgg;
|
||||
int nAgg;
|
||||
AggExpr *aAgg;
|
||||
};
|
||||
@ -2426,10 +2429,8 @@ typedef struct AggregateInfo AggregateInfo;
|
||||
static void saveAggregateInfo(Parse *pParse, AggregateInfo *pInfo){
|
||||
pInfo->aAgg = pParse->aAgg;
|
||||
pInfo->nAgg = pParse->nAgg;
|
||||
pInfo->useAgg = pParse->useAgg;
|
||||
pParse->aAgg = 0;
|
||||
pParse->nAgg = 0;
|
||||
pParse->useAgg = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2441,7 +2442,6 @@ static void restoreAggregateInfo(Parse *pParse, AggregateInfo *pInfo){
|
||||
sqliteFree(pParse->aAgg);
|
||||
pParse->aAgg = pInfo->aAgg;
|
||||
pParse->nAgg = pInfo->nAgg;
|
||||
pParse->useAgg = pInfo->useAgg;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2674,26 +2674,31 @@ int sqlite3Select(
|
||||
/* Do an analysis of aggregate expressions.
|
||||
*/
|
||||
if( isAgg || pGroupBy ){
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
|
||||
assert( pParse->nAgg==0 );
|
||||
isAgg = 1;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
if( sqlite3ExprAnalyzeAggregates(pParse, pEList->a[i].pExpr) ){
|
||||
if( sqlite3ExprAnalyzeAggregates(&sNC, pEList->a[i].pExpr) ){
|
||||
goto select_end;
|
||||
}
|
||||
}
|
||||
if( pGroupBy ){
|
||||
for(i=0; i<pGroupBy->nExpr; i++){
|
||||
if( sqlite3ExprAnalyzeAggregates(pParse, pGroupBy->a[i].pExpr) ){
|
||||
if( sqlite3ExprAnalyzeAggregates(&sNC, pGroupBy->a[i].pExpr) ){
|
||||
goto select_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pHaving && sqlite3ExprAnalyzeAggregates(pParse, pHaving) ){
|
||||
if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){
|
||||
goto select_end;
|
||||
}
|
||||
if( pOrderBy ){
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
if( sqlite3ExprAnalyzeAggregates(pParse, pOrderBy->a[i].pExpr) ){
|
||||
if( sqlite3ExprAnalyzeAggregates(&sNC, pOrderBy->a[i].pExpr) ){
|
||||
goto select_end;
|
||||
}
|
||||
}
|
||||
@ -2765,8 +2770,9 @@ int sqlite3Select(
|
||||
*/
|
||||
else{
|
||||
AggExpr *pAgg;
|
||||
int lbl1 = 0;
|
||||
pParse->fillAgg = 1;
|
||||
if( pGroupBy ){
|
||||
int lbl1;
|
||||
for(i=0; i<pGroupBy->nExpr; i++){
|
||||
sqlite3ExprCode(pParse, pGroupBy->a[i].pExpr);
|
||||
}
|
||||
@ -2775,11 +2781,14 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pGroupBy->nExpr, 0);
|
||||
lbl1 = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp(v, OP_AggFocus, 0, lbl1);
|
||||
for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
|
||||
if( pAgg->isAgg ) continue;
|
||||
sqlite3ExprCode(pParse, pAgg->pExpr);
|
||||
sqlite3VdbeAddOp(v, OP_AggSet, 0, i);
|
||||
}
|
||||
}
|
||||
for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
|
||||
if( pAgg->isAgg ) continue;
|
||||
sqlite3ExprCode(pParse, pAgg->pExpr);
|
||||
sqlite3VdbeAddOp(v, OP_AggSet, 0, i);
|
||||
}
|
||||
pParse->fillAgg = 0;
|
||||
if( lbl1<0 ){
|
||||
sqlite3VdbeResolveLabel(v, lbl1);
|
||||
}
|
||||
for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
|
||||
@ -2819,7 +2828,6 @@ int sqlite3Select(
|
||||
int endagg = sqlite3VdbeMakeLabel(v);
|
||||
int startagg;
|
||||
startagg = sqlite3VdbeAddOp(v, OP_AggNext, 0, endagg);
|
||||
pParse->useAgg = 1;
|
||||
if( pHaving ){
|
||||
sqlite3ExprIfFalse(pParse, pHaving, startagg, 1);
|
||||
}
|
||||
@ -2830,7 +2838,6 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, startagg);
|
||||
sqlite3VdbeResolveLabel(v, endagg);
|
||||
sqlite3VdbeAddOp(v, OP_Noop, 0, 0);
|
||||
pParse->useAgg = 0;
|
||||
}
|
||||
|
||||
/* If there is an ORDER BY clause, then we need to sort the results
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.368 2005/02/06 02:45:43 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.369 2005/02/08 07:50:42 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@ -812,8 +812,9 @@ struct Expr {
|
||||
Token span; /* Complete text of the expression */
|
||||
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
|
||||
** iColumn-th field of the iTable-th table. */
|
||||
int iAgg; /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
|
||||
int iAgg; /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull
|
||||
** result from the iAgg-th element of the aggregator */
|
||||
int iAggCtx; /* The value to pass as P1 of OP_AggGet. */
|
||||
Select *pSelect; /* When the expression is a sub-select. Also the
|
||||
** right side of "<expr> IN (<select>)" */
|
||||
};
|
||||
@ -1091,8 +1092,7 @@ struct Parse {
|
||||
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
|
||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||
u32 writeMask; /* Start a write transaction on these databases */
|
||||
u8 useAgg; /* If true, extract field values from the aggregator
|
||||
** while generating expressions. Normally false */
|
||||
u8 fillAgg; /* If true, ignore the Expr.iAgg field. Normally false */
|
||||
|
||||
/* Above is constant between recursions. Below is reset before and after
|
||||
** each recursion */
|
||||
@ -1410,7 +1410,7 @@ int sqlite3ExprCheck(Parse*, Expr*, int, int*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*);
|
||||
int sqliteFuncId(Token*);
|
||||
int sqlite3ExprResolveNames(NameContext *, Expr *);
|
||||
int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
|
||||
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
Vdbe *sqlite3GetVdbe(Parse*);
|
||||
void sqlite3Randomness(int, void*);
|
||||
void sqlite3RollbackAll(sqlite3*);
|
||||
|
24
src/vdbe.c
24
src/vdbe.c
@ -43,7 +43,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.453 2005/02/05 12:48:48 danielk1977 Exp $
|
||||
** $Id: vdbe.c,v 1.454 2005/02/08 07:50:42 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -4395,31 +4395,39 @@ case OP_AggSet: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: AggGet * P2 *
|
||||
/* Opcode: AggGet P1 P2 *
|
||||
**
|
||||
** Push a new entry onto the stack which is a copy of the P2-th field
|
||||
** of the current aggregate. Strings are not duplicated so
|
||||
** string values will be ephemeral.
|
||||
**
|
||||
** If P1 is zero, then the value is pulled out of the current aggregate
|
||||
** in the current aggregate context. If P1 is greater than zero, then
|
||||
** the value is taken from the P1th outer aggregate context. (i.e. if
|
||||
** P1==1 then read from the aggregate context that will be restored
|
||||
** by the next OP_AggContextPop opcode).
|
||||
*/
|
||||
case OP_AggGet: {
|
||||
AggElem *pFocus;
|
||||
int i = pOp->p2;
|
||||
pFocus = p->pAgg->pCurrent;
|
||||
Agg *pAgg = &p->pAgg[-pOp->p1];
|
||||
assert( pAgg>=p->apAgg );
|
||||
pFocus = pAgg->pCurrent;
|
||||
if( pFocus==0 ){
|
||||
int res;
|
||||
if( sqlite3_malloc_failed ) goto no_mem;
|
||||
rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
|
||||
rc = sqlite3BtreeFirst(pAgg->pCsr, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
if( res!=0 ){
|
||||
rc = AggInsert(p->pAgg, "", 1);
|
||||
pFocus = p->pAgg->pCurrent;
|
||||
rc = AggInsert(pAgg, "", 1);
|
||||
pFocus = pAgg->pCurrent;
|
||||
}else{
|
||||
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, 4, (char *)&pFocus);
|
||||
rc = sqlite3BtreeData(pAgg->pCsr, 0, 4, (char *)&pFocus);
|
||||
}
|
||||
}
|
||||
assert( i>=0 && i<p->pAgg->nMem );
|
||||
assert( i>=0 && i<pAgg->nMem );
|
||||
pTos++;
|
||||
sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
|
||||
if( pTos->flags&MEM_Str ){
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing correlated subqueries
|
||||
#
|
||||
# $Id: subquery.test,v 1.4 2005/01/30 11:11:44 danielk1977 Exp $
|
||||
# $Id: subquery.test,v 1.5 2005/02/08 07:50:42 danielk1977 Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -216,6 +216,36 @@ do_test subquery-3.2 {
|
||||
}
|
||||
} {1}
|
||||
|
||||
# Test Cases subquery-3.3.* test correlated subqueries where the
|
||||
# parent query is an aggregate query. Ticket #1105 is an example
|
||||
# of such a query.
|
||||
#
|
||||
do_test subquery-3.3.1 {
|
||||
execsql {
|
||||
SELECT a, (SELECT b) FROM t1 GROUP BY a;
|
||||
}
|
||||
} {1 2}
|
||||
do_test subquery-3.3.2 {
|
||||
catchsql {DROP TABLE t2}
|
||||
execsql {
|
||||
CREATE TABLE t2(c, d);
|
||||
INSERT INTO t2 VALUES(1, 'one');
|
||||
INSERT INTO t2 VALUES(2, 'two');
|
||||
SELECT a, (SELECT d FROM t2 WHERE a=c) FROM t1 GROUP BY a;
|
||||
}
|
||||
} {1 one}
|
||||
do_test subquery-3.3.3 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(2, 4);
|
||||
SELECT max(a), (SELECT d FROM t2 WHERE a=c) FROM t1;
|
||||
}
|
||||
} {2 two}
|
||||
do_test subquery-3.3.3 {
|
||||
execsql {
|
||||
SELECT a, (SELECT (SELECT d FROM t2 WHERE a=c)) FROM t1 GROUP BY a;
|
||||
}
|
||||
} {1 one 2 two}
|
||||
|
||||
#------------------------------------------------------------------
|
||||
# These tests - subquery-4.* - use the TCL statement cache to try
|
||||
# and expose bugs to do with re-using statements that have been
|
||||
|
Loading…
x
Reference in New Issue
Block a user