/ Check-in [ec2f207d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improved TreeView display of Window objects. Change the Window.eType field to Window.eFrmType to avoid confusion with other "eType" values.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: ec2f207dedb223077bbd3e4584499250eb12219712c917e930acccfa2c46e23b
User & Date: drh 2019-03-28 13:03:41
Context
2019-03-28
13:35
More improvements to TreeView output for Window objects: (1) Show when the frame-spec is implied rather than explicit. (2) Move the FILTER clause out from within the OVER clause, making it a sibling of the OVER clause, to match syntax. check-in: d6a07433 user: drh tags: trunk
13:03
Improved TreeView display of Window objects. Change the Window.eType field to Window.eFrmType to avoid confusion with other "eType" values. check-in: ec2f207d user: drh tags: trunk
04:03
If the string formatter in sqlite3NestedParse() fails due to an over-length string, make sure this error is recorded by the parser so that it knows to fail. check-in: 85e53ff1 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/sqliteInt.h.

  3531   3531   struct TreeView {
  3532   3532     int iLevel;             /* Which level of the tree we are on */
  3533   3533     u8  bLine[100];         /* Draw vertical in column i if bLine[i] is true */
  3534   3534   };
  3535   3535   #endif /* SQLITE_DEBUG */
  3536   3536   
  3537   3537   /*
  3538         -** This object is used in varioius ways, all related to window functions
         3538  +** This object is used in various ways, all related to window functions
  3539   3539   **
  3540   3540   **   (1) A single instance of this structure is attached to the
  3541   3541   **       the Expr.pWin field for each window function in an expression tree.
  3542   3542   **       This object holds the information contained in the OVER clause,
  3543   3543   **       plus additional fields used during code generation.
  3544   3544   **
  3545   3545   **   (2) All window functions in a single SELECT form a linked-list
................................................................................
  3546   3546   **       attached to Select.pWin.  The Window.pFunc and Window.pExpr
  3547   3547   **       fields point back to the expression that is the window function.
  3548   3548   **
  3549   3549   **   (3) The terms of the WINDOW clause of a SELECT are instances of this
  3550   3550   **       object on a linked list attached to Select.pWinDefn.
  3551   3551   **
  3552   3552   ** The uses (1) and (2) are really the same Window object that just happens
  3553         -** to be accessible in two different ways.  Use (3) is are separate objects.
         3553  +** to be accessible in two different ways.  Use case (3) are separate objects.
  3554   3554   */
  3555   3555   struct Window {
  3556   3556     char *zName;            /* Name of window (may be NULL) */
  3557   3557     char *zBase;            /* Name of base window for chaining (may be NULL) */
  3558   3558     ExprList *pPartition;   /* PARTITION BY clause */
  3559   3559     ExprList *pOrderBy;     /* ORDER BY clause */
  3560         -  u8 eType;               /* TK_RANGE or TK_ROWS */
         3560  +  u8 eFrmType;            /* TK_RANGE, TK_GROUPS, TK_ROWS, or 0 */
  3561   3561     u8 eStart;              /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
  3562   3562     u8 eEnd;                /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
  3563   3563     u8 bImplicitFrame;      /* True if frame was implicitly specified */
  3564         -  u8 eExclude;
         3564  +  u8 eExclude;            /* TK_NO, TK_CURRENT, TK_TIES, TK_GROUP, or 0 */
  3565   3565     Expr *pStart;           /* Expression for "<expr> PRECEDING" */
  3566   3566     Expr *pEnd;             /* Expression for "<expr> FOLLOWING" */
  3567   3567     Window *pNextWin;       /* Next window function belonging to this SELECT */
  3568   3568     Expr *pFilter;          /* The FILTER expression */
  3569   3569     FuncDef *pFunc;         /* The function */
  3570   3570     int iEphCsr;            /* Partition buffer or Peer buffer */
  3571   3571     int regAccum;

Changes to src/treeview.c.

   305    305   #endif /* SQLITE_OMIT_WINDOWFUNC */
   306    306   
   307    307   #ifndef SQLITE_OMIT_WINDOWFUNC
   308    308   /*
   309    309   ** Generate a human-readable explanation for a Window object
   310    310   */
   311    311   void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
          312  +  int nElement = 0;
   312    313     pView = sqlite3TreeViewPush(pView, more);
   313    314     if( pWin->zName ){
   314    315       sqlite3TreeViewLine(pView, "OVER %s", pWin->zName);
   315    316     }else{
   316    317       sqlite3TreeViewLine(pView, "OVER");
   317    318     }
          319  +  if( pWin->pFilter )  nElement++;
          320  +  if( pWin->zBase )    nElement++;
          321  +  if( pWin->pOrderBy ) nElement++;
          322  +  if( pWin->eFrmType ) nElement++;
          323  +  if( pWin->eExclude ) nElement++;
          324  +  if( pWin->pFilter ){
          325  +    sqlite3TreeViewItem(pView, "FILTER", (--nElement)>0);
          326  +    sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
          327  +    sqlite3TreeViewPop(pView);
          328  +  }
          329  +  if( pWin->zBase ){
          330  +    sqlite3TreeViewPush(pView, (--nElement)>0);
          331  +    sqlite3TreeViewLine(pView, "window: %s", pWin->zBase);
          332  +    sqlite3TreeViewPop(pView);
          333  +  }
   318    334     if( pWin->pPartition ){
   319         -    sqlite3TreeViewExprList(pView, pWin->pPartition, 1, "PARTITION-BY");
          335  +    sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY");
   320    336     }
   321    337     if( pWin->pOrderBy ){
   322         -    sqlite3TreeViewExprList(pView, pWin->pOrderBy, 1, "ORDER-BY");
          338  +    sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY");
   323    339     }
   324         -  if( pWin->eType ){
   325         -    sqlite3TreeViewItem(pView, pWin->eType==TK_RANGE ? "RANGE" : "ROWS", 0);
          340  +  if( pWin->eFrmType ){
          341  +    const char *zFrmType = "ROWS";
          342  +    if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE";
          343  +    if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS";
          344  +    sqlite3TreeViewItem(pView, zFrmType, (--nElement)>0);
   326    345       sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
   327    346       sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
   328    347       sqlite3TreeViewPop(pView);
   329    348     }
          349  +  if( pWin->eExclude ){
          350  +    char zBuf[30];
          351  +    const char *zExclude;
          352  +    switch( pWin->eExclude ){
          353  +      case TK_NO:      zExclude = "NO OTHERS";   break;
          354  +      case TK_CURRENT: zExclude = "CURRENT ROW"; break;
          355  +      case TK_GROUP:   zExclude = "GROUP";       break;
          356  +      case TK_TIES:    zExclude = "TIES";        break;
          357  +      default:
          358  +        sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude);
          359  +        zExclude = zBuf;
          360  +        break;
          361  +    }
          362  +    sqlite3TreeViewPush(pView, 0);
          363  +    sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude);
          364  +    sqlite3TreeViewPop(pView);
          365  +  }
   330    366     sqlite3TreeViewPop(pView);
   331    367   }
   332    368   #endif /* SQLITE_OMIT_WINDOWFUNC */
   333    369   
   334    370   #ifndef SQLITE_OMIT_WINDOWFUNC
   335    371   /*
   336    372   ** Generate a human-readable explanation for a Window Function object

Changes to src/window.c.

   658    658   */
   659    659   void sqlite3WindowUpdate(
   660    660     Parse *pParse, 
   661    661     Window *pList,                  /* List of named windows for this SELECT */
   662    662     Window *pWin,                   /* Window frame to update */
   663    663     FuncDef *pFunc                  /* Window function definition */
   664    664   ){
   665         -  if( pWin->zName && pWin->eType==0 ){
          665  +  if( pWin->zName && pWin->eFrmType==0 ){
   666    666       Window *p = windowFind(pParse, pList, pWin->zName);
   667    667       if( p==0 ) return;
   668    668       pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0);
   669    669       pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0);
   670    670       pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0);
   671    671       pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0);
   672    672       pWin->eStart = p->eStart;
   673    673       pWin->eEnd = p->eEnd;
   674         -    pWin->eType = p->eType;
          674  +    pWin->eFrmType = p->eFrmType;
   675    675       pWin->eExclude = p->eExclude;
   676    676     }else{
   677    677       sqlite3WindowChain(pParse, pWin, pList);
   678    678     }
   679         -  if( (pWin->eType==TK_RANGE)
          679  +  if( (pWin->eFrmType==TK_RANGE)
   680    680      && (pWin->pStart || pWin->pEnd) 
   681    681      && (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1)
   682    682     ){
   683    683       sqlite3ErrorMsg(pParse, 
   684    684         "RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression"
   685    685       );
   686    686     }else
................................................................................
   689    689       if( pWin->pFilter ){
   690    690         sqlite3ErrorMsg(pParse, 
   691    691             "FILTER clause may only be used with aggregate window functions"
   692    692         );
   693    693       }else{
   694    694         struct WindowUpdate {
   695    695           const char *zFunc;
   696         -        int eType;
          696  +        int eFrmType;
   697    697           int eStart;
   698    698           int eEnd;
   699    699         } aUp[] = {
   700    700           { row_numberName,   TK_ROWS,   TK_UNBOUNDED, TK_CURRENT }, 
   701    701           { dense_rankName,   TK_RANGE,  TK_UNBOUNDED, TK_CURRENT }, 
   702    702           { rankName,         TK_RANGE,  TK_UNBOUNDED, TK_CURRENT }, 
   703    703           { percent_rankName, TK_GROUPS, TK_CURRENT,   TK_UNBOUNDED }, 
................................................................................
   708    708         };
   709    709         int i;
   710    710         for(i=0; i<ArraySize(aUp); i++){
   711    711           if( pFunc->zName==aUp[i].zFunc ){
   712    712             sqlite3ExprDelete(db, pWin->pStart);
   713    713             sqlite3ExprDelete(db, pWin->pEnd);
   714    714             pWin->pEnd = pWin->pStart = 0;
   715         -          pWin->eType = aUp[i].eType;
          715  +          pWin->eFrmType = aUp[i].eFrmType;
   716    716             pWin->eStart = aUp[i].eStart;
   717    717             pWin->eEnd = aUp[i].eEnd;
   718    718             pWin->eExclude = 0;
   719    719             if( pWin->eStart==TK_FOLLOWING ){
   720    720               pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1");
   721    721             }
   722    722             break;
................................................................................
  1038   1038   }
  1039   1039   
  1040   1040   /*
  1041   1041   ** Allocate and return a new Window object describing a Window Definition.
  1042   1042   */
  1043   1043   Window *sqlite3WindowAlloc(
  1044   1044     Parse *pParse,    /* Parsing context */
  1045         -  int eType,        /* Frame type. TK_RANGE or TK_ROWS */
         1045  +  int eType,        /* Frame type. TK_RANGE, TK_ROWS, TK_GROUPS, or 0 */
  1046   1046     int eStart,       /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */
  1047   1047     Expr *pStart,     /* Start window size if TK_PRECEDING or FOLLOWING */
  1048   1048     int eEnd,         /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */
  1049   1049     Expr *pEnd,       /* End window size if TK_FOLLOWING or PRECEDING */
  1050   1050     u8 eExclude       /* EXCLUDE clause */
  1051   1051   ){
  1052   1052     Window *pWin = 0;
................................................................................
  1085   1085     ){
  1086   1086       sqlite3ErrorMsg(pParse, "unsupported frame specification");
  1087   1087       goto windowAllocErr;
  1088   1088     }
  1089   1089   
  1090   1090     pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
  1091   1091     if( pWin==0 ) goto windowAllocErr;
  1092         -  pWin->eType = eType;
         1092  +  pWin->eFrmType = eType;
  1093   1093     pWin->eStart = eStart;
  1094   1094     pWin->eEnd = eEnd;
  1095   1095     if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_QueryFlattener) ){
  1096   1096       eExclude = TK_NO;
  1097   1097     }
  1098   1098     pWin->eExclude = eExclude;
  1099   1099     pWin->bImplicitFrame = bImplicitFrame;
................................................................................
  1194   1194   }
  1195   1195   
  1196   1196   /*
  1197   1197   ** Return 0 if the two window objects are identical, or non-zero otherwise.
  1198   1198   ** Identical window objects can be processed in a single scan.
  1199   1199   */
  1200   1200   int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){
  1201         -  if( p1->eType!=p2->eType ) return 1;
         1201  +  if( p1->eFrmType!=p2->eFrmType ) return 1;
  1202   1202     if( p1->eStart!=p2->eStart ) return 1;
  1203   1203     if( p1->eEnd!=p2->eEnd ) return 1;
  1204   1204     if( p1->eExclude!=p2->eExclude ) return 1;
  1205   1205     if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
  1206   1206     if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
  1207   1207     if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1;
  1208   1208     if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1;
................................................................................
  1857   1857     Parse *pParse = p->pParse;
  1858   1858     Window *pMWin = p->pMWin;
  1859   1859     int ret = 0;
  1860   1860     Vdbe *v = p->pVdbe;
  1861   1861     int addrIf = 0; 
  1862   1862     int addrContinue = 0;
  1863   1863     int addrGoto = 0;
  1864         -  int bPeer = (pMWin->eType!=TK_ROWS);
         1864  +  int bPeer = (pMWin->eFrmType!=TK_ROWS);
  1865   1865   
  1866   1866     int lblDone = sqlite3VdbeMakeLabel(pParse);
  1867   1867     int addrNextRange = 0;
  1868   1868   
  1869   1869     /* Special case - WINDOW_AGGINVERSE is always a no-op if the frame
  1870   1870     ** starts with UNBOUNDED PRECEDING. */
  1871   1871     if( op==WINDOW_AGGINVERSE && pMWin->eStart==TK_UNBOUNDED ){
  1872   1872       assert( regCountdown==0 && jumpOnEof==0 );
  1873   1873       return 0;
  1874   1874     }
  1875   1875   
  1876   1876     if( regCountdown>0 ){
  1877         -    if( pMWin->eType==TK_RANGE ){
         1877  +    if( pMWin->eFrmType==TK_RANGE ){
  1878   1878         addrNextRange = sqlite3VdbeCurrentAddr(v);
  1879   1879         assert( op==WINDOW_AGGINVERSE || op==WINDOW_AGGSTEP );
  1880   1880         if( op==WINDOW_AGGINVERSE ){
  1881   1881           if( pMWin->eStart==TK_FOLLOWING ){
  1882   1882             windowCodeRangeTest(
  1883   1883                 p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone
  1884   1884             );
................................................................................
  1979   1979       pNew = sqlite3DbMallocZero(db, sizeof(Window));
  1980   1980       if( pNew ){
  1981   1981         pNew->zName = sqlite3DbStrDup(db, p->zName);
  1982   1982         pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0);
  1983   1983         pNew->pFunc = p->pFunc;
  1984   1984         pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0);
  1985   1985         pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0);
  1986         -      pNew->eType = p->eType;
         1986  +      pNew->eFrmType = p->eFrmType;
  1987   1987         pNew->eEnd = p->eEnd;
  1988   1988         pNew->eStart = p->eStart;
  1989   1989         pNew->eExclude = p->eExclude;
  1990   1990         pNew->pStart = sqlite3ExprDup(db, p->pStart, 0);
  1991   1991         pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0);
  1992   1992         pNew->pOwner = pOwner;
  1993   1993       }
................................................................................
  2423   2423     ** are four options - they may never be deleted (eDelete==0), they may 
  2424   2424     ** be deleted as soon as they are no longer part of the window frame
  2425   2425     ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row 
  2426   2426     ** has been returned to the caller (WINDOW_RETURN_ROW), or they may
  2427   2427     ** be deleted after they enter the frame (WINDOW_AGGSTEP). */
  2428   2428     switch( pMWin->eStart ){
  2429   2429       case TK_FOLLOWING:
  2430         -      if( pMWin->eType!=TK_RANGE && windowExprGtZero(pParse, pMWin->pStart) ){
         2430  +      if( pMWin->eFrmType!=TK_RANGE
         2431  +       && windowExprGtZero(pParse, pMWin->pStart)
         2432  +      ){
  2431   2433           s.eDelete = WINDOW_RETURN_ROW;
  2432   2434         }
  2433   2435         break;
  2434   2436       case TK_UNBOUNDED:
  2435   2437         if( windowCacheFrame(pMWin)==0 ){
  2436   2438           if( pMWin->eEnd==TK_PRECEDING ){
  2437         -          if( pMWin->eType!=TK_RANGE && windowExprGtZero(pParse, pMWin->pEnd) ){
         2439  +          if( pMWin->eFrmType!=TK_RANGE
         2440  +           && windowExprGtZero(pParse, pMWin->pEnd)
         2441  +          ){
  2438   2442               s.eDelete = WINDOW_AGGSTEP;
  2439   2443             }
  2440   2444           }else{
  2441   2445             s.eDelete = WINDOW_RETURN_ROW;
  2442   2446           }
  2443   2447         }
  2444   2448         break;
................................................................................
  2464   2468     if( pMWin->eEnd==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING ){
  2465   2469       regEnd = ++pParse->nMem;
  2466   2470     }
  2467   2471   
  2468   2472     /* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of
  2469   2473     ** registers to store copies of the ORDER BY expressions (peer values) 
  2470   2474     ** for the main loop, and for each cursor (start, current and end). */
  2471         -  if( pMWin->eType!=TK_ROWS ){
         2475  +  if( pMWin->eFrmType!=TK_ROWS ){
  2472   2476       int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
  2473   2477       regNewPeer = regNew + pMWin->nBufferCol;
  2474   2478       if( pMWin->pPartition ) regNewPeer += pMWin->pPartition->nExpr;
  2475   2479       regPeer = pParse->nMem+1;       pParse->nMem += nPeer;
  2476   2480       s.start.reg = pParse->nMem+1;   pParse->nMem += nPeer;
  2477   2481       s.current.reg = pParse->nMem+1; pParse->nMem += nPeer;
  2478   2482       s.end.reg = pParse->nMem+1;     pParse->nMem += nPeer;
................................................................................
  2515   2519     VdbeCoverage(v);
  2516   2520   
  2517   2521     /* This block is run for the first row of each partition */
  2518   2522     s.regArg = windowInitAccum(pParse, pMWin);
  2519   2523   
  2520   2524     if( regStart ){
  2521   2525       sqlite3ExprCode(pParse, pMWin->pStart, regStart);
  2522         -    windowCheckValue(pParse, regStart, 0 + (pMWin->eType==TK_RANGE ? 3 : 0));
         2526  +    windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE ? 3 : 0));
  2523   2527     }
  2524   2528     if( regEnd ){
  2525   2529       sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
  2526         -    windowCheckValue(pParse, regEnd, 1 + (pMWin->eType==TK_RANGE ? 3 : 0));
         2530  +    windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE ? 3 : 0));
  2527   2531     }
  2528   2532   
  2529   2533     if( pMWin->eStart==pMWin->eEnd && regStart ){
  2530   2534       int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
  2531   2535       int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
  2532   2536       VdbeCoverage(v);
  2533   2537       windowAggFinal(&s, 0);
................................................................................
  2534   2538       sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
  2535   2539       VdbeCoverageNeverTaken(v);
  2536   2540       windowReturnOneRow(&s);
  2537   2541       sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr);
  2538   2542       sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd);
  2539   2543       sqlite3VdbeJumpHere(v, addrGe);
  2540   2544     }
  2541         -  if( pMWin->eStart==TK_FOLLOWING && pMWin->eType!=TK_RANGE && regEnd ){
         2545  +  if( pMWin->eStart==TK_FOLLOWING && pMWin->eFrmType!=TK_RANGE && regEnd ){
  2542   2546       assert( pMWin->eEnd==TK_FOLLOWING );
  2543   2547       sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart);
  2544   2548     }
  2545   2549   
  2546   2550     if( pMWin->eStart!=TK_UNBOUNDED ){
  2547   2551       sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1);
  2548   2552       VdbeCoverageNeverTaken(v);
................................................................................
  2563   2567     sqlite3VdbeJumpHere(v, addrNe);
  2564   2568     if( regPeer ){
  2565   2569       windowIfNewPeer(pParse, pOrderBy, regNewPeer, regPeer, lblWhereEnd);
  2566   2570     }
  2567   2571     if( pMWin->eStart==TK_FOLLOWING ){
  2568   2572       windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0);
  2569   2573       if( pMWin->eEnd!=TK_UNBOUNDED ){
  2570         -      if( pMWin->eType==TK_RANGE ){
         2574  +      if( pMWin->eFrmType==TK_RANGE ){
  2571   2575           int lbl = sqlite3VdbeMakeLabel(pParse);
  2572   2576           int addrNext = sqlite3VdbeCurrentAddr(v);
  2573   2577           windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl);
  2574   2578           windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
  2575   2579           windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
  2576   2580           sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
  2577   2581           sqlite3VdbeResolveLabel(v, lbl);
................................................................................
  2585   2589       windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0);
  2586   2590       windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
  2587   2591       windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
  2588   2592     }else{
  2589   2593       int addr = 0;
  2590   2594       windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0);
  2591   2595       if( pMWin->eEnd!=TK_UNBOUNDED ){
  2592         -      if( pMWin->eType==TK_RANGE ){
         2596  +      if( pMWin->eFrmType==TK_RANGE ){
  2593   2597           int lbl = 0;
  2594   2598           addr = sqlite3VdbeCurrentAddr(v);
  2595   2599           if( regEnd ){
  2596   2600             lbl = sqlite3VdbeMakeLabel(pParse);
  2597   2601             windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl);
  2598   2602           }
  2599   2603           windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
................................................................................
  2631   2635       windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
  2632   2636     }else if( pMWin->eStart==TK_FOLLOWING ){
  2633   2637       int addrStart;
  2634   2638       int addrBreak1;
  2635   2639       int addrBreak2;
  2636   2640       int addrBreak3;
  2637   2641       windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0);
  2638         -    if( pMWin->eType==TK_RANGE ){
         2642  +    if( pMWin->eFrmType==TK_RANGE ){
  2639   2643         addrStart = sqlite3VdbeCurrentAddr(v);
  2640   2644         addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1);
  2641   2645         addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1);
  2642   2646       }else
  2643   2647       if( pMWin->eEnd==TK_UNBOUNDED ){
  2644   2648         addrStart = sqlite3VdbeCurrentAddr(v);
  2645   2649         addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regStart, 1);