1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Support some "ROWS BETWEEN N PRECEDING AND M FOLLOWING" window functions without caching entire partitions.

FossilOrigin-Name: e7a91f12282afb5d5d7d78397a11d18e0268ee0c931d85e21fce00d13929494e
This commit is contained in:
dan
2019-03-04 21:07:11 +00:00
parent e7c9ca41b2
commit 680f6e8e2e
9 changed files with 508 additions and 15 deletions

View File

@@ -1,5 +1,5 @@
C Add\ssupport\sfor\schaining\sof\sWINDOW\sdefinitions. C Support\ssome\s"ROWS\sBETWEEN\sN\sPRECEDING\sAND\sM\sFOLLOWING"\swindow\sfunctions\swithout\scaching\sentire\spartitions.
D 2019-02-16T17:27:51.404 D 2019-03-04T21:07:11.233
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 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4
@@ -519,7 +519,7 @@ F src/shell.c.in f2c1adbee3f6f36686b4a38d2168ebfc25298b4ad1e6d95199fc4e95b539251
F src/sqlite.h.in 7da74fd5bd7a9dbe92297060f036935520b26e240457287c5e67c7b9db51a986 F src/sqlite.h.in 7da74fd5bd7a9dbe92297060f036935520b26e240457287c5e67c7b9db51a986
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683 F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
F src/sqliteInt.h f44de7fea38d4fd03ee8db7f851f2727b701d4ec3fc21a8335e8d3888dda7176 F src/sqliteInt.h fa802d30bdb2c41a3645875006c08876ff2beca44f4e3715b6794fce9451538a
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -603,7 +603,7 @@ F src/where.c 8a207cb2ca6b99e1edb1e4bbff9b0504385a759cbf66180d1deb34d80ca4b799
F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88 F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
F src/wherecode.c a571d8d7c19d6db786a201f2df8788b320fefcb2842f2a1eb9a85b85e91bc35f F src/wherecode.c a571d8d7c19d6db786a201f2df8788b320fefcb2842f2a1eb9a85b85e91bc35f
F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442 F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
F src/window.c a96e58c91e77690726512e1dc5de2f95ece975097171e8554a9e8dbd3cdfb0d9 F src/window.c b2316f6082849e6a98a7f46209528721082533297c3c8b535edd5581863610d7
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
@@ -1196,7 +1196,7 @@ F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442 F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test 52d2c37fe8cc07ec7362024c214b04bb69432995b3a984a3fbabc60fa6ada3ee F test/permutations.test 52d2c37fe8cc07ec7362024c214b04bb69432995b3a984a3fbabc60fa6ada3ee
F test/pg_common.tcl 301ac19c1a52fd55166d26db929b3b89165c634d52b5f8ad76ea8cb06960db30 F test/pg_common.tcl 72d4c464cf323768bbeb260ea2439602af2a780458b2e67d40e459127fd42b8b
F test/pragma.test c267bf02742c823a191960895b3d52933cebd7beee26757d1ed694f213fcd867 F test/pragma.test c267bf02742c823a191960895b3d52933cebd7beee26757d1ed694f213fcd867
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9 F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9
@@ -1684,6 +1684,10 @@ F test/window4.tcl 511425f6b0abf9b953df54cc9c7295cc7c25d78f4ed6f7a74b094eec0120e
F test/window4.test c5d6bf3403e4ade2f19df2afe4c16f29fb817c392c6c1c8017edb7165c191a62 F test/window4.test c5d6bf3403e4ade2f19df2afe4c16f29fb817c392c6c1c8017edb7165c191a62
F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652821e F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652821e
F test/window6.test 5eae4ae7a590ccf1e605880969ca0bad3955616ac91cad3031baea38748badb3 F test/window6.test 5eae4ae7a590ccf1e605880969ca0bad3955616ac91cad3031baea38748badb3
F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f
F test/window7.test ce7f865241fdd1c5c4db869cd7bb2986c3be836bc2e73649a6846dd920f63e0f
F test/windowerr.tcl 5211e12818c013af2180c8da8f6dc007ef746e4cf386a5f2a87a5c340cb76829
F test/windowerr.test 8a38c774e41c1b0c76e20d035c979040a69e104fcc6f10d9d3d2d50daa3cfafd
F test/windowfault.test 12ceb6bbb355d13e8fcd88c5731a57256dfdf77b9a7ae20842a76fcd4623df5b F test/windowfault.test 12ceb6bbb355d13e8fcd88c5731a57256dfdf77b9a7ae20842a76fcd4623df5b
F test/with1.test a07b5aad7f77acdf13e52e8814ea94606fcc72e9ea4c99baf293e9d7c63940be F test/with1.test a07b5aad7f77acdf13e52e8814ea94606fcc72e9ea4c99baf293e9d7c63940be
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
@@ -1804,10 +1808,8 @@ 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 aa61435a4c3800f023788081c1342ad6a05a41449a424fa6c039d5ca46072256 P c155125fd5dddb438c09d40f5137c47d88defb7a6ede4261f09d7bdaad250d37
R f8f3f55ce4dbb9bcc0042a3bde2239b1 R af19e2d286499d03a5f60c3423d10c17
T *branch * window-functions T +closed 9c17fdebd5a44754ee5d23b5403b0c51fae6ba98eb4b2b54e1389de4d4b142f7
T *sym-window-functions *
T -sym-trunk *
U dan U dan
Z b3b312efff88db643f5cb6a825d2a2ac Z 3c7515a96a0c664794629970af14a8d6

