Improved handling of aggregate subqueries within an aggregate query.
FossilOrigin-Name: 430bb59d798286a86c351de92c429345f016b3f0
This commit is contained in:
parent
d8621b90c9
commit
374fdce485
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
||||
C Add\san\sundocumented\sand\spossibly\sephemeral\s".breakpoint"\scommand\sto\sthe\s\ncommand-line\sshell,\sto\scall\sa\sno-op\sroutine\son\swhich\sit\sis\sconvenient\sto\s\nset\sa\ssymbolic\sdebugger\sbreakpoint.
|
||||
D 2012-04-17T09:09:33.765
|
||||
C Improved\shandling\sof\saggregate\ssubqueries\swithin\san\saggregate\squery.
|
||||
D 2012-04-17T16:38:53.916
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -135,7 +135,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 4c20ea4f6213b3bc1c6a510586864b679946e05e
|
||||
F src/expr.c ebb0e2b21379d4ec0c5c2c7c952784cb300c8436
|
||||
F src/expr.c 1b2383adc4391ddae38abb71fd4690a3af8efb01
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
|
||||
F src/func.c c6b3c94320253a35bda43fb69cc292618e3285d6
|
||||
@ -185,7 +185,7 @@ F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335
|
||||
F src/shell.c 11185a9a4574f363bd4268a2780d37480ae00040
|
||||
F src/sqlite.h.in 4338f299fc83dada8407358d585c0e240ecb76a3
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h ce7d8404f15db6cbe73cf196d3d6198aaa4e3924
|
||||
F src/sqliteInt.h c5e917c4f1453f3972b1fd0c81105dfe4f09cc32
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@ -713,7 +713,7 @@ F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 08e8185b3fd5b010c90d7ad82b9dd4ea1cbf14b0
|
||||
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
|
||||
F test/subquery.test c5e0d183f1ae6251453338a465b32ae11326e0fa
|
||||
F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
@ -1000,7 +1000,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
P 020b5e90f950a42299074ff770612b9e68850d95
|
||||
R b1350dfbc2eb46aaca5347bd8a799d07
|
||||
P 8e2363ad76446e863d03ead91fd621e59d5cb495
|
||||
R f4f12ce6163c2f6bb1a71deb9cb7039c
|
||||
U drh
|
||||
Z ed107cd283f4ba98c58e464c44f875e3
|
||||
Z 58b2a5ebe7a572f77bef677b95126ab0
|
||||
|
@ -1 +1 @@
|
||||
8e2363ad76446e863d03ead91fd621e59d5cb495
|
||||
430bb59d798286a86c351de92c429345f016b3f0
|
52
src/expr.c
52
src/expr.c
@ -3778,7 +3778,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
|
||||
return 2;
|
||||
}
|
||||
}else if( pA->op!=TK_COLUMN && pA->u.zToken ){
|
||||
}else if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
|
||||
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
|
||||
if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
|
||||
return 2;
|
||||
@ -3815,6 +3815,41 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the expression callback for sqlite3FunctionUsesOtherSrc().
|
||||
**
|
||||
** Determine if an expression references any table other than one of the
|
||||
** tables in pWalker->u.pSrcList and abort if it does.
|
||||
*/
|
||||
static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
|
||||
int i;
|
||||
SrcList *pSrc = pWalker->u.pSrcList;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
if( pExpr->iTable==pSrc->a[i].iCursor ) return WRC_Continue;
|
||||
}
|
||||
return WRC_Abort;
|
||||
}else{
|
||||
return WRC_Continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Determine if any of the arguments to the pExpr Function references
|
||||
** any SrcList other than pSrcList. Return true if they do. Return
|
||||
** false if pExpr has no argument or has only constant arguments or
|
||||
** only references tables named in pSrcList.
|
||||
*/
|
||||
static int sqlite3FunctionUsesOtherSrc(Expr *pExpr, SrcList *pSrcList){
|
||||
Walker w;
|
||||
assert( pExpr->op==TK_AGG_FUNCTION );
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = exprUsesOtherSrc;
|
||||
w.u.pSrcList = pSrcList;
|
||||
if( sqlite3WalkExprList(&w, pExpr->x.pList)!=WRC_Continue ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new element to the pAggInfo->aCol[] array. Return the index of
|
||||
** the new element. Return a negative number if malloc fails.
|
||||
@ -3930,9 +3965,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Prune;
|
||||
}
|
||||
case TK_AGG_FUNCTION: {
|
||||
/* The pNC->nDepth==0 test causes aggregate functions in subqueries
|
||||
** to be ignored */
|
||||
if( pNC->nDepth==0 ){
|
||||
if( !sqlite3FunctionUsesOtherSrc(pExpr, pSrcList) ){
|
||||
/* Check to see if pExpr is a duplicate of another aggregate
|
||||
** function that is already in the pAggInfo structure
|
||||
*/
|
||||
@ -3976,15 +4009,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Continue;
|
||||
}
|
||||
static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
|
||||
NameContext *pNC = pWalker->u.pNC;
|
||||
if( pNC->nDepth==0 ){
|
||||
pNC->nDepth++;
|
||||
sqlite3WalkSelect(pWalker, pSelect);
|
||||
pNC->nDepth--;
|
||||
return WRC_Prune;
|
||||
}else{
|
||||
return WRC_Continue;
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3997,6 +4022,7 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
|
||||
*/
|
||||
void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
|
||||
Walker w;
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = analyzeAggregate;
|
||||
w.xSelectCallback = analyzeAggregatesInSelect;
|
||||
w.u.pNC = pNC;
|
||||
|
@ -2011,7 +2011,6 @@ struct NameContext {
|
||||
u8 allowAgg; /* Aggregate functions allowed here */
|
||||
u8 hasAgg; /* True if aggregates are seen */
|
||||
u8 isCheck; /* True if resolving names in a CHECK constraint */
|
||||
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
|
||||
AggInfo *pAggInfo; /* Information about aggregates at this level */
|
||||
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
||||
};
|
||||
@ -2477,6 +2476,7 @@ struct Walker {
|
||||
union { /* Extra data for callback */
|
||||
NameContext *pNC; /* Naming context */
|
||||
int i; /* Integer value */
|
||||
SrcList *pSrcList; /* FROM clause */
|
||||
} u;
|
||||
};
|
||||
|
||||
|
@ -331,6 +331,53 @@ do_test subquery-3.3.5 {
|
||||
}
|
||||
} {1 1 2 1}
|
||||
|
||||
# The following tests check for aggregate subqueries in an aggregate
|
||||
# query.
|
||||
#
|
||||
do_test subquery-3.4.1 {
|
||||
execsql {
|
||||
CREATE TABLE t34(x,y);
|
||||
INSERT INTO t34 VALUES(106,4), (107,3), (106,5), (107,5);
|
||||
SELECT a.x, avg(a.y)
|
||||
FROM t34 AS a
|
||||
GROUP BY a.x
|
||||
HAVING NOT EXISTS( SELECT b.x, avg(b.y)
|
||||
FROM t34 AS b
|
||||
GROUP BY b.x
|
||||
HAVING avg(a.y) > avg(b.y));
|
||||
}
|
||||
} {107 4.0}
|
||||
do_test subquery-3.4.2 {
|
||||
execsql {
|
||||
SELECT a.x, avg(a.y) AS avg1
|
||||
FROM t34 AS a
|
||||
GROUP BY a.x
|
||||
HAVING NOT EXISTS( SELECT b.x, avg(b.y) AS avg2
|
||||
FROM t34 AS b
|
||||
GROUP BY b.x
|
||||
HAVING avg1 > avg2);
|
||||
}
|
||||
} {107 4.0}
|
||||
do_test subquery-3.4.3 {
|
||||
execsql {
|
||||
SELECT
|
||||
a.x,
|
||||
avg(a.y),
|
||||
NOT EXISTS ( SELECT b.x, avg(b.y)
|
||||
FROM t34 AS b
|
||||
GROUP BY b.x
|
||||
HAVING avg(a.y) > avg(b.y)),
|
||||
EXISTS ( SELECT c.x, avg(c.y)
|
||||
FROM t34 AS c
|
||||
GROUP BY c.x
|
||||
HAVING avg(a.y) > avg(c.y))
|
||||
FROM t34 AS a
|
||||
GROUP BY a.x
|
||||
ORDER BY a.x;
|
||||
}
|
||||
} {106 4.5 0 1 107 4.0 1 0}
|
||||
|
||||
|
||||
#------------------------------------------------------------------
|
||||
# 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