1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-12-09 10:21:35 +03:00

Do not flatten aggregate subqueries that contain min() or max() functions

so that if the min()/max() are discarded by the outer query, they still
function and cause non-aggregate expression to be evaluated on the minimal
or maximal row.

FossilOrigin-Name: 0bdf1a086b3946722f4d4b328e25917f61c14713
This commit is contained in:
drh
2014-09-15 14:46:02 +00:00
parent 6092d2bcfe
commit 9588ad95c1
8 changed files with 75 additions and 40 deletions

View File

@@ -1,5 +1,5 @@
C Adjust\scomments\sto\sshow\sthat\ssubquery\sflattening\srestriction\s(10)\swas\nremoved\sfrom\sthe\scode\sback\sin\s2005.\s\sThis\sis\sa\scomment\schange\sonly. C Do\snot\sflatten\saggregate\ssubqueries\sthat\scontain\smin()\sor\smax()\sfunctions\nso\sthat\sif\sthe\smin()/max()\sare\sdiscarded\sby\sthe\souter\squery,\sthey\sstill\nfunction\sand\scause\snon-aggregate\sexpression\sto\sbe\sevaluated\son\sthe\sminimal\nor\smaximal\srow.
D 2014-09-15T11:14:50.871 D 2014-09-15T14:46:02.082
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -183,7 +183,7 @@ F src/delete.c fae81cc2eb14b75267d4f47d3cfc9ae02aae726f
F src/expr.c 19392d98e089640c3336e65b4254cc337efef7d1 F src/expr.c 19392d98e089640c3336e65b4254cc337efef7d1
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7 F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
F src/func.c d4d218704b13bc1814b7d76874e405743c903773 F src/func.c 5d498933f6168dff80941c873805fe04dc2b766d
F src/global.c 5110fa12e09729b84eee0191c984ec4008e21937 F src/global.c 5110fa12e09729b84eee0191c984ec4008e21937
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
@@ -224,14 +224,14 @@ F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f
F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196 F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196
F src/printf.c e74925089a85e3c9f0e315595f41c139d3d118c2 F src/printf.c e74925089a85e3c9f0e315595f41c139d3d118c2
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 0d1621e45fffe4b4396477cf46e41a84b0145ffb F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c 70312b18bf56f741556ed494c398afa0ca3c0e1a F src/select.c 0cd6706fd52ae5db229e9041094db6ec27195335
F src/shell.c c00220cdd7f2027780bc25b78376c16dc24e4b7d F src/shell.c c00220cdd7f2027780bc25b78376c16dc24e4b7d
F src/sqlite.h.in 8b018219ce988913e5977d5de9ab4beb33be23b6 F src/sqlite.h.in 8b018219ce988913e5977d5de9ab4beb33be23b6
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
F src/sqliteInt.h e9030816d5ee6fe2063553b40359096f994664ee F src/sqliteInt.h 0803e900eb1882f7dd88e86ddcddd2d1b27c8d86
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 218ae2ba022881846741dfc8351aefdf129e0377 F src/table.c 218ae2ba022881846741dfc8351aefdf129e0377
@@ -305,7 +305,7 @@ F src/where.c 839b5e1db2507e221ad1c308f148a8519ed750be
F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783 F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2 F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2
@@ -712,7 +712,7 @@ F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9
F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f
F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417 F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
@@ -1197,7 +1197,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P b332a84d5154f70f3197537df4af243eaebbb011 P 4ff0eb96bc364baed2d8005c69291ca9240b99dd
R 4fde0e674c64eada90bf3beabe45d5b4 R d83c0c27bf862a8b9f30cb2ccec5fde3
U drh U drh
Z 7e796116236157f7f97effb3ae76fb8a Z 5049f8c8dea35bd8f91ea699f6fd9960

View File

@@ -1 +1 @@
4ff0eb96bc364baed2d8005c69291ca9240b99dd 0bdf1a086b3946722f4d4b328e25917f61c14713

View File

@@ -1663,10 +1663,12 @@ void sqlite3RegisterGlobalFunctions(void){
FUNCTION(trim, 2, 3, 0, trimFunc ), FUNCTION(trim, 2, 3, 0, trimFunc ),
FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, -1, 0, 1, minmaxFunc ),
FUNCTION(min, 0, 0, 1, 0 ), FUNCTION(min, 0, 0, 1, 0 ),
AGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize ), AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize,
SQLITE_FUNC_MINMAX ),
FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ), FUNCTION(max, 0, 1, 1, 0 ),
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ), AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize,
SQLITE_FUNC_MINMAX ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(instr, 2, 0, 0, instrFunc ),
@@ -1719,8 +1721,8 @@ void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
/* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */ AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
{0,SQLITE_UTF8|SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0}, SQLITE_FUNC_COUNT ),
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),

