Fix a problem with window functions min() and max() when used with a FILTER clause. Forum post [forum:/forumpost/e9126d554a | e9126d554a].

FossilOrigin-Name: d15fb0f75e64bbfdb8df0c0d0358aafbbd7d5e2048df676dafe1abd5e9917f2a
This commit is contained in:
dan 2024-11-14 14:38:16 +00:00
parent f154cef8f2
commit c87d7bede0
6 changed files with 210 additions and 25 deletions

View File

@ -1,5 +1,5 @@
C Document\sthe\sif\sblock\sat\sthe\send\sof\ssqlite-check-tcl. C Fix\sa\sproblem\swith\swindow\sfunctions\smin()\sand\smax()\swhen\sused\swith\sa\sFILTER\sclause.\sForum\spost\s[forum:/forumpost/e9126d554a\s|\se9126d554a].
D 2024-11-14T12:23:05.149 D 2024-11-14T14:38:16.785
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
@ -863,7 +863,7 @@ F src/where.c 4de9e7ca5f49e4a21c1d733e2b2fbbc8b62b1a157a58a562c569da84cfcb005b
F src/whereInt.h 1e36ec50392f7cc3d93d1152d4338064cd522b87156a0739388b7e273735f0ca F src/whereInt.h 1e36ec50392f7cc3d93d1152d4338064cd522b87156a0739388b7e273735f0ca
F src/wherecode.c 81b9af89f4f85c8097d0da6a31499f015eabc4d3584963d30ba7b7b782e26514 F src/wherecode.c 81b9af89f4f85c8097d0da6a31499f015eabc4d3584963d30ba7b7b782e26514
F src/whereexpr.c 0f93a29cabd3a338d09a1f5c6770620a1ac51ec1157f3229502a7e7767c60b6f F src/whereexpr.c 0f93a29cabd3a338d09a1f5c6770620a1ac51ec1157f3229502a7e7767c60b6f
F src/window.c 499d48f315a09242dc68f2fac635ed27dcf6bbb0d9ab9084857898c64489e975 F src/window.c 6c386af5972a58f9a9847bba9d7ca70c4c682391ab8478d94a6e046b22a0dbb3
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9 F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
@ -2067,9 +2067,9 @@ F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652
F test/window6.test 311de885bd7e453134fa6747680bfb4a1be87c91720bf58703db945891e7d30b F test/window6.test 311de885bd7e453134fa6747680bfb4a1be87c91720bf58703db945891e7d30b
F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f
F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd
F test/window8.tcl 5e02e41d9d9a80f597063aed1a381eb19d1d0ef677a4f0df352c5365cf23f79c F test/window8.tcl c57364e64d816f6e26df60437e1202e2c1031c7b818a1a67535d1006862a026a
F test/window8.test 4ab16817414af0c904abe2ebdf88eb6c2b00058b84f9748c6174ff11fc45f1ed F test/window8.test 3d931e58802b8ab8063da00f0cf30aa3351640238a952c0efb5a129e2349a4bb
F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836 F test/window9.test 7b98a7916dd87763ea35f56ea023e3b29e99744582204ccf2937a3bac411cd4d
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
F test/windowB.test aad7c31739999f68a98a813cfd78390918fc70f56d2d925317a1523cab548ecf F test/windowB.test aad7c31739999f68a98a813cfd78390918fc70f56d2d925317a1523cab548ecf
F test/windowC.test 6fd75f5bb2f1343d34e470e36e68f0ff638d8a42f6aa7d99471261b31a0d42f2 F test/windowC.test 6fd75f5bb2f1343d34e470e36e68f0ff638d8a42f6aa7d99471261b31a0d42f2
@ -2199,8 +2199,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 6940caa192fa0cc84dbd24191a940aec96c304c68e60ead8f239e85d093e01e0 P 6bfd09408b9a51c0cbdb28f901a79c9774da755294d7eb67d88e4c42c5652830
R a630c6439d1fbf64015d5e1115d0f02b R 4dbd1e8b72bd923323c250178cad8662
U stephan U dan
Z 28b305c9589a667cd87e3823cca8351c Z 283ba5d1ed32af60aeb437d70b951d46
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
6bfd09408b9a51c0cbdb28f901a79c9774da755294d7eb67d88e4c42c5652830 d15fb0f75e64bbfdb8df0c0d0358aafbbd7d5e2048df676dafe1abd5e9917f2a

