Fix handling of window frames containing negative number of rows. e.g. "ROWS x

PRECEDING AND y PRECEDING" where (x<y).

FossilOrigin-Name: b6d9c7eda853420ae46a05bd432711e8bf9ebaa448c7d90ccfc0bcc338a87706
This commit is contained in:
dan 2018-06-11 18:16:51 +00:00
parent 72a9f0233b
commit 26522d1c45
7 changed files with 146 additions and 21 deletions

View File

@ -1,5 +1,5 @@
C Fix\sa\stypon\sin\smain.mk. 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-11T11:19:35.512 D 2018-06-11T18:16:51.622
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 Makefile.in 498b77b89a8cb42f2ee20fcd6317f279a45c0d6ff40d27825f94b69884c09bbe F Makefile.in 498b77b89a8cb42f2ee20fcd6317f279a45c0d6ff40d27825f94b69884c09bbe
@ -493,7 +493,7 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0 F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365 F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c da9b85ec0e1a05384134cece5747a90b8da1fc5750f4705c7812d2294ca20cec F src/resolve.c 03791a761ede3a2cd71dffb92aa760d728122dbbdbf26010813da3edd01cb431
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 0b0ce29bd7b8a7232e6f7602ddb447caa954a1fc476ff5e23ce1e5aaa6a0e0ed F src/select.c 0b0ce29bd7b8a7232e6f7602ddb447caa954a1fc476ff5e23ce1e5aaa6a0e0ed
F src/shell.c.in 4d0ddf10c403710d241bf920163dcf032c21119aebb61e70840942c0eafecdf9 F src/shell.c.in 4d0ddf10c403710d241bf920163dcf032c21119aebb61e70840942c0eafecdf9
@ -583,7 +583,7 @@ F src/where.c fe1a6f97c12cc9472ccce86166ba3f827cf61d6ae770c036a6396b63863baac4
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4 F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96 F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
F src/whereexpr.c 6f022d6cc9daf56495f191b199352f783aff5cf268ba136b4d8cea3fb62d8c7d F src/whereexpr.c 6f022d6cc9daf56495f191b199352f783aff5cf268ba136b4d8cea3fb62d8c7d
F src/window.c 72c08229b59a447db5ffb8e87680105549465df502092e0e24f9451e6b082031 F src/window.c 0519e5a03ebbcf22ab692410d4b25f28cc2d0e4e37e6288ca1eb0820276d67ba
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@ -1617,13 +1617,13 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
F test/window1.test 6c648f3fa79b29ef114c4e73ae8adefae70e4d3aae4cc36a3318ab237b64e9c5 F test/window1.test 94c626fe8d9eced3e3d5ef0a2106209904daba77d549aafde09eba1db8e98c3e
F test/window2.tcl 0983de5eade5eeda49469244799d5331bfe3199fca3f6c6d2a836aa08f4fba1b F test/window2.tcl 0983de5eade5eeda49469244799d5331bfe3199fca3f6c6d2a836aa08f4fba1b
F test/window2.test 79747b2edde4ad424e0752b27529aedc86e91f3d8d88846fa17ff0cb67f65086 F test/window2.test 79747b2edde4ad424e0752b27529aedc86e91f3d8d88846fa17ff0cb67f65086
F test/window3.tcl 654d61d73e10db089b22514d498bb23ec310f720c0f4b5f69f67fda83d672048 F test/window3.tcl 654d61d73e10db089b22514d498bb23ec310f720c0f4b5f69f67fda83d672048
F test/window3.test 41727668ee31d2ba50f78efcb5bf1bda2c5cffd889aa65243511004669d1ac25 F test/window3.test 41727668ee31d2ba50f78efcb5bf1bda2c5cffd889aa65243511004669d1ac25
F test/window4.tcl e459eb2fe561d7731008a80d071e2d995c3554706de764c9f456f54357e70316 F test/window4.tcl bfea0c4f65dff22568032ae3a0cf3be0910c4160314e5ac3f895eca11b068cb1
F test/window4.test 207ab5e54ba0fec5e1157d136489b615a0e88dc8f9fb81cd77e11f20d2ddd72e F test/window4.test ca7c63f27604a0eb432cab1673da75498c69d66b9093ef80a5d4c7287b95906b
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96 F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
@ -1740,7 +1740,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 16db73842ade5eb0fe02f257b91d1c7b41d830d3f17f8638b8fbaed309d9a852 P e74f86f271d6ab1ecd17c1ee63ab2aa0885ca56624be7382872f04d46c48ed86
R 96748b81a5c5c17387af91f1f0c0dfa1 R a123bfa3a94ae6460114239fab9e1170
U dan U dan
Z 83b8eb197a3e3709547b1acd87361cc8 Z 6b49a0a9a9265834682b1c9c02ee1753

