]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix handling of window frames containing negative number of rows. e.g. "ROWS x
authordan <dan@noemail.net>
Mon, 11 Jun 2018 18:16:51 +0000 (18:16 +0000)
committerdan <dan@noemail.net>
Mon, 11 Jun 2018 18:16:51 +0000 (18:16 +0000)
PRECEDING AND y PRECEDING" where (x<y).

FossilOrigin-Name: b6d9c7eda853420ae46a05bd432711e8bf9ebaa448c7d90ccfc0bcc338a87706

manifest
manifest.uuid
src/resolve.c
src/window.c
test/window1.test
test/window4.tcl
test/window4.test

index a43cce585fff463d4585bf45ee4867dde2b7dfcb..18f389d9322cad73cb3f935b3fbfb65c28f14faf 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\stypon\sin\smain.mk.
-D 2018-06-11T11:19:35.512
+C Fix\shandling\sof\swindow\sframes\scontaining\snegative\snumber\sof\srows.\se.g.\s"ROWS\sx\nPRECEDING\sAND\sy\sPRECEDING"\swhere\s(x<y).
+D 2018-06-11T18:16:51.622
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 498b77b89a8cb42f2ee20fcd6317f279a45c0d6ff40d27825f94b69884c09bbe
@@ -493,7 +493,7 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
 F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
 F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
-F src/resolve.c da9b85ec0e1a05384134cece5747a90b8da1fc5750f4705c7812d2294ca20cec
+F src/resolve.c 03791a761ede3a2cd71dffb92aa760d728122dbbdbf26010813da3edd01cb431
 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
 F src/select.c 0b0ce29bd7b8a7232e6f7602ddb447caa954a1fc476ff5e23ce1e5aaa6a0e0ed
 F src/shell.c.in 4d0ddf10c403710d241bf920163dcf032c21119aebb61e70840942c0eafecdf9
@@ -583,7 +583,7 @@ F src/where.c fe1a6f97c12cc9472ccce86166ba3f827cf61d6ae770c036a6396b63863baac4
 F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
 F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
 F src/whereexpr.c 6f022d6cc9daf56495f191b199352f783aff5cf268ba136b4d8cea3fb62d8c7d
-F src/window.c 72c08229b59a447db5ffb8e87680105549465df502092e0e24f9451e6b082031
+F src/window.c 0519e5a03ebbcf22ab692410d4b25f28cc2d0e4e37e6288ca1eb0820276d67ba
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
 F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -1617,13 +1617,13 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
 F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
 F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
 F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
-F test/window1.test 6c648f3fa79b29ef114c4e73ae8adefae70e4d3aae4cc36a3318ab237b64e9c5
+F test/window1.test 94c626fe8d9eced3e3d5ef0a2106209904daba77d549aafde09eba1db8e98c3e
 F test/window2.tcl 0983de5eade5eeda49469244799d5331bfe3199fca3f6c6d2a836aa08f4fba1b
 F test/window2.test 79747b2edde4ad424e0752b27529aedc86e91f3d8d88846fa17ff0cb67f65086
 F test/window3.tcl 654d61d73e10db089b22514d498bb23ec310f720c0f4b5f69f67fda83d672048
 F test/window3.test 41727668ee31d2ba50f78efcb5bf1bda2c5cffd889aa65243511004669d1ac25
-F test/window4.tcl e459eb2fe561d7731008a80d071e2d995c3554706de764c9f456f54357e70316
-F test/window4.test 207ab5e54ba0fec5e1157d136489b615a0e88dc8f9fb81cd77e11f20d2ddd72e
+F test/window4.tcl bfea0c4f65dff22568032ae3a0cf3be0910c4160314e5ac3f895eca11b068cb1
+F test/window4.test ca7c63f27604a0eb432cab1673da75498c69d66b9093ef80a5d4c7287b95906b
 F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
 F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
 F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
@@ -1740,7 +1740,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 16db73842ade5eb0fe02f257b91d1c7b41d830d3f17f8638b8fbaed309d9a852
-R 96748b81a5c5c17387af91f1f0c0dfa1
+P e74f86f271d6ab1ecd17c1ee63ab2aa0885ca56624be7382872f04d46c48ed86
+R a123bfa3a94ae6460114239fab9e1170
 U dan
