]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a problem with window functions min() and max() when used with a FILTER clause...
authordan <Dan Kennedy>
Thu, 14 Nov 2024 14:38:16 +0000 (14:38 +0000)
committerdan <Dan Kennedy>
Thu, 14 Nov 2024 14:38:16 +0000 (14:38 +0000)
FossilOrigin-Name: d15fb0f75e64bbfdb8df0c0d0358aafbbd7d5e2048df676dafe1abd5e9917f2a

manifest
manifest.uuid
src/window.c
test/window8.tcl
test/window8.test
test/window9.test

index f4236a85e5408a487bd2b316f605ea26d82e0983..01eec35bff0da40b69312b1023b6d3a11795c187 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Document\sthe\sif\sblock\sat\sthe\send\sof\ssqlite-check-tcl.
-D 2024-11-14T12:23:05.149
+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-14T14:38:16.785
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
@@ -863,7 +863,7 @@ F src/where.c 4de9e7ca5f49e4a21c1d733e2b2fbbc8b62b1a157a58a562c569da84cfcb005b
 F src/whereInt.h 1e36ec50392f7cc3d93d1152d4338064cd522b87156a0739388b7e273735f0ca
 F src/wherecode.c 81b9af89f4f85c8097d0da6a31499f015eabc4d3584963d30ba7b7b782e26514
 F src/whereexpr.c 0f93a29cabd3a338d09a1f5c6770620a1ac51ec1157f3229502a7e7767c60b6f
-F src/window.c 499d48f315a09242dc68f2fac635ed27dcf6bbb0d9ab9084857898c64489e975
+F src/window.c 6c386af5972a58f9a9847bba9d7ca70c4c682391ab8478d94a6e046b22a0dbb3
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
 F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
@@ -2067,9 +2067,9 @@ F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652
 F test/window6.test 311de885bd7e453134fa6747680bfb4a1be87c91720bf58703db945891e7d30b
 F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f
 F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd
-F test/window8.tcl 5e02e41d9d9a80f597063aed1a381eb19d1d0ef677a4f0df352c5365cf23f79c
-F test/window8.test 4ab16817414af0c904abe2ebdf88eb6c2b00058b84f9748c6174ff11fc45f1ed
-F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836
+F test/window8.tcl c57364e64d816f6e26df60437e1202e2c1031c7b818a1a67535d1006862a026a
+F test/window8.test 3d931e58802b8ab8063da00f0cf30aa3351640238a952c0efb5a129e2349a4bb
+F test/window9.test 7b98a7916dd87763ea35f56ea023e3b29e99744582204ccf2937a3bac411cd4d
 F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
 F test/windowB.test aad7c31739999f68a98a813cfd78390918fc70f56d2d925317a1523cab548ecf
 F test/windowC.test 6fd75f5bb2f1343d34e470e36e68f0ff638d8a42f6aa7d99471261b31a0d42f2
@@ -2199,8 +2199,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 6940caa192fa0cc84dbd24191a940aec96c304c68e60ead8f239e85d093e01e0
-R a630c6439d1fbf64015d5e1115d0f02b
-U stephan
-Z 28b305c9589a667cd87e3823cca8351c
+P 6bfd09408b9a51c0cbdb28f901a79c9774da755294d7eb67d88e4c42c5652830
+R 4dbd1e8b72bd923323c250178cad8662
+U dan
+Z 283ba5d1ed32af60aeb437d70b951d46
 # Remove this line to create a well-formed Fossil manifest.
index 258ecf84b09ff061bd247ff1fac31b5349f2afba..a40565627e7784288b21bad742a8a0898fd7be10 100644 (file)
@@ -1 +1 @@
-6bfd09408b9a51c0cbdb28f901a79c9774da755294d7eb67d88e4c42c5652830
+d15fb0f75e64bbfdb8df0c0d0358aafbbd7d5e2048df676dafe1abd5e9917f2a
index d4083beeb3edb495a605e97c1eebe419e84874ea..acc6ea85460f13e6514baac2eb359e40f9cca6b4 100644 (file)
@@ -1670,6 +1670,7 @@ static void windowAggStep(
     int regArg;
     int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
     int i;
+    int addrIf = 0;
 
     assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
 
@@ -1686,6 +1687,18 @@ static void windowAggStep(
     }
     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
      && (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
      && (pWin->eStart!=TK_UNBOUNDED)
@@ -1705,25 +1718,13 @@ static void windowAggStep(
       }
       sqlite3VdbeJumpHere(v, addrIsNull);
     }else if( pWin->regApp ){
+      assert( pWin->pFilter==0 );
       assert( pFunc->zName==nth_valueName
            || pFunc->zName==first_valueName
       );
       assert( bInverse==0 || bInverse==1 );
       sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
     }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 ){
         int iOp = sqlite3VdbeCurrentAddr(v);
         int iEnd;
@@ -1754,8 +1755,9 @@ static void windowAggStep(
       if( pWin->bExprArgs ){
         sqlite3ReleaseTempRange(pParse, regArg, nArg);
       }
-      if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
     }
+
+    if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
   }
 }
 
index 69ad0ad263f3e037cec3470d1bdaabe02d9e8227..fcb18249ae5f885b9fd63b9d493fc9becfac73ae 100644 (file)
@@ -489,6 +489,68 @@ execsql_test 9.2 {
   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
 
index 0c5d39badb951188daf59df867382b2224ea030d..b1b28f1c2f6f19ec16c8be1cd66f2e77c75c2103 100644 (file)
@@ -6540,4 +6540,67 @@ do_execsql_test 9.2 {
   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
index 4b8e4fa58ff7886305efd6c3bba43ccdf896c79f..0548624f8274c29c3a975ecbe7369680a12eac3d 100644 (file)
@@ -282,4 +282,62 @@ do_catchsql_test 9.1 {
   FROM t1
 } {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