Add support for "ROWS BETWEEN <expr> PRECEDING AND <expr> FOLLOWING" window
frames. FossilOrigin-Name: 3a203660f1e4da3b8d2d605c494f4843f6e00752f28042b49e11d7d6550dd406
This commit is contained in:
parent
72779425b5
commit
c3a20c19a8
28
manifest
28
manifest
@ -1,5 +1,5 @@
|
||||
C Merge\slatest\strunk\schanges\sinto\sthis\sbranch.
|
||||
D 2018-05-22T20:36:12.808
|
||||
C Add\ssupport\sfor\s"ROWS\sBETWEEN\s<expr>\sPRECEDING\sAND\s<expr>\sFOLLOWING"\swindow\nframes.
|
||||
D 2018-05-23T20:55:37.621
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
|
||||
@ -435,8 +435,8 @@ F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 8270813c8f0ca91b2802e88ded3755d04ee962a923d431c13bcb6cf3e0c18f63
|
||||
F src/btree.h 448f15b98ea85dcf7e4eb76f731cadb89636c676ad25dfaac6de77cd66556598
|
||||
F src/btree.c b8fc4fcf851316fc0b84d4aa46899d127df952c39cfeb067bc97036060df1138
|
||||
F src/btree.h d46a8e31a4bd15572cdb6f2c940966f57b605b865628028c5eccf7d1bed83bac
|
||||
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
||||
F src/build.c 50ff3e0fa07646b4d797aae0f773efcdb7602f6a5e2f5da27856503f35200889
|
||||
F src/callback.c fe677cb5f5abb02f7a772a62a98c2f516426081df68856e8f2d5f950929b966a
|
||||
@ -449,7 +449,7 @@ F src/delete.c b0f90749e22d5e41a12dbf940f4811138cf97da54b46b737089b93eb64a2896f
|
||||
F src/expr.c bb57b0b5ba1351335091ce4ec43b40968746f03afd65c9e2920d7cbe4dc98133
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
|
||||
F src/func.c b1a5122c69ef13c7bf0100e792ca539a36034c1b50476233ded6d2f72afcfbfc
|
||||
F src/func.c eff9c15696cda3485df3ae52ce3663692a2cd506fba63a5f49f56cb204831021
|
||||
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
|
||||
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
@ -494,12 +494,12 @@ F src/printf.c 1d1b4a568a58d0f32a5ff26c6b98db8a6e1883467f343a6406263cacd2e60c21
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 446f60b2e0d2440bb233d6a69a4ed0f2ad030a4e63ac4b3cfc0e98cf73d9c5a3
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 1ebe775c0651bf357ab83b4c9b9139194149cfe1277dfa3e16f3ed73669b6b04
|
||||
F src/select.c 8a7f842a049a3407079e0b0748de916dcd91c00377394b2e8b1aefc5972a0b2f
|
||||
F src/shell.c.in 51c100206f4b7f86cd9affd80b764825e0edc36ca0190c442e4ca7994611bfe2
|
||||
F src/sqlite.h.in 34be2d0d18bf4726538793bdc9854cd87f689fda4b3789515134cdbd68188cf4
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
||||
F src/sqliteInt.h a3f0edb26ebfee6107fa99f3c300e71018ad23addeeba0746a4ac62425e36f3f
|
||||
F src/sqliteInt.h 735b04170551a899e8703421c376f98c19503b8210ad4cd2e0f35b85b6af595d
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -564,7 +564,7 @@ F src/upsert.c ae4a4823b45c4daf87e8aea8c0f582a8844763271f5ed54ee5956c4c612734f4
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||
F src/vacuum.c 37730af7540033135909ecaee3667dddec043293428d8718546d0d64ba4a5025
|
||||
F src/vdbe.c d83cfec9ebf523d5b2a8a3756ba8f23e39723725334a2e2e947e602ef6e6b278
|
||||
F src/vdbe.c 89c76c95a24e2561f5f94ef8530bd0127d512ed56b62932047ef89076d58fa91
|
||||
F src/vdbe.h d970d9738efdd09cb2df73e3a40856e7df13e88a3486789c49fcdd322c9eb8a2
|
||||
F src/vdbeInt.h 3878856fab3a8e64d27d472909e391db9d82f4f8b902a1737a1f7f351299ff52
|
||||
F src/vdbeapi.c 29d2baf9c1233131ec467d7bed1b7c8a03c27579048d768c4b04acf427838858
|
||||
@ -582,7 +582,7 @@ F src/where.c 60ec752fcbe9f9e0271ac60548d159a540a1ee47a4f9fedc85e88a3d0e392dd1
|
||||
F src/whereInt.h cbae2bcd37cfebdb7812a8b188cdb19634ced2b9346470d1c270556b0c33ea53
|
||||
F src/wherecode.c 728c7f70731430ccdac807a79969873e1af6968bf1c4745dff3f9dd35f636cc8
|
||||
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
|
||||
F src/window.c 37eb02c2af935f207ba902ef25ec27d635b68bb1567f9e5994a6720bac1c093e
|
||||
F src/window.c 1313e941d1e50a44594e6f3e12bc7d0fe6f092ea35c1f3884c31bd224ba66d29
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||
@ -1615,8 +1615,8 @@ F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
||||
F test/window1.test 5705337783d220b47f6fb4432264543b7557a05be8013d772f57d71f2fded271
|
||||
F test/window2.tcl 7e0b692974a18ae0992dd2e76be83d8e1c6c5cac3190d84fa62911ab0e5c7896
|
||||
F test/window2.test e1453371b605e54eeb2264fc3a4a23c5eba93e95f6c7f3230fce9d34b4b5e8a4
|
||||
F test/window2.tcl 29e9bb16a52eb1e9e8f376519185af5c64eed88a8e6f0bee54237ba2971803a7
|
||||
F test/window2.test f580e1cc96d1ccb6bb220d1e338525ee5541e45e2206ed9ca74417ba862d8a62
|
||||
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
|
||||
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
|
||||
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
|
||||
@ -1733,7 +1733,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 16168146b202915252f9375aef38e65ca20c5d4aa906e851d4d3a484db57562d c6071ac99cfa4b6272ac4d739fc61a85acb544f6c1c2ae67b31e92aadcc995bd
|
||||
R a9163894154abe7467dbbc7b918577f5
|
||||
P cdb68d2c64e453fdcd29437d5915c5c5ab6fbc7b5ffac52f4cb393f35b4a0124
|
||||
R 20d653691e285483f3e3bdb0b082aa4b
|
||||
U dan
|
||||
Z 671adb87a45ec21df0f125088181e31d
|
||||
Z e628ea8085262c078f67c7957c5a3c95
|
||||
|
@ -1 +1 @@
|
||||
cdb68d2c64e453fdcd29437d5915c5c5ab6fbc7b5ffac52f4cb393f35b4a0124
|
||||
3a203660f1e4da3b8d2d605c494f4843f6e00752f28042b49e11d7d6550dd406
|
@ -5176,6 +5176,13 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
|
||||
return rc;
|
||||
}
|
||||
|
||||
void sqlite3BtreeSkipNext(BtCursor *pCur){
|
||||
if( pCur->eState==CURSOR_VALID ){
|
||||
pCur->eState = CURSOR_SKIPNEXT;
|
||||
pCur->skipNext = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move the cursor to the last entry in the table. Return SQLITE_OK
|
||||
** on success. Set *pRes to 0 if the cursor actually points to something
|
||||
** or set *pRes to 1 if the table is empty.
|
||||
|
@ -301,6 +301,7 @@ struct BtreePayload {
|
||||
int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
|
||||
int flags, int seekResult);
|
||||
int sqlite3BtreeFirst(BtCursor*, int *pRes);
|
||||
void sqlite3BtreeSkipNext(BtCursor*);
|
||||
int sqlite3BtreeLast(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeNext(BtCursor*, int flags);
|
||||
int sqlite3BtreeEof(BtCursor*);
|
||||
|
29
src/func.c
29
src/func.c
@ -1513,6 +1513,27 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}
|
||||
}
|
||||
}
|
||||
static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
SumCtx *p;
|
||||
int type;
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
type = sqlite3_value_numeric_type(argv[0]);
|
||||
if( p && type!=SQLITE_NULL ){
|
||||
p->cnt--;
|
||||
if( type==SQLITE_INTEGER ){
|
||||
i64 v = sqlite3_value_int64(argv[0]);
|
||||
p->rSum -= v;
|
||||
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, -1*v) ){
|
||||
p->overflow = 1;
|
||||
}
|
||||
}else{
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
p->approx = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void sumFinalize(sqlite3_context *context){
|
||||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
@ -1873,12 +1894,12 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
|
||||
FUNCTION(substr, 2, 0, 0, substrFunc ),
|
||||
FUNCTION(substr, 3, 0, 0, substrFunc ),
|
||||
WAGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize),
|
||||
WAGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
|
||||
WAGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
|
||||
WAGGREGATE(sum, 1, 0, 0, sumStep, sumInverse, sumFinalize),
|
||||
WAGGREGATE(total, 1, 0, 0, sumStep, sumInverse, totalFinalize ),
|
||||
WAGGREGATE(avg, 1, 0, 0, sumStep, sumInverse, avgFinalize ),
|
||||
AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
|
||||
SQLITE_FUNC_COUNT ),
|
||||
WAGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
|
||||
WAGGREGATE(count, 1, 0, 0, countStep, 0, countFinalize ),
|
||||
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize,
|
||||
groupConcatValue),
|
||||
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize,
|
||||
|
19
src/select.c
19
src/select.c
@ -5576,7 +5576,7 @@ static int selectWindowRewrite(Parse *pParse, Select *p){
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pMWin->nBufferCol);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -6087,16 +6087,23 @@ int sqlite3Select(
|
||||
if( pWin ){
|
||||
int addrGosub = sqlite3VdbeMakeLabel(v);
|
||||
int regGosub = ++pParse->nMem;
|
||||
int addr;
|
||||
int addr = 0;
|
||||
int bLoop = 0;
|
||||
|
||||
sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub);
|
||||
sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub, &bLoop);
|
||||
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeResolveLabel(v, addrGosub);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_Rewind, pWin->iEphCsr);
|
||||
if( bLoop ){
|
||||
addr = sqlite3VdbeAddOp1(v, OP_Rewind, pWin->iEphCsr);
|
||||
}else{
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
}
|
||||
selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addr+1, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, pWin->iEphCsr, addr+1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
if( bLoop ){
|
||||
sqlite3VdbeAddOp2(v, OP_Next, pWin->iEphCsr, addr+1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regGosub);
|
||||
sqlite3VdbeJumpHere(v, addr-1); /* OP_Goto jumps here */
|
||||
|
||||
|
@ -1723,9 +1723,9 @@ struct FuncDestructor {
|
||||
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
|
||||
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}}
|
||||
|
||||
#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
|
||||
#define WAGGREGATE(zName, nArg, arg, nc, xStep, xInverse, xFinal) \
|
||||
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
|
||||
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}}
|
||||
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,xInverse,#zName, {0}}
|
||||
|
||||
/*
|
||||
** All current savepoints are stored in a linked list starting at
|
||||
@ -3496,7 +3496,7 @@ Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*);
|
||||
void sqlite3WindowAttach(Parse*, Expr*, Window*);
|
||||
int sqlite3WindowCompare(Parse*, Window*, Window*);
|
||||
void sqlite3WindowCodeInit(Parse*, Window*);
|
||||
void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
|
||||
void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int, int*);
|
||||
|
||||
/*
|
||||
** Assuming zIn points to the first byte of a UTF-8 character,
|
||||
|
@ -5018,6 +5018,7 @@ case OP_Rewind: { /* jump */
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr );
|
||||
rc = sqlite3BtreeFirst(pCrsr, &res);
|
||||
if( pOp->p5 ) sqlite3BtreeSkipNext(pCrsr);
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
}
|
||||
@ -6273,7 +6274,8 @@ case OP_AggStep: {
|
||||
assert( pCtx->pOut->flags==MEM_Null );
|
||||
assert( pCtx->isError==0 );
|
||||
assert( pCtx->skipFlag==0 );
|
||||
(pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
|
||||
(pOp->p1 ? (pCtx->pFunc->xInverse) : (pCtx->pFunc->xSFunc))
|
||||
(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
|
||||
if( pCtx->isError ){
|
||||
if( pCtx->isError>0 ){
|
||||
sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
|
||||
|
382
src/window.c
382
src/window.c
@ -25,8 +25,8 @@ void sqlite3WindowDelete(sqlite3 *db, Window *p){
|
||||
Window *sqlite3WindowAlloc(
|
||||
Parse *pParse,
|
||||
int eType,
|
||||
int eEnd, Expr *pEnd,
|
||||
int eStart, Expr *pStart
|
||||
int eStart, Expr *pStart,
|
||||
int eEnd, Expr *pEnd
|
||||
){
|
||||
Window *pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
||||
|
||||
@ -77,6 +77,279 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pWin){
|
||||
}
|
||||
}
|
||||
|
||||
static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){
|
||||
static const char *azErr[] = {
|
||||
"frame starting offset must be a non-negative integer",
|
||||
"frame ending offset must be a non-negative integer"
|
||||
};
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int regZero = ++pParse->nMem;
|
||||
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero);
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3VdbeAddOp3(v, OP_Ge, regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
|
||||
sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
|
||||
}
|
||||
|
||||
static void windowCodeRowExprStep(
|
||||
Parse *pParse,
|
||||
Select *p,
|
||||
WhereInfo *pWInfo,
|
||||
int regGosub,
|
||||
int addrGosub
|
||||
){
|
||||
Window *pMWin = p->pWin;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Window *pWin;
|
||||
int k;
|
||||
int iSubCsr = p->pSrc->a[0].iCursor;
|
||||
int nSub = p->pSrc->a[0].pTab->nCol;
|
||||
int regFlushPart; /* Register for "Gosub flush_partition" */
|
||||
int addrFlushPart; /* Label for "Gosub flush_partition" */
|
||||
int addrDone; /* Label for "Gosub flush_partition_done" */
|
||||
|
||||
int reg = pParse->nMem+1;
|
||||
int regRecord = reg+nSub;
|
||||
int regRowid = regRecord+1;
|
||||
int addr;
|
||||
int csrPrec = pParse->nTab++;
|
||||
int csrFollow = pParse->nTab++;
|
||||
int regPrec; /* Value of <expr> PRECEDING */
|
||||
int regFollow; /* Value of <expr> FOLLOWING */
|
||||
int addrNext;
|
||||
int addrGoto;
|
||||
int addrIfPos1;
|
||||
int addrIfPos2;
|
||||
|
||||
pParse->nMem += nSub + 2;
|
||||
|
||||
/* Allocate register and label for the "flush_partition" sub-routine. */
|
||||
regFlushPart = ++pParse->nMem;
|
||||
addrFlushPart = sqlite3VdbeMakeLabel(v);
|
||||
addrDone = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
regPrec = ++pParse->nMem;
|
||||
regFollow = ++pParse->nMem;
|
||||
|
||||
/* Martial the row returned by the sub-select into an array of
|
||||
** registers. */
|
||||
for(k=0; k<nSub; k++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord);
|
||||
|
||||
/* Check if this is the start of a new partition. If so, call the
|
||||
** flush_partition sub-routine. */
|
||||
if( pMWin->pPartition ){
|
||||
ExprList *pPart = pMWin->pPartition;
|
||||
int nPart = (pPart ? pPart->nExpr : 0);
|
||||
int addrJump = 0;
|
||||
int regNewPart = reg + pMWin->nBufferCol;
|
||||
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
|
||||
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
|
||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, addrFlushPart);
|
||||
sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart);
|
||||
}
|
||||
|
||||
/* Buffer the current row in the ephemeral table. */
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
|
||||
|
||||
/* End of the input loop */
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
/* Invoke "flush_partition" to deal with the final (or only) partition */
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, addrFlushPart);
|
||||
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
|
||||
/* flush_partition: */
|
||||
sqlite3VdbeResolveLabel(v, addrFlushPart);
|
||||
sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, csrPrec, pMWin->iEphCsr);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, csrFollow, pMWin->iEphCsr);
|
||||
|
||||
sqlite3ExprCode(pParse, pMWin->pStart, regPrec);
|
||||
sqlite3ExprCode(pParse, pMWin->pEnd, regFollow);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pMWin->regResult);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pMWin->regAccum);
|
||||
|
||||
/* If either regPrec or regFollow are not non-negative integers, throw an
|
||||
** exception. */
|
||||
windowCheckFrameValue(pParse, regPrec, 0);
|
||||
windowCheckFrameValue(pParse, regFollow, 1);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, addrDone);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, csrPrec, addrDone);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, csrFollow, addrDone);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
|
||||
/* Invoke AggStep function for each window function using the row that
|
||||
** csrFollow currently points to. Or, if csrFollow is already at EOF,
|
||||
** do nothing. */
|
||||
addrNext = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csrFollow, addrNext+2);
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
int i;
|
||||
for(i=0; i<pWin->nArg; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csrFollow, pWin->iArgCol+i, reg+i);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg, pWin->regAccum);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addrNext+1);
|
||||
|
||||
addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regFollow, 0 , 1);
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp3(v,
|
||||
OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult
|
||||
);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone);
|
||||
|
||||
addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regPrec, 0 , 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csrPrec, sqlite3VdbeCurrentAddr(v)+1);
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
int i;
|
||||
for(i=0; i<pWin->nArg; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csrPrec, pWin->iArgCol+i, reg+i);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_AggStep0, 1, reg, pWin->regAccum);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addrIfPos2);
|
||||
|
||||
sqlite3VdbeJumpHere(v, addrIfPos1);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
|
||||
|
||||
/* flush_partition_done: */
|
||||
sqlite3VdbeResolveLabel(v, addrDone);
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
|
||||
|
||||
/* Jump to here to skip over flush_partition */
|
||||
sqlite3VdbeJumpHere(v, addrGoto);
|
||||
}
|
||||
|
||||
static void windowCodeDefaultStep(
|
||||
Parse *pParse,
|
||||
Select *p,
|
||||
WhereInfo *pWInfo,
|
||||
int regGosub,
|
||||
int addrGosub
|
||||
){
|
||||
Window *pMWin = p->pWin;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Window *pWin;
|
||||
int k;
|
||||
int iSubCsr = p->pSrc->a[0].iCursor;
|
||||
int nSub = p->pSrc->a[0].pTab->nCol;
|
||||
int reg = pParse->nMem+1;
|
||||
int regRecord = reg+nSub;
|
||||
int regRowid = regRecord+1;
|
||||
int addr;
|
||||
|
||||
pParse->nMem += nSub + 2;
|
||||
|
||||
/* Martial the row returned by the sub-select into an array of
|
||||
** registers. */
|
||||
for(k=0; k<nSub; k++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
|
||||
}
|
||||
|
||||
/* Check if this is the start of a new partition or peer group. */
|
||||
if( pMWin->regPart ){
|
||||
ExprList *pPart = pMWin->pPartition;
|
||||
int nPart = (pPart ? pPart->nExpr : 0);
|
||||
ExprList *pOrderBy = pMWin->pOrderBy;
|
||||
int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
|
||||
int addrGoto = 0;
|
||||
int addrJump = 0;
|
||||
|
||||
if( pPart ){
|
||||
int regNewPart = reg + pMWin->nBufferCol;
|
||||
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
|
||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
|
||||
}
|
||||
if( pOrderBy ){
|
||||
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
}
|
||||
}
|
||||
|
||||
if( pOrderBy ){
|
||||
int regNewPeer = reg + pMWin->nBufferCol + nPart;
|
||||
int regPeer = pMWin->regPart + nPart;
|
||||
|
||||
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
|
||||
if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer);
|
||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp3(v,
|
||||
OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult
|
||||
);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
}
|
||||
if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
|
||||
sqlite3VdbeAddOp3(
|
||||
v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1
|
||||
);
|
||||
|
||||
sqlite3VdbeJumpHere(v, addrJump);
|
||||
}
|
||||
|
||||
/* Invoke step function for window functions */
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg+pWin->iArgCol, pWin->regAccum);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
|
||||
}
|
||||
|
||||
/* Buffer the current row in the ephemeral table. */
|
||||
if( pMWin->nBufferCol>0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord);
|
||||
sqlite3VdbeAppendP4(v, (void*)"", 0);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
|
||||
|
||||
/* End the database scan loop. */
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||||
**
|
||||
@ -243,105 +516,22 @@ void sqlite3WindowCodeStep(
|
||||
Select *p,
|
||||
WhereInfo *pWInfo,
|
||||
int regGosub,
|
||||
int addrGosub
|
||||
int addrGosub,
|
||||
int *pbLoop
|
||||
){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Window *pWin;
|
||||
Window *pMWin = p->pWin;
|
||||
int k;
|
||||
int iSubCsr = p->pSrc->a[0].iCursor;
|
||||
int nSub = p->pSrc->a[0].pTab->nCol;
|
||||
int reg = pParse->nMem+1;
|
||||
int regRecord = reg+nSub;
|
||||
int regRowid = regRecord+1;
|
||||
int addr;
|
||||
|
||||
pParse->nMem += nSub + 2;
|
||||
|
||||
/* Martial the row returned by the sub-select into an array of
|
||||
** registers. */
|
||||
for(k=0; k<nSub; k++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
|
||||
if( pMWin->eType==TK_ROWS
|
||||
&& pMWin->eStart==TK_PRECEDING
|
||||
&& pMWin->eEnd==TK_FOLLOWING
|
||||
){
|
||||
*pbLoop = 0;
|
||||
windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if this is the start of a new partition or peer group. */
|
||||
if( pMWin->regPart ){
|
||||
ExprList *pPart = pMWin->pPartition;
|
||||
int nPart = (pPart ? pPart->nExpr : 0);
|
||||
ExprList *pOrderBy = pMWin->pOrderBy;
|
||||
int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
|
||||
int addrGoto = 0;
|
||||
int addrJump = 0;
|
||||
|
||||
if( pPart ){
|
||||
int regNewPart = reg + pMWin->nBufferCol;
|
||||
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
|
||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
|
||||
}
|
||||
if( pOrderBy ){
|
||||
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
}
|
||||
}
|
||||
|
||||
if( pOrderBy ){
|
||||
int regNewPeer = reg + pMWin->nBufferCol + nPart;
|
||||
int regPeer = pMWin->regPart + nPart;
|
||||
|
||||
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
|
||||
if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
|
||||
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer);
|
||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp3(v,
|
||||
OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult
|
||||
);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
}
|
||||
if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
|
||||
sqlite3VdbeAddOp3(
|
||||
v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1
|
||||
);
|
||||
|
||||
sqlite3VdbeJumpHere(v, addrJump);
|
||||
}
|
||||
|
||||
/* Invoke step function for window functions */
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg+pWin->iArgCol, pWin->regAccum);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
|
||||
}
|
||||
|
||||
/* Buffer the current row in the ephemeral table. */
|
||||
if( pMWin->nBufferCol>0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord);
|
||||
sqlite3VdbeAppendP4(v, (void*)"", 0);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
|
||||
|
||||
/* End the database scan loop. */
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
|
||||
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
|
||||
*pbLoop = 1;
|
||||
windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub);
|
||||
}
|
||||
|
||||
|
||||
|
@ -136,41 +136,75 @@ execsql_test 1.3 {
|
||||
SELECT sum(d) OVER (PARTITION BY b) FROM t1;
|
||||
}
|
||||
|
||||
puts $::fd finish_test
|
||||
==========
|
||||
|
||||
execsql_test 2.1 {
|
||||
SELECT a, sum(d) OVER (
|
||||
PARTITION BY b ORDER BY d
|
||||
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1000 PRECEDING AND 1 FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
execsql_test 2.2 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY b
|
||||
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1000 PRECEDING AND 1000 FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
execsql_test 2.3 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
|
||||
ROWS BETWEEN 1 PRECEDING AND 1000 FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
execsql_test 2.4 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
execsql_test 2.5 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING
|
||||
ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
execsql_test 2.6 {
|
||||
SELECT a, sum(d) OVER (
|
||||
PARTITION BY b
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
execsql_test 2.7 {
|
||||
SELECT a, sum(d) OVER (
|
||||
PARTITION BY b
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 0 PRECEDING AND 0 FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
puts $::fd finish_test
|
||||
==========
|
||||
|
||||
execsql_test 3.1 {
|
||||
SELECT a, sum(d) OVER (
|
||||
PARTITION BY b ORDER BY d
|
||||
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
execsql_test 3.2 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY b
|
||||
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
execsql_test 3.3 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
|
||||
) FROM t1
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,59 @@ do_execsql_test 1.3 {
|
||||
SELECT sum(d) OVER (PARTITION BY b) FROM t1;
|
||||
} {12 12 12 9 9 9}
|
||||
|
||||
#==========================================================================
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1000 PRECEDING AND 1 FOLLOWING
|
||||
) FROM t1
|
||||
} {1 3 2 6 3 10 4 15 5 21 6 21}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1000 PRECEDING AND 1000 FOLLOWING
|
||||
) FROM t1
|
||||
} {1 21 2 21 3 21 4 21 5 21 6 21}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1 PRECEDING AND 1000 FOLLOWING
|
||||
) FROM t1
|
||||
} {1 21 2 21 3 20 4 18 5 15 6 11}
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
|
||||
) FROM t1
|
||||
} {1 3 2 6 3 9 4 12 5 15 6 11}
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
SELECT a, sum(d) OVER (
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING
|
||||
) FROM t1
|
||||
} {1 1 2 3 3 5 4 7 5 9 6 11}
|
||||
|
||||
do_execsql_test 2.6 {
|
||||
SELECT a, sum(d) OVER (
|
||||
PARTITION BY b
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
|
||||
) FROM t1
|
||||
} {2 6 4 12 6 10 1 4 3 9 5 8}
|
||||
|
||||
do_execsql_test 2.7 {
|
||||
SELECT a, sum(d) OVER (
|
||||
PARTITION BY b
|
||||
ORDER BY d
|
||||
ROWS BETWEEN 0 PRECEDING AND 0 FOLLOWING
|
||||
) FROM t1
|
||||
} {2 2 4 4 6 6 1 1 3 3 5 5}
|
||||
|
||||
finish_test
|
||||
#==========================================================================
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user