View File

@@ -719,9 +719,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938; pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938;
} }
} }
}
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
if( pDef ){
auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0); auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
if( auth!=SQLITE_OK ){ if( auth!=SQLITE_OK ){
if( auth==SQLITE_DENY ){ if( auth==SQLITE_DENY ){
@@ -732,9 +730,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pExpr->op = TK_NULL; pExpr->op = TK_NULL;
return WRC_Prune; return WRC_Prune;
} }
#endif
if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant); if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant);
} }
#endif
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++; pNC->nErr++;
@@ -757,7 +755,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pExpr->op2++; pExpr->op2++;
pNC2 = pNC2->pNext; pNC2 = pNC2->pNext;
} }
if( pNC2 ) pNC2->ncFlags |= NC_HasAgg; assert( pDef!=0 );
if( pNC2 ){
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
}
pNC->ncFlags |= NC_AllowAgg; pNC->ncFlags |= NC_AllowAgg;
} }
/* FIX ME: Compute pExpr->affinity based on the expected return /* FIX ME: Compute pExpr->affinity based on the expected return
@@ -1222,7 +1226,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
assert( (p->selFlags & SF_Aggregate)==0 ); assert( (p->selFlags & SF_Aggregate)==0 );
pGroupBy = p->pGroupBy; pGroupBy = p->pGroupBy;
if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){
p->selFlags |= SF_Aggregate; assert( NC_MinMaxAgg==SF_MinMaxAgg );
p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg);
}else{ }else{
sNC.ncFlags &= ~NC_AllowAgg; sNC.ncFlags &= ~NC_AllowAgg;
} }
@@ -1350,7 +1355,7 @@ int sqlite3ResolveExprNames(
NameContext *pNC, /* Namespace to resolve expressions in. */ NameContext *pNC, /* Namespace to resolve expressions in. */
Expr *pExpr /* The expression to be analyzed. */ Expr *pExpr /* The expression to be analyzed. */
){ ){
u8 savedHasAgg; u16 savedHasAgg;
Walker w; Walker w;
if( pExpr==0 ) return 0; if( pExpr==0 ) return 0;
@@ -1363,8 +1368,8 @@ int sqlite3ResolveExprNames(
pParse->nHeight += pExpr->nHeight; pParse->nHeight += pExpr->nHeight;
} }
#endif #endif
savedHasAgg = pNC->ncFlags & NC_HasAgg; savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
pNC->ncFlags &= ~NC_HasAgg; pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
memset(&w, 0, sizeof(w)); memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep; w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep; w.xSelectCallback = resolveSelectStep;
@@ -1379,9 +1384,8 @@ int sqlite3ResolveExprNames(
} }
if( pNC->ncFlags & NC_HasAgg ){ if( pNC->ncFlags & NC_HasAgg ){
ExprSetProperty(pExpr, EP_Agg); ExprSetProperty(pExpr, EP_Agg);
}else if( savedHasAgg ){
pNC->ncFlags |= NC_HasAgg;
} }
pNC->ncFlags |= savedHasAgg;
return ExprHasProperty(pExpr, EP_Error); return ExprHasProperty(pExpr, EP_Error);
} }

View File