View File

@ -1 +1 @@
e74f86f271d6ab1ecd17c1ee63ab2aa0885ca56624be7382872f04d46c48ed86 b6d9c7eda853420ae46a05bd432711e8bf9ebaa448c7d90ccfc0bcc338a87706

View File

@ -756,11 +756,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
NC_IdxExpr|NC_PartIdx); 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"; const char *zType;
sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId); 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++; pNC->nErr++;
is_agg = 0; is_agg = 0;
}else if( no_such_func && pParse->db->init.busy==0 }else if( no_such_func && pParse->db->init.busy==0

View File

@ -1,4 +1,5 @@
/* /*
** 2018 May 08
** **
** The author disclaims copyright to this source code. In place of ** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing: ** 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 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; ** regEnd = regEnd - regStart;
*/ */
if( pMWin->pEnd && pMWin->pStart && pMWin->eStart==TK_FOLLOWING ){ if( pMWin->pEnd && pMWin->pStart && pMWin->eStart==TK_FOLLOWING ){
assert( pMWin->eEnd==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); 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 */ /* Initialize the accumulator register for each window function to NULL */
regArg = windowInitAccum(pParse, pMWin); regArg = windowInitAccum(pParse, pMWin);
@ -1731,6 +1745,14 @@ void sqlite3WindowCodeStep(
Window *pMWin = p->pWin; Window *pMWin = p->pWin;
Window *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 if( (pMWin->eType==TK_ROWS
&& (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy)) && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy))
|| (pMWin->eStart==TK_CURRENT&&pMWin->eEnd==TK_UNBOUNDED&&pMWin->pOrderBy) || (pMWin->eStart==TK_CURRENT&&pMWin->eEnd==TK_UNBOUNDED&&pMWin->pOrderBy)
@ -1739,6 +1761,11 @@ void sqlite3WindowCodeStep(
return; 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){ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
FuncDef *pFunc = pWin->pFunc; FuncDef *pFunc = pWin->pFunc;
if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE) if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)

View 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 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 SELECT x, lag(x) FILTER (WHERE (x%2)=0) OVER w FROM t1
WINDOW w AS (ORDER BY x) WINDOW w AS (ORDER BY x)
} {1 {FILTER clause may only be used with aggregate window functions}} } {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 finish_test

View File

@ -102,6 +102,32 @@ execsql_test 3.4 {
WINDOW w AS (ORDER BY a) 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 finish_test

View File

@ -176,14 +176,39 @@ do_execsql_test 3.3 {
ORDER BY a; ORDER BY a;
} {1 1 5 2 2 4 3 3 3 4 4 2 5 5 1} } {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 { do_execsql_test 3.4 {
SELECT a, max(a) FILTER (WHERE (a%2)=0) OVER w FROM t5 SELECT a, max(a) FILTER (WHERE (a%2)=0) OVER w FROM t5
WINDOW w AS (ORDER BY a) WINDOW w AS (ORDER BY a)
} {1 {} 2 2 3 2 4 4 5 4} } {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 finish_test