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:
34
src/select.c
34
src/select.c
@@ -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 ){
|
||||
|
||||
Reference in New Issue
Block a user