View File

@@ -1 +1 @@
c155125fd5dddb438c09d40f5137c47d88defb7a6ede4261f09d7bdaad250d37 e7a91f12282afb5d5d7d78397a11d18e0268ee0c931d85e21fce00d13929494e

View File

@@ -3577,6 +3577,8 @@ struct Window {
Expr *pOwner; /* Expression object this window is attached to */ Expr *pOwner; /* Expression object this window is attached to */
int nBufferCol; /* Number of columns in buffer table */ int nBufferCol; /* Number of columns in buffer table */
int iArgCol; /* Offset of first argument for this function */ int iArgCol; /* Offset of first argument for this function */
int regFirst;
}; };
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC

View File

@@ -788,6 +788,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
** The OpenEphemeral instruction is coded later, after it is known how ** The OpenEphemeral instruction is coded later, after it is known how
** many columns the table will have. */ ** many columns the table will have. */
pMWin->iEphCsr = pParse->nTab++; pMWin->iEphCsr = pParse->nTab++;
pParse->nTab += 3;
selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist); selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist);
selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist); selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist);
@@ -843,6 +844,9 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
} }
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr);
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);
}else{ }else{
sqlite3SelectDelete(db, pSub); sqlite3SelectDelete(db, pSub);
} }
@@ -1086,6 +1090,9 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nPart-1); sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nPart-1);
} }
pMWin->regFirst = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regFirst);
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
FuncDef *p = pWin->pFunc; FuncDef *p = pWin->pFunc;
if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){ if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){
@@ -1429,10 +1436,10 @@ static void windowReturnOneRow(
} }
else if( pFunc->zName==leadName || pFunc->zName==lagName ){ else if( pFunc->zName==leadName || pFunc->zName==lagName ){
int nArg = pWin->pOwner->x.pList->nExpr; int nArg = pWin->pOwner->x.pList->nExpr;
int iEph = pMWin->iEphCsr;
int csr = pWin->csrApp; int csr = pWin->csrApp;
int lbl = sqlite3VdbeMakeLabel(pParse); int lbl = sqlite3VdbeMakeLabel(pParse);
int tmpReg = sqlite3GetTempReg(pParse); int tmpReg = sqlite3GetTempReg(pParse);
int iEph = pMWin->iEphCsr;
if( nArg<3 ){ if( nArg<3 ){
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
@@ -1834,6 +1841,154 @@ static void windowCodeRowExprStep(
sqlite3VdbeJumpHere(v, addrGoto); sqlite3VdbeJumpHere(v, addrGoto);
} }
static void windowCodeStep(
Parse *pParse,
Select *p,
WhereInfo *pWInfo,
int regGosub,
int addrGosub
){
Window *pMWin = p->pWin;
Vdbe *v = sqlite3GetVdbe(pParse);
int regFlushPart; /* Register for "Gosub flush_partition" */
int regArg;
int csrCurrent = pMWin->iEphCsr;
int csrWrite = csrCurrent+1;
int csrStart = csrCurrent+2;
int csrEnd = csrCurrent+3;
int regStart; /* Value of <expr> PRECEDING */
int regEnd; /* Value of <expr> FOLLOWING */
int iSubCsr = p->pSrc->a[0].iCursor;
int nSub = p->pSrc->a[0].pTab->nCol;
int k;
int addrGoto;
int addrIf;
int addrIfEnd;
int addrIfStart;
int addrGosubFlush;
int addrInteger;
int addrGoto2;
int reg = pParse->nMem+1;
int regRecord = reg+nSub;
int regRowid = regRecord+1;
pParse->nMem += 1 + nSub + 1;
regFlushPart = ++pParse->nMem;
regStart = ++pParse->nMem;
regEnd = ++pParse->nMem;
assert( pMWin->eStart==TK_PRECEDING
|| pMWin->eStart==TK_CURRENT
|| pMWin->eStart==TK_FOLLOWING
|| pMWin->eStart==TK_UNBOUNDED
);
assert( pMWin->eEnd==TK_FOLLOWING
|| pMWin->eEnd==TK_CURRENT
|| pMWin->eEnd==TK_UNBOUNDED
|| pMWin->eEnd==TK_PRECEDING
);
/* Load the column values for the row returned by the sub-select
** into an array of registers starting at reg. Assemble them into
** a record in register regRecord. TODO: An optimization here? */
for(k=0; k<nSub; k++){
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord);
/* Check if the current iteration is the first row of a new partition */
if( pMWin->pPartition ){
int addr;
ExprList *pPart = pMWin->pPartition;
int nPart = pPart->nExpr;
int regNewPart = reg + pMWin->nBufferCol;
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
addrIf = sqlite3VdbeAddOp1(v, OP_If, pMWin->regFirst);
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart, nPart);
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+3, addr+2);
VdbeCoverageEqNe(v);
addrGosubFlush = sqlite3VdbeAddOp1(v, OP_Gosub, regFlushPart);
VdbeComment((v, "call flush_partition"));
sqlite3VdbeJumpHere(v, addrIf);
}
/* Insert the new row into the ephemeral table */
sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, regRowid);
/* This block is run for the first row of each partition */
addrIf = sqlite3VdbeAddOp1(v, OP_IfNot, pMWin->regFirst);
if( pMWin->pPartition ){
sqlite3VdbeAddOp3(v, OP_Copy,
reg+pMWin->nBufferCol, pMWin->regPart, pMWin->pPartition->nExpr-1
);
}
sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, 1); sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeAddOp2(v, OP_Rewind, csrCurrent, 1); sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, 1);
regArg = windowInitAccum(pParse, pMWin);
sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regFirst);
sqlite3ExprCode(pParse, pMWin->pStart, regStart);
windowCheckIntValue(pParse, regStart, 0);
sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
windowCheckIntValue(pParse, regEnd, 1);
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
/* This block is run for the second and subsequent rows of each partition */
sqlite3VdbeJumpHere(v, addrIf);
sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+1);
addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
windowAggFinal(pParse, pMWin, 0);
sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+1);
windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
windowAggStep(pParse, pMWin, csrStart, 1, regArg, 0);
sqlite3VdbeJumpHere(v, addrIfStart);
sqlite3VdbeJumpHere(v, addrIfEnd);
sqlite3VdbeJumpHere(v, addrGoto);
windowAggStep(pParse, pMWin, csrEnd, 0, regArg, 0);
/* End of the main input loop */
sqlite3WhereEnd(pWInfo);
/* Fall through */
if( pMWin->pPartition ){
addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart);
sqlite3VdbeJumpHere(v, addrGosubFlush);
}
sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+2);
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
windowAggFinal(pParse, pMWin, 0);
windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2);
addrGoto2 = sqlite3VdbeAddOp0(v, OP_Goto);
windowAggStep(pParse, pMWin, csrStart, 1, regArg, 0);
sqlite3VdbeJumpHere(v, addrIfStart);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrGoto-1);
sqlite3VdbeJumpHere(v, addrGoto);
sqlite3VdbeJumpHere(v, addrGoto2);
sqlite3VdbeAddOp1(v, OP_ResetSorter, csrCurrent);
sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regFirst);
if( pMWin->pPartition ){
sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
}
}
/* /*
** This function does the work of sqlite3WindowCodeStep() for cases that ** This function does the work of sqlite3WindowCodeStep() for cases that
** would normally be handled by windowCodeDefaultStep() when there are ** would normally be handled by windowCodeDefaultStep() when there are
@@ -2296,8 +2451,29 @@ void sqlite3WindowCodeStep(
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)
){ ){
Window *pWin;
int bCache = 0; /* True to use CacheStep() */
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
FuncDef *pFunc = pWin->pFunc;
if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)
|| (pFunc->zName==nth_valueName)
|| (pFunc->zName==first_valueName)
|| (pFunc->zName==leadName)
|| (pFunc->zName==lagName)
){
bCache = 1;
break;
}
}
if( bCache || pMWin->eStart!=TK_PRECEDING || pMWin->eEnd!=TK_FOLLOWING ){
VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()")); VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()"));
windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub); windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
VdbeModuleComment((pParse->pVdbe, "End RowExprStep()"));
}else{
VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep()"));
windowCodeStep(pParse, p, pWInfo, regGosub, addrGosub);
VdbeModuleComment((pParse->pVdbe, "End windowCodeStep()"));
}
}else{ }else{
Window *pWin; Window *pWin;
int bCache = 0; /* True to use CacheStep() */ int bCache = 0; /* True to use CacheStep() */
@@ -2323,9 +2499,11 @@ void sqlite3WindowCodeStep(
if( bCache ){ if( bCache ){
VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()")); VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()"));
windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub); windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub);
VdbeModuleComment((pParse->pVdbe, "End CacheStep()"));
}else{ }else{
VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()")); VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()"));
windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub); windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub);
VdbeModuleComment((pParse->pVdbe, "End DefaultStep()"));
} }
} }
} }