-Z 83b8eb197a3e3709547b1acd87361cc8
+Z 6b49a0a9a9265834682b1c9c02ee1753
index d49243596d33231dcf7e66733a00cf4914add3f6..0cd6c62cdb8b93cbae332cda30bb20b6b7b3587d 100644 (file)
@@ -1 +1 @@
-e74f86f271d6ab1ecd17c1ee63ab2aa0885ca56624be7382872f04d46c48ed86
\ No newline at end of file
+b6d9c7eda853420ae46a05bd432711e8bf9ebaa448c7d90ccfc0bcc338a87706
\ No newline at end of file
index cf0ca280eaf2d5c2a474681400a92cf756c9b032..0d946681900c3adec9ef98242f6e63f461739ae4 100644 (file)
@@ -756,11 +756,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
                    NC_IdxExpr|NC_PartIdx);
         }
       }
-      if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) 
-       || (pExpr->pWin && (pNC->ncFlags & NC_AllowWin)==0)
+
+      if( is_agg==0 && pExpr->pWin ){
+        sqlite3ErrorMsg(pParse, 
+            "%.*s() may not be used as a window function", nId, zId
+        );
+        pNC->nErr++;
+      }else if( 
+            (is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
+         || (is_agg && (pDef->funcFlags & SQLITE_FUNC_WINDOW) && !pExpr->pWin)
+         || (is_agg && pExpr->pWin && (pNC->ncFlags & NC_AllowWin)==0)
       ){
-        const char *zType = pExpr->pWin ? "window" : "aggregate";
-        sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId);
+        const char *zType;
+        if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){
+          zType = "window";
+        }else{
+          zType = "aggregate";
+        }
+        sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()", zType, nId,zId);
         pNC->nErr++;
         is_agg = 0;
       }else if( no_such_func && pParse->db->init.busy==0
index fc4c7d905ec3cb90d0571f3e2a9e89b7acb82c40..9c633621053e0fc9f2c1e19785c5f0166fe1563f 100644 (file)
@@ -1,4 +1,5 @@
 /*
+** 2018 May 08
 **
 ** The author disclaims copyright to this source code.  In place of
 ** a legal notice, here is a blessing:
@@ -1258,13 +1259,26 @@ static void windowCodeRowExprStep(
 
   /* If this is "ROWS <expr1> FOLLOWING AND ROWS <expr2> FOLLOWING", do:
   **
+  **   if( regEnd<regStart ){
+  **     // The frame always consists of 0 rows
+  **     regStart = regSize;
+  **   }
   **   regEnd = regEnd - regStart;
   */
   if( pMWin->pEnd && pMWin->pStart && pMWin->eStart==TK_FOLLOWING ){
     assert( pMWin->eEnd==TK_FOLLOWING );
+    sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd);
+    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
     sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd);
   }
 
+  if( pMWin->pEnd && pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){
+    assert( pMWin->eStart==TK_PRECEDING );
+    sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd);
+    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
+    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd);
+  }
+
   /* Initialize the accumulator register for each window function to NULL */
   regArg = windowInitAccum(pParse, pMWin);
 
@@ -1731,6 +1745,14 @@ void sqlite3WindowCodeStep(
   Window *pMWin = p->pWin;
   Window *pWin;
 
+  /*
+  ** Call windowCodeRowExprStep() for all window modes *except*:
+  **
+  **   RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+  **   RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+  **   RANGE BETWEEN CURRENT ROW AND CURRENT ROW
+  **   ROWS  BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+  */
   if( (pMWin->eType==TK_ROWS 
    && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy))
    || (pMWin->eStart==TK_CURRENT&&pMWin->eEnd==TK_UNBOUNDED&&pMWin->pOrderBy)
@@ -1739,6 +1761,11 @@ void sqlite3WindowCodeStep(
     return;
   }
 
+  /*
+  ** Call windowCodeCacheStep() if there is a window function that requires
+  ** that the entire partition be cached in a temp table before any rows
+  ** are returned.
+  */
   for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
     FuncDef *pFunc = pWin->pFunc;
     if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)
index 81541dad4eeb7cd8725173f34e2893f81ec9cb7c..18d547963c3a21240b3934748437dc057caa4f0a 100644 (file)
@@ -214,9 +214,43 @@ do_execsql_test 6.2 {
   a 1 1 a 2 2 a 3 3 a 4 4 a 5 5 a 6 6 a 7 7
 }
 
