xref: /sqlite-3.40.0/src/window.c (revision c3a20c19)
186fb6e17Sdan /*
286fb6e17Sdan **
386fb6e17Sdan ** The author disclaims copyright to this source code.  In place of
486fb6e17Sdan ** a legal notice, here is a blessing:
586fb6e17Sdan **
686fb6e17Sdan **    May you do good and not evil.
786fb6e17Sdan **    May you find forgiveness for yourself and forgive others.
886fb6e17Sdan **    May you share freely, never taking more than you give.
986fb6e17Sdan **
1086fb6e17Sdan *************************************************************************
1186fb6e17Sdan */
1286fb6e17Sdan #include "sqliteInt.h"
1386fb6e17Sdan 
1486fb6e17Sdan void sqlite3WindowDelete(sqlite3 *db, Window *p){
1586fb6e17Sdan   if( p ){
1686fb6e17Sdan     sqlite3ExprDelete(db, p->pFilter);
1786fb6e17Sdan     sqlite3ExprListDelete(db, p->pPartition);
1886fb6e17Sdan     sqlite3ExprListDelete(db, p->pOrderBy);
1986fb6e17Sdan     sqlite3ExprDelete(db, p->pEnd);
2086fb6e17Sdan     sqlite3ExprDelete(db, p->pStart);
2186fb6e17Sdan     sqlite3DbFree(db, p);
2286fb6e17Sdan   }
2386fb6e17Sdan }
2486fb6e17Sdan 
2586fb6e17Sdan Window *sqlite3WindowAlloc(
2686fb6e17Sdan   Parse *pParse,
2786fb6e17Sdan   int eType,
28*c3a20c19Sdan   int eStart, Expr *pStart,
29*c3a20c19Sdan   int eEnd, Expr *pEnd
3086fb6e17Sdan ){
3186fb6e17Sdan   Window *pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
3286fb6e17Sdan 
3386fb6e17Sdan   if( pWin ){
3486fb6e17Sdan     pWin->eType = eType;
3586fb6e17Sdan     pWin->eStart = eStart;
3686fb6e17Sdan     pWin->eEnd = eEnd;
3786fb6e17Sdan     pWin->pEnd = pEnd;
3886fb6e17Sdan     pWin->pStart = pStart;
3986fb6e17Sdan   }else{
4086fb6e17Sdan     sqlite3ExprDelete(pParse->db, pEnd);
4186fb6e17Sdan     sqlite3ExprDelete(pParse->db, pStart);
4286fb6e17Sdan   }
4386fb6e17Sdan 
4486fb6e17Sdan   return pWin;
4586fb6e17Sdan }
4686fb6e17Sdan 
4786fb6e17Sdan void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
4886fb6e17Sdan   if( p ){
4986fb6e17Sdan     p->pWin = pWin;
5086fb6e17Sdan   }else{
5186fb6e17Sdan     sqlite3WindowDelete(pParse->db, pWin);
5286fb6e17Sdan   }
5386fb6e17Sdan }
54e2f781b9Sdan 
55e2f781b9Sdan /*
56e2f781b9Sdan ** Return 0 if the two window objects are identical, or non-zero otherwise.
57e2f781b9Sdan */
58e2f781b9Sdan int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){
59e2f781b9Sdan   if( p1->eType!=p2->eType ) return 1;
60e2f781b9Sdan   if( p1->eStart!=p2->eStart ) return 1;
61e2f781b9Sdan   if( p1->eEnd!=p2->eEnd ) return 1;
62e2f781b9Sdan   if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
63e2f781b9Sdan   if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
64e2f781b9Sdan   if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1;
65e2f781b9Sdan   if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1;
66e2f781b9Sdan   return 0;
67e2f781b9Sdan }
68e2f781b9Sdan 
69f9eae18bSdan void sqlite3WindowCodeInit(Parse *pParse, Window *pWin){
70f9eae18bSdan   Vdbe *v = sqlite3GetVdbe(pParse);
71f9eae18bSdan   int nPart = (pWin->pPartition ? pWin->pPartition->nExpr : 0);
72f9eae18bSdan   nPart += (pWin->pOrderBy ? pWin->pOrderBy->nExpr : 0);
73f9eae18bSdan   if( nPart ){
74f9eae18bSdan     pWin->regPart = pParse->nMem+1;
75f9eae18bSdan     pParse->nMem += nPart;
76f9eae18bSdan     sqlite3VdbeAddOp3(v, OP_Null, 0, pWin->regPart, pWin->regPart+nPart-1);
77f9eae18bSdan   }
78f9eae18bSdan }
79f9eae18bSdan 
80*c3a20c19Sdan static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){
81*c3a20c19Sdan   static const char *azErr[] = {
82*c3a20c19Sdan     "frame starting offset must be a non-negative integer",
83*c3a20c19Sdan     "frame ending offset must be a non-negative integer"
84*c3a20c19Sdan   };
85*c3a20c19Sdan   Vdbe *v = sqlite3GetVdbe(pParse);
86*c3a20c19Sdan   int regZero = ++pParse->nMem;
87*c3a20c19Sdan 
88*c3a20c19Sdan 
89*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero);
90*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
91*c3a20c19Sdan   sqlite3VdbeAddOp3(v, OP_Ge, regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
92*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
93*c3a20c19Sdan   sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
94*c3a20c19Sdan }
95*c3a20c19Sdan 
96*c3a20c19Sdan static void windowCodeRowExprStep(
97*c3a20c19Sdan   Parse *pParse,
98*c3a20c19Sdan   Select *p,
99*c3a20c19Sdan   WhereInfo *pWInfo,
100*c3a20c19Sdan   int regGosub,
101*c3a20c19Sdan   int addrGosub
102*c3a20c19Sdan ){
103*c3a20c19Sdan   Window *pMWin = p->pWin;
104*c3a20c19Sdan   Vdbe *v = sqlite3GetVdbe(pParse);
105*c3a20c19Sdan   Window *pWin;
106*c3a20c19Sdan   int k;
107*c3a20c19Sdan   int iSubCsr = p->pSrc->a[0].iCursor;
108*c3a20c19Sdan   int nSub = p->pSrc->a[0].pTab->nCol;
109*c3a20c19Sdan   int regFlushPart;               /* Register for "Gosub flush_partition" */
110*c3a20c19Sdan   int addrFlushPart;              /* Label for "Gosub flush_partition" */
111*c3a20c19Sdan   int addrDone;                   /* Label for "Gosub flush_partition_done" */
112*c3a20c19Sdan 
113*c3a20c19Sdan   int reg = pParse->nMem+1;
114*c3a20c19Sdan   int regRecord = reg+nSub;
115*c3a20c19Sdan   int regRowid = regRecord+1;
116*c3a20c19Sdan   int addr;
117*c3a20c19Sdan   int csrPrec = pParse->nTab++;
118*c3a20c19Sdan   int csrFollow = pParse->nTab++;
119*c3a20c19Sdan   int regPrec;                    /* Value of <expr> PRECEDING */
120*c3a20c19Sdan   int regFollow;                  /* Value of <expr> FOLLOWING */
121*c3a20c19Sdan   int addrNext;
122*c3a20c19Sdan   int addrGoto;
123*c3a20c19Sdan   int addrIfPos1;
124*c3a20c19Sdan   int addrIfPos2;
125*c3a20c19Sdan 
126*c3a20c19Sdan   pParse->nMem += nSub + 2;
127*c3a20c19Sdan 
128*c3a20c19Sdan   /* Allocate register and label for the "flush_partition" sub-routine. */
129*c3a20c19Sdan   regFlushPart = ++pParse->nMem;
130*c3a20c19Sdan   addrFlushPart = sqlite3VdbeMakeLabel(v);
131*c3a20c19Sdan   addrDone = sqlite3VdbeMakeLabel(v);
132*c3a20c19Sdan 
133*c3a20c19Sdan   regPrec = ++pParse->nMem;
134*c3a20c19Sdan   regFollow = ++pParse->nMem;
135*c3a20c19Sdan 
136*c3a20c19Sdan   /* Martial the row returned by the sub-select into an array of
137*c3a20c19Sdan   ** registers. */
138*c3a20c19Sdan   for(k=0; k<nSub; k++){
139*c3a20c19Sdan     sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
140*c3a20c19Sdan   }
141*c3a20c19Sdan   sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord);
142*c3a20c19Sdan 
143*c3a20c19Sdan   /* Check if this is the start of a new partition. If so, call the
144*c3a20c19Sdan   ** flush_partition sub-routine.  */
145*c3a20c19Sdan   if( pMWin->pPartition ){
146*c3a20c19Sdan     ExprList *pPart = pMWin->pPartition;
147*c3a20c19Sdan     int nPart = (pPart ? pPart->nExpr : 0);
148*c3a20c19Sdan     int addrJump = 0;
149*c3a20c19Sdan     int regNewPart = reg + pMWin->nBufferCol;
150*c3a20c19Sdan     KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
151*c3a20c19Sdan 
152*c3a20c19Sdan     addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
153*c3a20c19Sdan     sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
154*c3a20c19Sdan     addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
155*c3a20c19Sdan     sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, addrFlushPart);
156*c3a20c19Sdan     sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart);
157*c3a20c19Sdan   }
158*c3a20c19Sdan 
159*c3a20c19Sdan   /* Buffer the current row in the ephemeral table. */
160*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
161*c3a20c19Sdan   sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
162*c3a20c19Sdan 
163*c3a20c19Sdan   /* End of the input loop */
164*c3a20c19Sdan   sqlite3WhereEnd(pWInfo);
165*c3a20c19Sdan 
166*c3a20c19Sdan   /* Invoke "flush_partition" to deal with the final (or only) partition */
167*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, addrFlushPart);
168*c3a20c19Sdan   addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
169*c3a20c19Sdan 
170*c3a20c19Sdan   /* flush_partition: */
171*c3a20c19Sdan   sqlite3VdbeResolveLabel(v, addrFlushPart);
172*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
173*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_OpenDup, csrPrec, pMWin->iEphCsr);
174*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_OpenDup, csrFollow, pMWin->iEphCsr);
175*c3a20c19Sdan 
176*c3a20c19Sdan   sqlite3ExprCode(pParse, pMWin->pStart, regPrec);
177*c3a20c19Sdan   sqlite3ExprCode(pParse, pMWin->pEnd, regFollow);
178*c3a20c19Sdan 
179*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Null, 0, pMWin->regResult);
180*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Null, 0, pMWin->regAccum);
181*c3a20c19Sdan 
182*c3a20c19Sdan   /* If either regPrec or regFollow are not non-negative integers, throw an
183*c3a20c19Sdan   ** exception.  */
184*c3a20c19Sdan   windowCheckFrameValue(pParse, regPrec, 0);
185*c3a20c19Sdan   windowCheckFrameValue(pParse, regFollow, 1);
186*c3a20c19Sdan 
187*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, addrDone);
188*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Rewind, csrPrec, addrDone);
189*c3a20c19Sdan   sqlite3VdbeChangeP5(v, 1);
190*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Rewind, csrFollow, addrDone);
191*c3a20c19Sdan   sqlite3VdbeChangeP5(v, 1);
192*c3a20c19Sdan 
193*c3a20c19Sdan   /* Invoke AggStep function for each window function using the row that
194*c3a20c19Sdan   ** csrFollow currently points to. Or, if csrFollow is already at EOF,
195*c3a20c19Sdan   ** do nothing.  */
196*c3a20c19Sdan   addrNext = sqlite3VdbeCurrentAddr(v);
197*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Next, csrFollow, addrNext+2);
198*c3a20c19Sdan   sqlite3VdbeAddOp0(v, OP_Goto);
199*c3a20c19Sdan   for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
200*c3a20c19Sdan     int i;
201*c3a20c19Sdan     for(i=0; i<pWin->nArg; i++){
202*c3a20c19Sdan       sqlite3VdbeAddOp3(v, OP_Column, csrFollow, pWin->iArgCol+i, reg+i);
203*c3a20c19Sdan     }
204*c3a20c19Sdan     sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg, pWin->regAccum);
205*c3a20c19Sdan     sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
206*c3a20c19Sdan     sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
207*c3a20c19Sdan   }
208*c3a20c19Sdan   sqlite3VdbeJumpHere(v, addrNext+1);
209*c3a20c19Sdan 
210*c3a20c19Sdan   addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regFollow, 0 , 1);
211*c3a20c19Sdan   for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
212*c3a20c19Sdan     sqlite3VdbeAddOp3(v,
213*c3a20c19Sdan         OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult
214*c3a20c19Sdan     );
215*c3a20c19Sdan     sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
216*c3a20c19Sdan   }
217*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
218*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2);
219*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone);
220*c3a20c19Sdan 
221*c3a20c19Sdan   addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regPrec, 0 , 1);
222*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Next, csrPrec, sqlite3VdbeCurrentAddr(v)+1);
223*c3a20c19Sdan   for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
224*c3a20c19Sdan     int i;
225*c3a20c19Sdan     for(i=0; i<pWin->nArg; i++){
226*c3a20c19Sdan       sqlite3VdbeAddOp3(v, OP_Column, csrPrec, pWin->iArgCol+i, reg+i);
227*c3a20c19Sdan     }
228*c3a20c19Sdan     sqlite3VdbeAddOp3(v, OP_AggStep0, 1, reg, pWin->regAccum);
229*c3a20c19Sdan     sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
230*c3a20c19Sdan     sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
231*c3a20c19Sdan   }
232*c3a20c19Sdan   sqlite3VdbeJumpHere(v, addrIfPos2);
233*c3a20c19Sdan 
234*c3a20c19Sdan   sqlite3VdbeJumpHere(v, addrIfPos1);
235*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
236*c3a20c19Sdan 
237*c3a20c19Sdan   /* flush_partition_done: */
238*c3a20c19Sdan   sqlite3VdbeResolveLabel(v, addrDone);
239*c3a20c19Sdan   sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
240*c3a20c19Sdan   sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
241*c3a20c19Sdan 
242*c3a20c19Sdan   /* Jump to here to skip over flush_partition */
243*c3a20c19Sdan   sqlite3VdbeJumpHere(v, addrGoto);
244*c3a20c19Sdan }
245*c3a20c19Sdan 
246*c3a20c19Sdan static void windowCodeDefaultStep(
247*c3a20c19Sdan   Parse *pParse,
248*c3a20c19Sdan   Select *p,
249*c3a20c19Sdan   WhereInfo *pWInfo,
250*c3a20c19Sdan   int regGosub,
251*c3a20c19Sdan   int addrGosub
252*c3a20c19Sdan ){
253*c3a20c19Sdan   Window *pMWin = p->pWin;
254*c3a20c19Sdan   Vdbe *v = sqlite3GetVdbe(pParse);
255*c3a20c19Sdan   Window *pWin;
256*c3a20c19Sdan   int k;
257*c3a20c19Sdan   int iSubCsr = p->pSrc->a[0].iCursor;
258*c3a20c19Sdan   int nSub = p->pSrc->a[0].pTab->nCol;
259*c3a20c19Sdan   int reg = pParse->nMem+1;
260*c3a20c19Sdan   int regRecord = reg+nSub;
261*c3a20c19Sdan   int regRowid = regRecord+1;
262*c3a20c19Sdan   int addr;
263*c3a20c19Sdan 
264*c3a20c19Sdan   pParse->nMem += nSub + 2;
265*c3a20c19Sdan 
266*c3a20c19Sdan   /* Martial the row returned by the sub-select into an array of
267*c3a20c19Sdan   ** registers. */
268*c3a20c19Sdan   for(k=0; k<nSub; k++){
269*c3a20c19Sdan     sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
270*c3a20c19Sdan   }
271*c3a20c19Sdan 
272*c3a20c19Sdan   /* Check if this is the start of a new partition or peer group. */
273*c3a20c19Sdan   if( pMWin->regPart ){
274*c3a20c19Sdan     ExprList *pPart = pMWin->pPartition;
275*c3a20c19Sdan     int nPart = (pPart ? pPart->nExpr : 0);
276*c3a20c19Sdan     ExprList *pOrderBy = pMWin->pOrderBy;
277*c3a20c19Sdan     int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
278*c3a20c19Sdan     int addrGoto = 0;
279*c3a20c19Sdan     int addrJump = 0;
280*c3a20c19Sdan 
281*c3a20c19Sdan     if( pPart ){
282*c3a20c19Sdan       int regNewPart = reg + pMWin->nBufferCol;
283*c3a20c19Sdan       KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
284*c3a20c19Sdan       addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
285*c3a20c19Sdan       sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
286*c3a20c19Sdan       addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
287*c3a20c19Sdan       for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
288*c3a20c19Sdan         sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
289*c3a20c19Sdan         sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
290*c3a20c19Sdan         sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
291*c3a20c19Sdan       }
292*c3a20c19Sdan       if( pOrderBy ){
293*c3a20c19Sdan         addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
294*c3a20c19Sdan       }
295*c3a20c19Sdan     }
296*c3a20c19Sdan 
297*c3a20c19Sdan     if( pOrderBy ){
298*c3a20c19Sdan       int regNewPeer = reg + pMWin->nBufferCol + nPart;
299*c3a20c19Sdan       int regPeer = pMWin->regPart + nPart;
300*c3a20c19Sdan 
301*c3a20c19Sdan       KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
302*c3a20c19Sdan       if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
303*c3a20c19Sdan       addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer);
304*c3a20c19Sdan       sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
305*c3a20c19Sdan       addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
306*c3a20c19Sdan       for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
307*c3a20c19Sdan         sqlite3VdbeAddOp3(v,
308*c3a20c19Sdan             OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult
309*c3a20c19Sdan         );
310*c3a20c19Sdan         sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
311*c3a20c19Sdan       }
312*c3a20c19Sdan       if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto);
313*c3a20c19Sdan     }
314*c3a20c19Sdan 
315*c3a20c19Sdan     sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
316*c3a20c19Sdan     sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
317*c3a20c19Sdan     sqlite3VdbeAddOp3(
318*c3a20c19Sdan         v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1
319*c3a20c19Sdan     );
320*c3a20c19Sdan 
321*c3a20c19Sdan     sqlite3VdbeJumpHere(v, addrJump);
322*c3a20c19Sdan   }
323*c3a20c19Sdan 
324*c3a20c19Sdan   /* Invoke step function for window functions */
325*c3a20c19Sdan   for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
326*c3a20c19Sdan     sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg+pWin->iArgCol, pWin->regAccum);
327*c3a20c19Sdan     sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
328*c3a20c19Sdan     sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
329*c3a20c19Sdan   }
330*c3a20c19Sdan 
331*c3a20c19Sdan   /* Buffer the current row in the ephemeral table. */
332*c3a20c19Sdan   if( pMWin->nBufferCol>0 ){
333*c3a20c19Sdan     sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord);
334*c3a20c19Sdan   }else{
335*c3a20c19Sdan     sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord);
336*c3a20c19Sdan     sqlite3VdbeAppendP4(v, (void*)"", 0);
337*c3a20c19Sdan   }
338*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
339*c3a20c19Sdan   sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
340*c3a20c19Sdan 
341*c3a20c19Sdan   /* End the database scan loop. */
342*c3a20c19Sdan   sqlite3WhereEnd(pWInfo);
343*c3a20c19Sdan 
344*c3a20c19Sdan   for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
345*c3a20c19Sdan     sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
346*c3a20c19Sdan     sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
347*c3a20c19Sdan     sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
348*c3a20c19Sdan   }
349*c3a20c19Sdan   sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
350*c3a20c19Sdan }
351*c3a20c19Sdan 
352*c3a20c19Sdan 
353f9eae18bSdan /*
354f9eae18bSdan ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
355f9eae18bSdan **
356f9eae18bSdan **   ...
357f9eae18bSdan **     if( new partition ){
358f9eae18bSdan **       AggFinal (xFinalize)
359f9eae18bSdan **       Gosub addrGosub
360f9eae18bSdan **       ResetSorter eph-table
361f9eae18bSdan **     }
362f9eae18bSdan **     else if( new peer ){
363f9eae18bSdan **       AggFinal (xValue)
364f9eae18bSdan **       Gosub addrGosub
365f9eae18bSdan **       ResetSorter eph-table
366f9eae18bSdan **     }
367f9eae18bSdan **     AggStep
368f9eae18bSdan **     Insert (record into eph-table)
369f9eae18bSdan **   sqlite3WhereEnd()
370f9eae18bSdan **   AggFinal (xFinalize)
371f9eae18bSdan **   Gosub addrGosub
372f9eae18bSdan **
373f9eae18bSdan ** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
374f9eae18bSdan **
375f9eae18bSdan **   As above, except take no action for a "new peer". Invoke
376f9eae18bSdan **   the sub-routine once only for each partition.
377f9eae18bSdan **
378f9eae18bSdan ** RANGE BETWEEN CURRENT ROW AND CURRENT ROW
379f9eae18bSdan **
380f9eae18bSdan **   As above, except that the "new peer" condition is handled in the
381f9eae18bSdan **   same way as "new partition" (so there is no "else if" block).
382f9eae18bSdan **
383f9eae18bSdan ** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
384f9eae18bSdan **
385f9eae18bSdan **   One way is to just reverse the sort order and do as for BETWEEN
386f9eae18bSdan **   UNBOUNDED PRECEDING AND CURRENT ROW. But that is not quite the same for
387f9eae18bSdan **   things like group_concat(). And perhaps other user defined aggregates
388f9eae18bSdan **   as well.
389f9eae18bSdan **
390f9eae18bSdan **   ...
391f9eae18bSdan **     if( new partition ){
392f9eae18bSdan **       Gosub flush_partition;
393f9eae18bSdan **       ResetSorter eph-table
394f9eae18bSdan **     }
395f9eae18bSdan **     AggStep
396f9eae18bSdan **     Insert (record into eph-table)
397f9eae18bSdan **   sqlite3WhereEnd()
398f9eae18bSdan **   Gosub flush_partition
399f9eae18bSdan **
400f9eae18bSdan **  flush_partition:
401f9eae18bSdan **   OpenDup (csr -> csr2)
402f9eae18bSdan **   foreach (record in eph-table) {
403f9eae18bSdan **     if( new peer ){
404f9eae18bSdan **       while( csr2!=csr ){
405f9eae18bSdan **         AggStep (xInverse)
406f9eae18bSdan **         Next (csr2)
407f9eae18bSdan **       }
408f9eae18bSdan **     }
409f9eae18bSdan **     AggFinal (xValue)
410f9eae18bSdan **     Gosub addrGosub
411f9eae18bSdan **   }
412f9eae18bSdan **
413f9eae18bSdan **========================================================================
414f9eae18bSdan **
415f9eae18bSdan ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
416f9eae18bSdan **   ...
417f9eae18bSdan **     if( new partition ){
418f9eae18bSdan **       AggFinal (xFinalize)
419f9eae18bSdan **     }
420f9eae18bSdan **     AggStep
421f9eae18bSdan **     AggFinal (xValue)
422f9eae18bSdan **     Gosub addrGosub
423f9eae18bSdan **   sqlite3WhereEnd()
424f9eae18bSdan **
425f9eae18bSdan ** ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
426f9eae18bSdan ** ROWS BETWEEN CURRENT ROW AND CURRENT ROW
427f9eae18bSdan ** ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
428f9eae18bSdan **
429f9eae18bSdan **========================================================================
430f9eae18bSdan **
431f9eae18bSdan ** ROWS BETWEEN <expr> PRECEDING    AND <expr> FOLLOWING
432f9eae18bSdan **
433f9eae18bSdan **   ...
4348471be33Sdan **     if( new partition ){
4358471be33Sdan **       Gosub flush_partition
4368471be33Sdan **     }
437f9eae18bSdan **     Insert (record in eph-table)
438f9eae18bSdan **   sqlite3WhereEnd()
4398471be33Sdan **   Gosub flush_partition
4408471be33Sdan **
4418471be33Sdan ** flush_partition:
4428471be33Sdan **   OpenDup (csr -> csr2)
4438471be33Sdan **   OpenDup (csr -> csr3)
4448471be33Sdan **   regPrec = <expr1>            // PRECEDING expression
4458471be33Sdan **   regFollow = <expr2>          // FOLLOWING expression
4468471be33Sdan **   if( regPrec<0 || regFollow<0 ) throw exception!
4478471be33Sdan **   Rewind (csr,csr2,csr3)       // if EOF goto flush_partition_done
4488471be33Sdan **     Aggstep (csr3)
4498471be33Sdan **     Next(csr3)                 // if EOF fall-through
4508471be33Sdan **     if( (regFollow--)<=0 ){
4518471be33Sdan **       AggFinal (xValue)
4528471be33Sdan **       Gosub addrGosub
4538471be33Sdan **       Next(csr)                // if EOF goto flush_partition_done
4548471be33Sdan **       if( (regPrec--)<=0 ){
4558471be33Sdan **         AggStep (csr2, xInverse)
4568471be33Sdan **         Next(csr2)
4578471be33Sdan **       }
4588471be33Sdan **     }
4598471be33Sdan ** flush_partition_done:
4608471be33Sdan **   Close (csr2)
4618471be33Sdan **   Close (csr3)
4628471be33Sdan **   ResetSorter (csr)
4638471be33Sdan **   Return
4648471be33Sdan **
4658471be33Sdan ** ROWS BETWEEN <expr> PRECEDING    AND CURRENT ROW
4668471be33Sdan ** ROWS BETWEEN CURRENT ROW         AND <expr> FOLLOWING
4678471be33Sdan ** ROWS BETWEEN <expr> PRECEDING    AND UNBOUNDED FOLLOWING
4688471be33Sdan ** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> FOLLOWING
4698471be33Sdan **
4708471be33Sdan **   These are similar to the above. For "CURRENT ROW", intialize the
4718471be33Sdan **   register to 0. For "UNBOUNDED ..." to infinity.
4728471be33Sdan **
4738471be33Sdan ** ROWS BETWEEN <expr> PRECEDING    AND <expr> PRECEDING
4748471be33Sdan **
4758471be33Sdan **   Replace the bit after "Rewind" in the above with:
4768471be33Sdan **
4778471be33Sdan **     if( (regFollow--)<=0 ){
4788471be33Sdan **       AggStep (csr3)
4798471be33Sdan **       Next (csr3)
4808471be33Sdan **     }
4818471be33Sdan **     AggFinal (xValue)
4828471be33Sdan **     Gosub addrGosub
4838471be33Sdan **     Next(csr)                  // if EOF goto flush_partition_done
4848471be33Sdan **     if( (regPrec--)<=0 ){
4858471be33Sdan **       AggStep (csr2, xInverse)
4868471be33Sdan **       Next (csr2)
4878471be33Sdan **     }
4888471be33Sdan **
4898471be33Sdan ** ROWS BETWEEN <expr> FOLLOWING    AND <expr> FOLLOWING
4908471be33Sdan **
4918471be33Sdan **   regFollow = regFollow - regPrec
4928471be33Sdan **   Rewind (csr,csr2,csr3)       // if EOF goto flush_partition_done
4938471be33Sdan **     Aggstep (csr3)
4948471be33Sdan **     Next(csr3)                 // if EOF fall-through
4958471be33Sdan **     if( (regFollow--)<=0 ){
4968471be33Sdan **       AggStep (csr2, xInverse)
4978471be33Sdan **       Next (csr2)
4988471be33Sdan **       if( (regPrec--)<=0 ){
4998471be33Sdan **         AggFinal (xValue)
5008471be33Sdan **         Gosub addrGosub
5018471be33Sdan **         Next(csr)              // if EOF goto flush_partition_done
5028471be33Sdan **       }
5038471be33Sdan **     }
5048471be33Sdan **
5058471be33Sdan ** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> PRECEDING
5068471be33Sdan ** ROWS BETWEEN <expr> FOLLOWING    AND UNBOUNDED FOLLOWING
5078471be33Sdan **
5088471be33Sdan **   Similar to the above, except with regPrec or regFollow set to infinity,
5098471be33Sdan **   as appropriate.
5108471be33Sdan **
5118471be33Sdan **
512f9eae18bSdan **
513f9eae18bSdan */
514f9eae18bSdan void sqlite3WindowCodeStep(
515f9eae18bSdan   Parse *pParse,
516f9eae18bSdan   Select *p,
517f9eae18bSdan   WhereInfo *pWInfo,
518f9eae18bSdan   int regGosub,
519*c3a20c19Sdan   int addrGosub,
520*c3a20c19Sdan   int *pbLoop
521f9eae18bSdan ){
522f9eae18bSdan   Window *pMWin = p->pWin;
523f9eae18bSdan 
524*c3a20c19Sdan   if( pMWin->eType==TK_ROWS
525*c3a20c19Sdan    && pMWin->eStart==TK_PRECEDING
526*c3a20c19Sdan    && pMWin->eEnd==TK_FOLLOWING
527*c3a20c19Sdan   ){
528*c3a20c19Sdan     *pbLoop = 0;
529*c3a20c19Sdan     windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
530*c3a20c19Sdan     return;
531f9eae18bSdan   }
532f9eae18bSdan 
533*c3a20c19Sdan   *pbLoop = 1;
534*c3a20c19Sdan   windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub);
535f9eae18bSdan }
536f9eae18bSdan 
537e2f781b9Sdan 
538