View File

@@ -67,6 +67,19 @@ proc execsql_test {tn sql} {
puts $::fd "" puts $::fd ""
} }
proc errorsql_test {tn sql} {
set rc [catch {execsql $sql} msg]
if {$rc==0} {
error "errorsql_test SQL did not cause an error!"
}
puts $::fd "# PG says \"[string trim $msg]\""
set sql [string map {string_agg group_concat} $sql]
puts $::fd "do_test $tn { catch { execsql {"
puts $::fd " [string trim $sql]"
puts $::fd "} } } 1"
puts $::fd ""
}
# Same as [execsql_test], except coerce all results to floating point values # Same as [execsql_test], except coerce all results to floating point values
# with two decimal points. # with two decimal points.
# #

91
test/window7.tcl Normal file
View File

@@ -0,0 +1,91 @@
# 2018 May 19
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
source [file join [file dirname $argv0] pg_common.tcl]
#=========================================================================
start_test window7 "2019 March 01"
ifcapable !windowfunc
execsql_test 1.0 {
DROP TABLE IF EXISTS t3;
CREATE TABLE t3(a INTEGER, b INTEGER);
INSERT INTO t3 VALUES
(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8),
(9, 9), (0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16),
(7, 17), (8, 18), (9, 19), (0, 20), (1, 21), (2, 22), (3, 23), (4, 24),
(5, 25), (6, 26), (7, 27), (8, 28), (9, 29), (0, 30), (1, 31), (2, 32),
(3, 33), (4, 34), (5, 35), (6, 36), (7, 37), (8, 38), (9, 39), (0, 40),
(1, 41), (2, 42), (3, 43), (4, 44), (5, 45), (6, 46), (7, 47), (8, 48),
(9, 49), (0, 50), (1, 51), (2, 52), (3, 53), (4, 54), (5, 55), (6, 56),
(7, 57), (8, 58), (9, 59), (0, 60), (1, 61), (2, 62), (3, 63), (4, 64),
(5, 65), (6, 66), (7, 67), (8, 68), (9, 69), (0, 70), (1, 71), (2, 72),
(3, 73), (4, 74), (5, 75), (6, 76), (7, 77), (8, 78), (9, 79), (0, 80),
(1, 81), (2, 82), (3, 83), (4, 84), (5, 85), (6, 86), (7, 87), (8, 88),
(9, 89), (0, 90), (1, 91), (2, 92), (3, 93), (4, 94), (5, 95), (6, 96),
(7, 97), (8, 98), (9, 99), (0, 100);
}
execsql_test 1.1 {
SELECT a, sum(b) FROM t3 GROUP BY a ORDER BY 1;
}
execsql_test 1.2 {
SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN CURRENT ROW AND CURRENT ROW
) FROM t3 ORDER BY 1;
}
execsql_test 1.3 {
SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN 0 PRECEDING AND 0 FOLLOWING
) FROM t3 ORDER BY 1;
}
execsql_test 1.4 {
SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING
) FROM t3 ORDER BY 1;
}
execsql_test 1.5 {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING
) FROM t3 ORDER BY 1;
}
execsql_test 1.6 {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING
) FROM t3 ORDER BY 1;
}
execsql_test 1.7 {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 2 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1;
}
execsql_test 1.8.1 {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1;
}
execsql_test 1.8.2 {
SELECT a, sum(b) OVER (
ORDER BY a DESC RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1;
}
finish_test

94
test/window7.test Normal file
View File

@@ -0,0 +1,94 @@
# 2019 March 01
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
####################################################
# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
####################################################
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix window7
ifcapable !windowfunc { finish_test ; return }
do_execsql_test 1.0 {
DROP TABLE IF EXISTS t3;
CREATE TABLE t3(a INTEGER, b INTEGER);
INSERT INTO t3 VALUES
(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8),
(9, 9), (0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16),
(7, 17), (8, 18), (9, 19), (0, 20), (1, 21), (2, 22), (3, 23), (4, 24),
(5, 25), (6, 26), (7, 27), (8, 28), (9, 29), (0, 30), (1, 31), (2, 32),
(3, 33), (4, 34), (5, 35), (6, 36), (7, 37), (8, 38), (9, 39), (0, 40),
(1, 41), (2, 42), (3, 43), (4, 44), (5, 45), (6, 46), (7, 47), (8, 48),
(9, 49), (0, 50), (1, 51), (2, 52), (3, 53), (4, 54), (5, 55), (6, 56),
(7, 57), (8, 58), (9, 59), (0, 60), (1, 61), (2, 62), (3, 63), (4, 64),
(5, 65), (6, 66), (7, 67), (8, 68), (9, 69), (0, 70), (1, 71), (2, 72),
(3, 73), (4, 74), (5, 75), (6, 76), (7, 77), (8, 78), (9, 79), (0, 80),
(1, 81), (2, 82), (3, 83), (4, 84), (5, 85), (6, 86), (7, 87), (8, 88),
(9, 89), (0, 90), (1, 91), (2, 92), (3, 93), (4, 94), (5, 95), (6, 96),
(7, 97), (8, 98), (9, 99), (0, 100);
} {}
do_execsql_test 1.1 {
SELECT a, sum(b) FROM t3 GROUP BY a ORDER BY 1;
} {0 550 1 460 2 470 3 480 4 490 5 500 6 510 7 520 8 530 9 540}
do_execsql_test 1.2 {
SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN CURRENT ROW AND CURRENT ROW
) FROM t3 ORDER BY 1;
} {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540}
do_execsql_test 1.3 {
SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN 0 PRECEDING AND 0 FOLLOWING
) FROM t3 ORDER BY 1;
} {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540}
do_execsql_test 1.4 {
SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING
) FROM t3 ORDER BY 1;
} {0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590}
do_execsql_test 1.5 {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING
) FROM t3 ORDER BY 1;
} {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540}
do_execsql_test 1.6 {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING
) FROM t3 ORDER BY 1;
} {0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590}
do_execsql_test 1.7 {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 2 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1;
} {0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590}
do_execsql_test 1.8.1 {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1;
} {0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540}
do_execsql_test 1.8.2 {
SELECT a, sum(b) OVER (
ORDER BY a DESC RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1;
} {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070}
finish_test

43
test/windowerr.tcl Normal file
View File

@@ -0,0 +1,43 @@
# 2018 May 19
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
source [file join [file dirname $argv0] pg_common.tcl]
#=========================================================================
start_test windowerr "2019 March 01"
ifcapable !windowfunc
execsql_test 1.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER, b INTEGER);
}
foreach {tn frame} {
1 "ORDER BY a ROWS BETWEEN -1 PRECEDING AND 1 FOLLOWING"
2 "ORDER BY a ROWS BETWEEN 1 PRECEDING AND -1 FOLLOWING"
3 "ORDER BY a RANGE BETWEEN -1 PRECEDING AND 1 FOLLOWING"
4 "ORDER BY a RANGE BETWEEN 1 PRECEDING AND -1 FOLLOWING"
5 "ORDER BY a GROUPS BETWEEN -1 PRECEDING AND 1 FOLLOWING"
6 "ORDER BY a GROUPS BETWEEN 1 PRECEDING AND -1 FOLLOWING"
} {
errorsql_test 1.$tn "
SELECT a, sum(b) OVER (
$frame
) FROM t3 ORDER BY 1
"
}
finish_test

