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