@@ -3197,6 +3197,11 @@ static void substSelect(
** parent to a compound query confuses the code that handles ** parent to a compound query confuses the code that handles
** recursive queries in multiSelect(). ** recursive queries in multiSelect().
** **
** (24) The subquery is not an aggregate that uses the built-in min() or
** or max() functions. (Without this restriction, a query like:
** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
** return the value X for which Y was maximal.)
**
** **
** In this routine, the "p" parameter is a pointer to the outer query. ** In this routine, the "p" parameter is a pointer to the outer query.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
@@ -3269,8 +3274,14 @@ static int flattenSubquery(
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){ if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
return 0; /* Restriction (21) */ return 0; /* Restriction (21) */
} }
if( pSub->selFlags & SF_Recursive ) return 0; /* Restriction (22) */ testcase( pSub->selFlags & SF_Recursive );
if( (p->selFlags & SF_Recursive) && pSub->pPrior ) return 0; /* (23) */ testcase( pSub->selFlags & SF_MinMaxAgg );
if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
return 0; /* Restrictions (22) and (24) */
}
if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
return 0; /* Restriction (23) */
}
/* OBSOLETE COMMENT 1: /* OBSOLETE COMMENT 1:
** Restriction 3: If the subquery is a join, make sure the subquery is ** Restriction 3: If the subquery is a join, make sure the subquery is

View File

@@ -1285,6 +1285,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */ #define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */ #define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */ #define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
/* /*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -1332,6 +1333,9 @@ struct FuncDestructor {
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
/* /*
** All current savepoints are stored in a linked list starting at ** All current savepoints are stored in a linked list starting at
@@ -2254,17 +2258,22 @@ struct NameContext {
NameContext *pNext; /* Next outer name context. NULL for outermost */ NameContext *pNext; /* Next outer name context. NULL for outermost */
int nRef; /* Number of names resolved by this context */ int nRef; /* Number of names resolved by this context */
int nErr; /* Number of errors encountered while resolving names */ int nErr; /* Number of errors encountered while resolving names */
u8 ncFlags; /* Zero or more NC_* flags defined below */ u16 ncFlags; /* Zero or more NC_* flags defined below */
}; };
/* /*
** Allowed values for the NameContext, ncFlags field. ** Allowed values for the NameContext, ncFlags field.
**
** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and
** SQLITE_FUNC_MINMAX.
**
*/ */
#define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */ #define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */
#define NC_HasAgg 0x02 /* One or more aggregate functions seen */ #define NC_HasAgg 0x0002 /* One or more aggregate functions seen */
#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */ #define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */ #define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */ #define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */
#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */
/* /*
** An instance of the following structure contains all information ** An instance of the following structure contains all information
@@ -2315,13 +2324,13 @@ struct Select {
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
/* 0x0040 NOT USED */ #define SF_Compound 0x0040 /* Part of a compound query */
#define SF_Values 0x0080 /* Synthesized from VALUES clause */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */
/* 0x0100 NOT USED */ /* 0x0100 NOT USED */
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
#define SF_Compound 0x1000 /* Part of a compound query */ #define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
/* /*

View File

@@ -156,8 +156,14 @@ do_test aggnested-3.2 {
(SELECT value1 as xyz, max(x1) AS pqr (SELECT value1 as xyz, max(x1) AS pqr
FROM t1 FROM t1
GROUP BY id1); GROUP BY id1);
SELECT
(SELECT sum(value2<>xyz) FROM t2)
FROM
(SELECT value1 as xyz, max(x1) AS pqr
FROM t1
GROUP BY id1);
} }
} {0} } {1 0}
do_test aggnested-3.3 { do_test aggnested-3.3 {
db eval { db eval {
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;

View File

@@ -56,14 +56,16 @@ do_test minmax4-1.5 {
do_test minmax4-1.6 { do_test minmax4-1.6 {
db eval { db eval {
SELECT p, min(q) FROM t1; SELECT p, min(q) FROM t1;
SELECT p FROM (SELECT p, min(q) FROM t1);
} }
} {1 2} } {1 2 1}
do_test minmax4-1.7 { do_test minmax4-1.7 {
db eval { db eval {
INSERT INTO t1 VALUES(5,0); INSERT INTO t1 VALUES(5,0);
SELECT p, max(q) FROM t1; SELECT p, max(q) FROM t1;
SELECT p FROM (SELECT max(q), p FROM t1);
} }
} {3 4} } {3 4 3}
do_test minmax4-1.8 { do_test minmax4-1.8 {
db eval { db eval {
SELECT p, min(q) FROM t1; SELECT p, min(q) FROM t1;
@@ -73,8 +75,9 @@ do_test minmax4-1.9 {
db eval { db eval {
INSERT INTO t1 VALUES(6,1); INSERT INTO t1 VALUES(6,1);
SELECT p, max(q) FROM t1; SELECT p, max(q) FROM t1;
SELECT p FROM (SELECT max(q), p FROM t1);
} }
} {3 4} } {3 4 3}
do_test minmax4-1.10 { do_test minmax4-1.10 {
db eval { db eval {
SELECT p, min(q) FROM t1; SELECT p, min(q) FROM t1;