mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-24 22:22:08 +03:00
Add further tests for new window function functionality.
FossilOrigin-Name: 1fbddf01b1c3fff95b05e2f2f709754e2b514296060b4846518791e7161d9ddb
This commit is contained in:
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
||||
C Always\sevaluate\swindow\sfunctions\susing\sthe\salternative\spath\susually\sonly\sused\sby\sEXCLUDE\sframes\sif\sthe\sSQLITE_QueryFlattener\stest\sflag\sis\sset.
|
||||
D 2019-03-18T18:55:35.969
|
||||
C Add\sfurther\stests\sfor\snew\swindow\sfunction\sfunctionality.
|
||||
D 2019-03-18T21:19:40.529
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 236d2739dc3e823c3c909bca2d6cef93009bafbefd7018a8f3281074ecb92954
|
||||
@ -604,7 +604,7 @@ F src/where.c 8a207cb2ca6b99e1edb1e4bbff9b0504385a759cbf66180d1deb34d80ca4b799
|
||||
F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
|
||||
F src/wherecode.c ce7b21e1be2b981d62683fc59c4ca73a04a7ff2f1ebec23d41baf2da2349afd6
|
||||
F src/whereexpr.c 90859652920f153d2c03f075488744be2926625ebd36911bcbcb17d0d29c891c
|
||||
F src/window.c ff735851ee35202a3b8834923121c3c1144b6dfed44c07453135684ccb9d1541
|
||||
F src/window.c 76d83479ab5d0379c1641e3e342f25c6e9f12987e59ce72d1ddcf3220bbad818
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||
@ -1680,7 +1680,7 @@ F test/window1.test 6c7bbed965407a28fc699d3bab2fd199e75dbd7a5b3fe88dfe8149c583a5
|
||||
F test/window2.tcl 9bfa842d8a62b0d36dc8c1b5972206393c43847433c6d75940b87fec93ce3143
|
||||
F test/window2.test 8e6d2a1b9f54dfebee1cde961c8590cd87b4db45c50f44947a211e1b63c2a05e
|
||||
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
|
||||
F test/window3.test f58f92026a7f51c9a4227e656cc392b4c6a7c856e03b114453937a48d1c98159
|
||||
F test/window3.test e9959a993c8a71e96433be8daaa1827d78b8921e4f12debd7bdbeb3c856ef3cb
|
||||
F test/window4.tcl 5fbaab489677914ee5686b2008426e336daf88a2f58be7df92757f780a5ebf91
|
||||
F test/window4.test bf8f86586ce101bf98e2306e597fa24aadc96c58d70ba4d11f956cf8ca4e0be3
|
||||
F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652821e
|
||||
@ -1689,8 +1689,8 @@ F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d761
|
||||
F test/window7.test ce7f865241fdd1c5c4db869cd7bb2986c3be836bc2e73649a6846dd920f63e0f
|
||||
F test/window8.tcl 9755f960fb3197e741b393e00841bb9374a5d5058f12b2d056213bfb53877b07
|
||||
F test/window8.test daacb65e98c21a614bed6cf55f0bb73146e0abac99916b3ed25041aa84911767
|
||||
F test/windowerr.tcl 4f0b111cdbb8de401a8135cd116604fb8add13042bb47a1f1496dd47a690e864
|
||||
F test/windowerr.test 461bc504d4af0ae16a081e0c3bdb3724356cdcfb07bdc4b1b2dc4ad91b69bb7e
|
||||
F test/windowerr.tcl 727d77959ac512b473dd2d659937f58688ce5460482a442c2d569fc8656491e5
|
||||
F test/windowerr.test 7962cf9b39f27b11ea5c62105ab2322a61ceac098dce536e2b8569c3053f62e7
|
||||
F test/windowfault.test cb27a4d8c85982733b123af667921df3a96e23d3739b15d414de75054b334cbe
|
||||
F test/with1.test a07b5aad7f77acdf13e52e8814ea94606fcc72e9ea4c99baf293e9d7c63940be
|
||||
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
|
||||
@ -1812,7 +1812,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 723c84be3ec5ae941b7abd2442cdb76ca3bd76a5ce2d830b0e648c6e1424885a
|
||||
R 2e8f4bf64033471c17340b1908337f7f
|
||||
P 2879a691aca9304aea5acb46bab8e82bb2e08eb54201f3679d60bfc0e8383845
|
||||
R 29fe8f61f3ee63049a1a0d59268525ca
|
||||
U dan
|
||||
Z e0a3f305963abba314f3600ee55e636f
|
||||
Z ab4dc94ee7f08da540a90fde4a158333
|
||||
|
@ -1 +1 @@
|
||||
2879a691aca9304aea5acb46bab8e82bb2e08eb54201f3679d60bfc0e8383845
|
||||
1fbddf01b1c3fff95b05e2f2f709754e2b514296060b4846518791e7161d9ddb
|
94
src/window.c
94
src/window.c
@ -248,16 +248,9 @@ static void nth_valueStepFunc(
|
||||
pCtx, "second argument to nth_value must be a positive integer", -1
|
||||
);
|
||||
}
|
||||
static void nth_valueValueFunc(sqlite3_context *pCtx){
|
||||
struct NthValueCtx *p;
|
||||
p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( p && p->pValue ){
|
||||
sqlite3_result_value(pCtx, p->pValue);
|
||||
}
|
||||
}
|
||||
static void nth_valueFinalizeFunc(sqlite3_context *pCtx){
|
||||
struct NthValueCtx *p;
|
||||
p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, 0);
|
||||
if( p && p->pValue ){
|
||||
sqlite3_result_value(pCtx, p->pValue);
|
||||
sqlite3_value_free(p->pValue);
|
||||
@ -265,6 +258,7 @@ static void nth_valueFinalizeFunc(sqlite3_context *pCtx){
|
||||
}
|
||||
}
|
||||
#define nth_valueInvFunc noopStepFunc
|
||||
#define nth_valueValueFunc noopValueFunc
|
||||
|
||||
static void first_valueStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
@ -282,13 +276,6 @@ static void first_valueStepFunc(
|
||||
UNUSED_PARAMETER(nArg);
|
||||
UNUSED_PARAMETER(apArg);
|
||||
}
|
||||
static void first_valueValueFunc(sqlite3_context *pCtx){
|
||||
struct NthValueCtx *p;
|
||||
p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( p && p->pValue ){
|
||||
sqlite3_result_value(pCtx, p->pValue);
|
||||
}
|
||||
}
|
||||
static void first_valueFinalizeFunc(sqlite3_context *pCtx){
|
||||
struct NthValueCtx *p;
|
||||
p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
@ -299,6 +286,7 @@ static void first_valueFinalizeFunc(sqlite3_context *pCtx){
|
||||
}
|
||||
}
|
||||
#define first_valueInvFunc noopStepFunc
|
||||
#define first_valueValueFunc noopValueFunc
|
||||
|
||||
/*
|
||||
** Implementation of built-in window function rank(). Assumes that
|
||||
@ -404,8 +392,8 @@ static void cume_distInvFunc(
|
||||
}
|
||||
static void cume_distValueFunc(sqlite3_context *pCtx){
|
||||
struct CallCount *p;
|
||||
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( p && p->nTotal ){
|
||||
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, 0);
|
||||
if( p ){
|
||||
double r = (double)(p->nStep) / (double)(p->nTotal);
|
||||
sqlite3_result_double(pCtx, r);
|
||||
}
|
||||
@ -529,7 +517,7 @@ static void last_valueInvFunc(
|
||||
}
|
||||
static void last_valueValueFunc(sqlite3_context *pCtx){
|
||||
struct LastValueCtx *p;
|
||||
p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, 0);
|
||||
if( p && p->pVal ){
|
||||
sqlite3_result_value(pCtx, p->pVal);
|
||||
}
|
||||
@ -1405,8 +1393,6 @@ static void windowAggStep(
|
||||
);
|
||||
assert( bInverse==0 || bInverse==1 );
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
|
||||
}else if( pFunc->zName==leadName || pFunc->zName==lagName ){
|
||||
/* no-op */
|
||||
}else if( pFunc->xSFunc!=noopStepFunc ){
|
||||
int addrIf = 0;
|
||||
if( pWin->pFilter ){
|
||||
@ -1506,9 +1492,6 @@ static void windowAggFinal(WindowCodeArg *p, int bFin){
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult);
|
||||
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
||||
if( bFin ){
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp);
|
||||
}
|
||||
}else if( pWin->regApp ){
|
||||
assert( pMWin->regStartRowid==0 );
|
||||
}else{
|
||||
@ -1526,6 +1509,12 @@ static void windowAggFinal(WindowCodeArg *p, int bFin){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to calculate the current values of all window functions in the
|
||||
** p->pMWin list by doing a full scan of the current window frame. Store the
|
||||
** results in the Window.regResult registers, ready to return the upper
|
||||
** layer.
|
||||
*/
|
||||
static void windowFullScan(WindowCodeArg *p){
|
||||
Window *pWin;
|
||||
Parse *pParse = p->pParse;
|
||||
@ -1828,11 +1817,17 @@ static void windowCodeRangeTest(
|
||||
sqlite3ReleaseTempReg(pParse, reg2);
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper function for sqlite3WindowCodeStep(). Each call to this function
|
||||
** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE
|
||||
** operation. Refer to the header comment for sqlite3WindowCodeStep() for
|
||||
** details.
|
||||
*/
|
||||
static int windowCodeOp(
|
||||
WindowCodeArg *p,
|
||||
int op,
|
||||
int regCountdown,
|
||||
int jumpOnEof
|
||||
WindowCodeArg *p, /* Context object */
|
||||
int op, /* WINDOW_RETURN_ROW, AGGSTEP or AGGINVERSE */
|
||||
int regCountdown, /* Register for OP_IfPos countdown */
|
||||
int jumpOnEof /* Jump here if stepped cursor reaches EOF */
|
||||
){
|
||||
int csr, reg;
|
||||
Parse *pParse = p->pParse;
|
||||
@ -1857,40 +1852,28 @@ static int windowCodeOp(
|
||||
if( regCountdown>0 ){
|
||||
if( pMWin->eType==TK_RANGE ){
|
||||
addrNextRange = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
switch( op ){
|
||||
case WINDOW_RETURN_ROW: {
|
||||
assert( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
case WINDOW_AGGINVERSE: {
|
||||
if( pMWin->eStart==TK_FOLLOWING ){
|
||||
windowCodeRangeTest(
|
||||
p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone
|
||||
);
|
||||
}else{
|
||||
windowCodeRangeTest(
|
||||
p, OP_Ge, p->start.csr, regCountdown, p->current.csr, lblDone
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WINDOW_AGGSTEP: {
|
||||
assert( op==WINDOW_AGGINVERSE || op==WINDOW_AGGSTEP );
|
||||
if( op==WINDOW_AGGINVERSE ){
|
||||
if( pMWin->eStart==TK_FOLLOWING ){
|
||||
windowCodeRangeTest(
|
||||
p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone
|
||||
p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone
|
||||
);
|
||||
}else{
|
||||
windowCodeRangeTest(
|
||||
p, OP_Ge, p->start.csr, regCountdown, p->current.csr, lblDone
|
||||
);
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
windowCodeRangeTest(
|
||||
p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone
|
||||
);
|
||||
}
|
||||
|
||||
}else{
|
||||
addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if( op==WINDOW_RETURN_ROW ){
|
||||
if( op==WINDOW_RETURN_ROW && pMWin->regStartRowid==0 ){
|
||||
windowAggFinal(p, 0);
|
||||
}
|
||||
addrContinue = sqlite3VdbeCurrentAddr(v);
|
||||
@ -1912,7 +1895,8 @@ static int windowCodeOp(
|
||||
}
|
||||
break;
|
||||
|
||||
case WINDOW_AGGSTEP:
|
||||
default:
|
||||
assert( op==WINDOW_AGGSTEP );
|
||||
csr = p->end.csr;
|
||||
reg = p->end.reg;
|
||||
if( pMWin->regStartRowid ){
|
||||
@ -2421,8 +2405,6 @@ void sqlite3WindowCodeStep(
|
||||
break;
|
||||
}
|
||||
|
||||
s.eDelete = 0;
|
||||
|
||||
/* Allocate registers for the array of values from the sub-query, the
|
||||
** samve values in record form, and the rowid used to insert said record
|
||||
** into the ephemeral table. */
|
||||
@ -2501,7 +2483,7 @@ void sqlite3WindowCodeStep(
|
||||
windowCheckValue(pParse, regEnd, 1 + (pMWin->eType==TK_RANGE ? 3 : 0));
|
||||
}
|
||||
|
||||
if( pMWin->eStart==pMWin->eEnd && regStart && regEnd ){
|
||||
if( pMWin->eStart==pMWin->eEnd && regStart ){
|
||||
int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
|
||||
int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
|
||||
windowAggFinal(&s, 0);
|
||||
|
31215
test/window3.test
31215
test/window3.test
File diff suppressed because one or more lines are too long
@ -38,6 +38,8 @@ foreach {tn frame} {
|
||||
6 "ORDER BY a GROUPS BETWEEN 1 PRECEDING AND -1 FOLLOWING"
|
||||
|
||||
7 "ORDER BY a,b RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING"
|
||||
|
||||
8 "PARTITION BY a RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING"
|
||||
} {
|
||||
errorsql_test 1.$tn "
|
||||
SELECT a, sum(b) OVER (
|
||||
|
@ -79,4 +79,11 @@ do_test 1.7 { catch { execsql {
|
||||
) FROM t1 ORDER BY 1
|
||||
} } } 1
|
||||
|
||||
# PG says ERROR: RANGE with offset PRECEDING/FOLLOWING requires exactly one ORDER BY column
|
||||
do_test 1.8 { catch { execsql {
|
||||
SELECT a, sum(b) OVER (
|
||||
PARTITION BY a RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING
|
||||
) FROM t1 ORDER BY 1
|
||||
} } } 1
|
||||
|
||||
finish_test
|
||||
|
Reference in New Issue
Block a user