1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +03:00

Fix a problem with queries containing a min() or max() function for which the FILTER clause excludes all rows.

FossilOrigin-Name: b1d7e104e034655fe41bc55c562d91e8074a2973d538b8b29301458db45afc57
This commit is contained in:
dan
2019-09-20 20:52:16 +00:00
parent 14e3e22773
commit ed09dddece
4 changed files with 70 additions and 13 deletions

View File

@@ -5343,6 +5343,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
int i;
int regHit = 0;
int addrHitTest = 0;
int bFilterMinMax = 0;
struct AggInfo_func *pF;
struct AggInfo_col *pC;
@@ -5356,6 +5357,17 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
assert( !IsWindowFunc(pF->pExpr) );
if( ExprHasProperty(pF->pExpr, EP_WinFunc) ){
Expr *pFilter = pF->pExpr->y.pWin->pFilter;
if( pAggInfo->nAccumulator
&& (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
){
bFilterMinMax = 1;
if( regHit==0 ) regHit = ++pParse->nMem;
/* If this is the first row of the group (regAcc==0), clear the
** "magnet" register regHit so that the accumulator registers
** are populated even if the FILTER clause causes control to
** skip over the invocation of min() or max() altogether */
sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit);
}
addrNext = sqlite3VdbeMakeLabel(pParse);
sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL);
}
@@ -5406,6 +5418,13 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
if( bFilterMinMax ){
/* If there is a min() or max() with a FILTER clause, then ensure that
** the "magnet" register is set to indicate "do not attract" after
** loading column values into the accumulator registers */
sqlite3VdbeAddOp2(v, OP_Integer, 1, regHit);
}
pAggInfo->directMode = 0;
if( addrHitTest ){
sqlite3VdbeJumpHere(v, addrHitTest);
@@ -6581,13 +6600,18 @@ int sqlite3Select(
{
int regAcc = 0; /* "populate accumulators" flag */
/* If there are accumulator registers but no min() or max() functions,
** allocate register regAcc. Register regAcc will contain 0 the first
** time the inner loop runs, and 1 thereafter. The code generated
** by updateAccumulator() only updates the accumulator registers if
** regAcc contains 0. */
/* If there are accumulator registers but no min() or max() functions
** without FILTER clauses, allocate register regAcc. Register regAcc
** will contain 0 the first time the inner loop runs, and 1 thereafter.
** The code generated by updateAccumulator() uses this to ensure
** that the accumulator registers are (a) updated only once if
** there are no min() or max functions or (b) always updated for the
** first row visited by the aggregate, so that they are updated at
** least once even if the FILTER clause means the min() or max()
** function visits zero rows. */
if( sAggInfo.nAccumulator ){
for(i=0; i<sAggInfo.nFunc; i++){
if( ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_WinFunc) ) continue;
if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
}
if( i==sAggInfo.nFunc ){