70
test/windowerr.test Normal file
View File

@@ -0,0 +1,70 @@
# 2019 March 01
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
####################################################
# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
####################################################
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix windowerr
ifcapable !windowfunc { finish_test ; return }
do_execsql_test 1.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER, b INTEGER);
} {}
# PG says "ERROR: frame starting offset must not be negative"
do_test 1.1 { catch { execsql {
SELECT a, sum(b) OVER (
ORDER BY a ROWS BETWEEN -1 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1
} } } 1
# PG says "ERROR: frame ending offset must not be negative"
do_test 1.2 { catch { execsql {
SELECT a, sum(b) OVER (
ORDER BY a ROWS BETWEEN 1 PRECEDING AND -1 FOLLOWING
) FROM t3 ORDER BY 1
} } } 1
# PG says "ERROR: invalid preceding or following size in window function"
do_test 1.3 { catch { execsql {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN -1 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1
} } } 1
# PG says "ERROR: invalid preceding or following size in window function"
do_test 1.4 { catch { execsql {
SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 1 PRECEDING AND -1 FOLLOWING
) FROM t3 ORDER BY 1
} } } 1
# PG says "ERROR: frame starting offset must not be negative"
do_test 1.5 { catch { execsql {
SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN -1 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1
} } } 1
# PG says "ERROR: frame ending offset must not be negative"
do_test 1.6 { catch { execsql {
SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN 1 PRECEDING AND -1 FOLLOWING
) FROM t3 ORDER BY 1
} } } 1
finish_test