View File

@ -1670,6 +1670,7 @@ static void windowAggStep(
int regArg; int regArg;
int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin); int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
int i; int i;
int addrIf = 0;
assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED ); assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
@ -1686,6 +1687,18 @@ static void windowAggStep(
} }
regArg = reg; regArg = reg;
if( pWin->pFilter ){
int regTmp;
assert( ExprUseXList(pWin->pOwner) );
assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
regTmp = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, regTmp);
}
if( pMWin->regStartRowid==0 if( pMWin->regStartRowid==0
&& (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
&& (pWin->eStart!=TK_UNBOUNDED) && (pWin->eStart!=TK_UNBOUNDED)
@ -1705,25 +1718,13 @@ static void windowAggStep(
} }
sqlite3VdbeJumpHere(v, addrIsNull); sqlite3VdbeJumpHere(v, addrIsNull);
}else if( pWin->regApp ){ }else if( pWin->regApp ){
assert( pWin->pFilter==0 );
assert( pFunc->zName==nth_valueName assert( pFunc->zName==nth_valueName
|| pFunc->zName==first_valueName || pFunc->zName==first_valueName
); );
assert( bInverse==0 || bInverse==1 ); assert( bInverse==0 || bInverse==1 );
sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
}else if( pFunc->xSFunc!=noopStepFunc ){ }else if( pFunc->xSFunc!=noopStepFunc ){
int addrIf = 0;
if( pWin->pFilter ){
int regTmp;
assert( ExprUseXList(pWin->pOwner) );
assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
regTmp = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, regTmp);
}
if( pWin->bExprArgs ){ if( pWin->bExprArgs ){
int iOp = sqlite3VdbeCurrentAddr(v); int iOp = sqlite3VdbeCurrentAddr(v);
int iEnd; int iEnd;
@ -1754,8 +1755,9 @@ static void windowAggStep(
if( pWin->bExprArgs ){ if( pWin->bExprArgs ){
sqlite3ReleaseTempRange(pParse, regArg, nArg); sqlite3ReleaseTempRange(pParse, regArg, nArg);
} }
if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
} }
if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
} }
} }

View File