-do_catchsql_test 3.5 {
+do_catchsql_test 6.3 {
   SELECT x, lag(x) FILTER (WHERE (x%2)=0) OVER w FROM t1 
   WINDOW w AS (ORDER BY x)
 } {1 {FILTER clause may only be used with aggregate window functions}}
+#-------------------------------------------------------------------------
+# Attempt to use a window function as an aggregate. And other errors.
+#
+reset_db
+do_execsql_test 7.0 {
+  CREATE TABLE t1(x, y);
+  INSERT INTO t1 VALUES(1, 2);
+  INSERT INTO t1 VALUES(3, 4);
+  INSERT INTO t1 VALUES(5, 6);
+  INSERT INTO t1 VALUES(7, 8);
+  INSERT INTO t1 VALUES(9, 10);
+}
+
+do_catchsql_test 7.1.1 {
+  SELECT nth_value(x, 1) FROM t1;
+} {1 {misuse of window function nth_value()}}
+do_catchsql_test 7.1.2 {
+  SELECT * FROM t1 WHERE nth_value(x, 1) OVER (ORDER BY y);
+} {1 {misuse of window function nth_value()}}
+do_catchsql_test 7.1.3 {
+  SELECT count(*) FROM t1 GROUP BY y HAVING nth_value(x, 1) OVER (ORDER BY y);
+} {1 {misuse of window function nth_value()}}
+do_catchsql_test 7.1.4 {
+  SELECT count(*) FROM t1 GROUP BY nth_value(x, 1) OVER (ORDER BY y);
+} {1 {misuse of window function nth_value()}}
+do_catchsql_test 7.1.5 {
+  SELECT count(*) FROM t1 LIMIT nth_value(x, 1) OVER (ORDER BY y);
+} {1 {no such column: x}}
+do_catchsql_test 7.1.6 {
+  SELECT trim(x) OVER (ORDER BY y) FROM t1;
+} {1 {trim() may not be used as a window function}}
+
 
 finish_test
+
index 30b56ca4e8cb8bae0cc0e58be5481cc6b65cb2d4..6a85a2a2905eee74bd75978c683a7c298f8d01fc 100644 (file)
@@ -102,6 +102,32 @@ execsql_test 3.4 {
   WINDOW w AS (ORDER BY a)
 }
 
+execsql_test 3.5.1 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 2 PRECEDING)
+  FROM t5
+}
+execsql_test 3.5.2 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING)
+  FROM t5
+}
+execsql_test 3.5.3 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 0 PRECEDING AND 0 PRECEDING)
+  FROM t5
+}
+
+execsql_test 3.6.1 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 2 FOLLOWING AND 1 FOLLOWING)
+  FROM t5
+}
+execsql_test 3.6.2 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING)
+  FROM t5
+}
+execsql_test 3.6.3 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 0 FOLLOWING AND 0 FOLLOWING)
+  FROM t5
+}
+
 
 finish_test
 
index 70963800f5f1bf6783eba8cdb2b711132a7704d3..317824e4c44c93682e0f5510a462e1a26ce7cf86 100644 (file)
@@ -176,14 +176,39 @@ do_execsql_test 3.3 {
   ORDER BY a;
 } {1 1 5   2 2 4   3 3 3   4 4 2   5 5 1}
 
-explain_i {
-  SELECT a, max(a) FILTER (WHERE (a%2)=0) OVER w FROM t5 
-  WINDOW w AS (ORDER BY a)
-  }
-  breakpoint
 do_execsql_test 3.4 {
   SELECT a, max(a) FILTER (WHERE (a%2)=0) OVER w FROM t5 
   WINDOW w AS (ORDER BY a)
 } {1 {}   2 2   3 2   4 4   5 4}
 
+do_execsql_test 3.5.1 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 2 PRECEDING)
+  FROM t5
+} {1 {}   2 {}   3 {}   4 {}   5 {}}
+
+do_execsql_test 3.5.2 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING)
+  FROM t5
+} {1 {}   2 one   3 two   4 three   5 four}
+
+do_execsql_test 3.5.3 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 0 PRECEDING AND 0 PRECEDING)
+  FROM t5
+} {1 one   2 two   3 three   4 four   5 five}
+
+do_execsql_test 3.6.1 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 2 FOLLOWING AND 1 FOLLOWING)
+  FROM t5
+} {1 {}   2 {}   3 {}   4 {}   5 {}}
+
+do_execsql_test 3.6.2 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING)
+  FROM t5
+} {1 two   2 three   3 four   4 five   5 {}}
+
+do_execsql_test 3.6.3 {
+  SELECT a, max(c) OVER (ORDER BY a ROWS BETWEEN 0 FOLLOWING AND 0 FOLLOWING)
+  FROM t5
+} {1 one   2 two   3 three   4 four   5 five}
+
 finish_test