-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.
-D 2014-09-15T11:14:50.871
+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-15T14:46:02.082
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/expr.c 19392d98e089640c3336e65b4254cc337efef7d1
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
-F src/func.c d4d218704b13bc1814b7d76874e405743c903773
+F src/func.c 5d498933f6168dff80941c873805fe04dc2b766d
F src/global.c 5110fa12e09729b84eee0191c984ec4008e21937
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196
F src/printf.c e74925089a85e3c9f0e315595f41c139d3d118c2
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
-F src/resolve.c 0d1621e45fffe4b4396477cf46e41a84b0145ffb
+F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
-F src/select.c 70312b18bf56f741556ed494c398afa0ca3c0e1a
+F src/select.c 0cd6706fd52ae5db229e9041094db6ec27195335
F src/shell.c c00220cdd7f2027780bc25b78376c16dc24e4b7d
F src/sqlite.h.in 8b018219ce988913e5977d5de9ab4beb33be23b6
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
-F src/sqliteInt.h e9030816d5ee6fe2063553b40359096f994664ee
+F src/sqliteInt.h 0803e900eb1882f7dd88e86ddcddd2d1b27c8d86
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 218ae2ba022881846741dfc8351aefdf129e0377
F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
-F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
+F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2
F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
-F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef
+F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f
F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P b332a84d5154f70f3197537df4af243eaebbb011
-R 4fde0e674c64eada90bf3beabe45d5b4
+P 4ff0eb96bc364baed2d8005c69291ca9240b99dd
+R d83c0c27bf862a8b9f30cb2ccec5fde3
U drh
-Z 7e796116236157f7f97effb3ae76fb8a
+Z 5049f8c8dea35bd8f91ea699f6fd9960
-4ff0eb96bc364baed2d8005c69291ca9240b99dd
\ No newline at end of file
+0bdf1a086b3946722f4d4b328e25917f61c14713
\ No newline at end of file
FUNCTION(trim, 2, 3, 0, trimFunc ),
FUNCTION(min, -1, 0, 1, minmaxFunc ),
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, 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(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
- /* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */
- {0,SQLITE_UTF8|SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
+ AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
+ SQLITE_FUNC_COUNT ),
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938;
}
}
- }
#ifndef SQLITE_OMIT_AUTHORIZATION
- if( pDef ){
auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
if( auth!=SQLITE_OK ){
if( auth==SQLITE_DENY ){
pExpr->op = TK_NULL;
return WRC_Prune;
}
+#endif
if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant);
}
-#endif
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++;
pExpr->op2++;
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;
}
/* FIX ME: Compute pExpr->affinity based on the expected return
assert( (p->selFlags & SF_Aggregate)==0 );
pGroupBy = p->pGroupBy;
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{
sNC.ncFlags &= ~NC_AllowAgg;
}
NameContext *pNC, /* Namespace to resolve expressions in. */
Expr *pExpr /* The expression to be analyzed. */
){
- u8 savedHasAgg;
+ u16 savedHasAgg;
Walker w;
if( pExpr==0 ) return 0;
pParse->nHeight += pExpr->nHeight;
}
#endif
- savedHasAgg = pNC->ncFlags & NC_HasAgg;
- pNC->ncFlags &= ~NC_HasAgg;
+ savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
+ pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
}
if( pNC->ncFlags & NC_HasAgg ){
ExprSetProperty(pExpr, EP_Agg);
- }else if( savedHasAgg ){
- pNC->ncFlags |= NC_HasAgg;
}
+ pNC->ncFlags |= savedHasAgg;
return ExprHasProperty(pExpr, EP_Error);
}
** parent to a compound query confuses the code that handles
** 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.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
return 0; /* Restriction (21) */
}
- if( pSub->selFlags & SF_Recursive ) return 0; /* Restriction (22) */
- if( (p->selFlags & SF_Recursive) && pSub->pPrior ) return 0; /* (23) */
+ testcase( pSub->selFlags & SF_Recursive );
+ 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:
** Restriction 3: If the subquery is a join, make sure the subquery is
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
#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
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
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
NameContext *pNext; /* Next outer name context. NULL for outermost */
int nRef; /* Number of names resolved by this context */
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.
+**
+** 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_HasAgg 0x02 /* One or more aggregate functions seen */
-#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
-#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
-#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */
+#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */
+#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */
+#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
+#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
+#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
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
#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 */
/* 0x0100 NOT USED */
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
#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() */
/*
(SELECT value1 as xyz, max(x1) AS pqr
FROM t1
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 {
db eval {
DROP TABLE IF EXISTS t1;
do_test minmax4-1.6 {
db eval {
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 {
db eval {
INSERT INTO t1 VALUES(5,0);
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 {
db eval {
SELECT p, min(q) FROM t1;
db eval {
INSERT INTO t1 VALUES(6,1);
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 {
db eval {
SELECT p, min(q) FROM t1;