@ -489,6 +489,68 @@ execsql_test 9.2 {
FROM t1 FROM t1
} }
==========
execsql_test 10.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER, b INTEGER);
INSERT INTO t1 VALUES (10, 1),
(20, -1),
(5, 2),
(15, 0),
(25, 3);
}
execsql_test 10.1 {
SELECT
a, b, MIN(a) FILTER(WHERE b > 0) OVER win
FROM t1
WINDOW win AS (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
}
execsql_test 10.2 {
SELECT
a, b, MIN(a) FILTER(WHERE b > 0) OVER win
FROM t1
WINDOW win AS ();
}
execsql_test 10.3 {
SELECT
a, b, MIN(a) FILTER(WHERE b > 0) OVER win
FROM t1
WINDOW win AS (ORDER BY a);
}
execsql_test 10.4 {
SELECT
a, b, MIN(a) OVER win
FROM t1
WINDOW win AS (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
}
==========
execsql_test 11.0 {
DROP TABLE IF EXISTS t2;
CREATE TABLE t2(a INTEGER, b INTEGER);
INSERT INTO t2 VALUES(1, 12);
INSERT INTO t2 VALUES(2, 10);
INSERT INTO t2 VALUES(3, 15);
INSERT INTO t2 VALUES(4, 22);
INSERT INTO t2 VALUES(5, 1);
INSERT INTO t2 VALUES(6, 4);
INSERT INTO t2 VALUES(7, 7);
INSERT INTO t2 VALUES(8, 6);
INSERT INTO t2 VALUES(9, 22);
INSERT INTO t2 VALUES(10, 2);
}
execsql_test 11.1 {
SELECT a, min(b) FILTER (WHERE a%2 != 0) OVER win
FROM t2
WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING);
}
finish_test finish_test

View File

@ -6540,4 +6540,67 @@ do_execsql_test 9.2 {
FROM t1 FROM t1
} {} } {}
#==========================================================================
do_execsql_test 10.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER, b INTEGER);
INSERT INTO t1 VALUES (10, 1),
(20, -1),
(5, 2),
(15, 0),
(25, 3);
} {}
do_execsql_test 10.1 {
SELECT
a, b, MIN(a) FILTER(WHERE b > 0) OVER win
FROM t1
WINDOW win AS (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
} {5 2 5 10 1 5 15 0 10 20 -1 25 25 3 25}
do_execsql_test 10.2 {
SELECT
a, b, MIN(a) FILTER(WHERE b > 0) OVER win
FROM t1
WINDOW win AS ();
} {10 1 5 20 -1 5 5 2 5 15 0 5 25 3 5}
do_execsql_test 10.3 {
SELECT
a, b, MIN(a) FILTER(WHERE b > 0) OVER win
FROM t1
WINDOW win AS (ORDER BY a);
} {5 2 5 10 1 5 15 0 5 20 -1 5 25 3 5}
do_execsql_test 10.4 {
SELECT
a, b, MIN(a) OVER win
FROM t1
WINDOW win AS (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
} {5 2 5 10 1 5 15 0 10 20 -1 15 25 3 20}
#==========================================================================
do_execsql_test 11.0 {
DROP TABLE IF EXISTS t2;
CREATE TABLE t2(a INTEGER, b INTEGER);
INSERT INTO t2 VALUES(1, 12);
INSERT INTO t2 VALUES(2, 10);
INSERT INTO t2 VALUES(3, 15);
INSERT INTO t2 VALUES(4, 22);
INSERT INTO t2 VALUES(5, 1);
INSERT INTO t2 VALUES(6, 4);
INSERT INTO t2 VALUES(7, 7);
INSERT INTO t2 VALUES(8, 6);
INSERT INTO t2 VALUES(9, 22);
INSERT INTO t2 VALUES(10, 2);
} {}
do_execsql_test 11.1 {
SELECT a, min(b) FILTER (WHERE a%2 != 0) OVER win
FROM t2
WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING);
} {1 12 2 12 3 1 4 1 5 1 6 1 7 1 8 7 9 7 10 22}
finish_test finish_test

View File

@ -282,4 +282,62 @@ do_catchsql_test 9.1 {
FROM t1 FROM t1
} {1 {frame ending offset must be a non-negative number}} } {1 {frame ending offset must be a non-negative number}}
#--------------------------------------------------------------------------
reset_db
do_execsql_test 10.0 {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 'a');
INSERT INTO t1 VALUES(2, 'b');
INSERT INTO t1 VALUES(3, 'c');
INSERT INTO t1 VALUES(4, 'd');
INSERT INTO t1 VALUES(5, 'e');
INSERT INTO t1 VALUES(6, 'f');
}
do_execsql_test 10.1 {
SELECT a, min(b) OVER win
FROM t1
WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING)
} {
1 a
2 a
3 a
4 b
5 c
6 d
}
do_execsql_test 10.2 {
SELECT a, min(b) FILTER (WHERE a%2) OVER win
FROM t1
WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING)
} {
1 a
2 a
3 a
4 c
5 c
6 e
}
do_execsql_test 10.3 {
SELECT a, min(b) FILTER (WHERE (a%2)=0) OVER win
FROM t1
WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING)
} {
1 b
2 b
3 b
4 b
5 d
6 d
}
do_catchsql_test 10.4 {
SELECT a, nth_value(b, 1) FILTER (WHERE (a%2)=0) OVER win
FROM t1
WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING)
} {1 {FILTER clause may only be used with aggregate window functions}}
finish_test finish_test