/ Check-in [7927b6b023]
Login

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

Overview
Comment:Fix a problem with window frames that use "BETWEEN <start> AND 0 PRECEDING".
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7927b6b023502e990d23f30251b5b0918b547726b863bfb6747dcd7f1f71d19a
User & Date: dan 2019-03-26 16:47:17
Context
2019-03-27
14:58
Fix harmless compiler warnings seen with MSVC. check-in: 5be64ea8e3 user: mistachkin tags: trunk
2019-03-26
16:47
Fix a problem with window frames that use "BETWEEN <start> AND 0 PRECEDING". check-in: 7927b6b023 user: dan tags: trunk
16:21
Fix harmless compiler warnings. check-in: a063f7c426 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/window.c.

2008
2009
2010
2011
2012
2013
2014




















2015
2016
2017
2018
2019
2020
2021
....
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423

2424

2425
2426
2427
2428
2429
2430
2431
    *pp = sqlite3WindowDup(db, 0, pWin);
    if( *pp==0 ) break;
    pp = &((*pp)->pNextWin);
  }

  return pRet;
}





















/*
** sqlite3WhereBegin() has already been called for the SELECT statement 
** passed as the second argument when this function is invoked. It generates
** code to populate the Window.regResult register for each window function 
** and invoke the sub-routine at instruction addrGosub once for each row.
** sqlite3WhereEnd() is always called before returning. 
................................................................................
  /* Figure out when rows may be deleted from the ephemeral table. There
  ** are four options - they may never be deleted (eDelete==0), they may 
  ** be deleted as soon as they are no longer part of the window frame
  ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row 
  ** has been returned to the caller (WINDOW_RETURN_ROW), or they may
  ** be deleted after they enter the frame (WINDOW_AGGSTEP). */
  switch( pMWin->eStart ){
    case TK_FOLLOWING: {
      if( pMWin->eType!=TK_RANGE ){
        sqlite3 *db = pParse->db;
        sqlite3_value *pVal = 0;
        sqlite3ValueFromExpr(db,pMWin->pStart,db->enc,SQLITE_AFF_NUMERIC,&pVal);
        if( pVal && sqlite3_value_int(pVal)>0 ){
          s.eDelete = WINDOW_RETURN_ROW;
        }
        sqlite3ValueFree(pVal);
      }
      break;
    }
    case TK_UNBOUNDED:
      if( windowCacheFrame(pMWin)==0 ){
        if( pMWin->eEnd==TK_PRECEDING ){

          s.eDelete = WINDOW_AGGSTEP;

        }else{
          s.eDelete = WINDOW_RETURN_ROW;
        }
      }
      break;
    default:
      s.eDelete = WINDOW_AGGINVERSE;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|
<
<
<
<
|
|
<
<

<



>
|
>







2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
....
2422
2423
2424
2425
2426
2427
2428
2429
2430




2431
2432


2433

2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
    *pp = sqlite3WindowDup(db, 0, pWin);
    if( *pp==0 ) break;
    pp = &((*pp)->pNextWin);
  }

  return pRet;
}

/*
** Return true if it can be determined at compile time that expression 
** pExpr evaluates to a value that, when cast to an integer, is greater 
** than zero. False otherwise.
**
** If an OOM error occurs, this function sets the Parse.db.mallocFailed 
** flag and returns zero.
*/
static int windowExprGtZero(Parse *pParse, Expr *pExpr){
  int ret = 0;
  sqlite3 *db = pParse->db;
  sqlite3_value *pVal = 0;
  sqlite3ValueFromExpr(db, pExpr, db->enc, SQLITE_AFF_NUMERIC, &pVal);
  if( pVal && sqlite3_value_int(pVal)>0 ){
    ret = 1;
  }
  sqlite3ValueFree(pVal);
  return ret;
}

/*
** sqlite3WhereBegin() has already been called for the SELECT statement 
** passed as the second argument when this function is invoked. It generates
** code to populate the Window.regResult register for each window function 
** and invoke the sub-routine at instruction addrGosub once for each row.
** sqlite3WhereEnd() is always called before returning. 
................................................................................
  /* Figure out when rows may be deleted from the ephemeral table. There
  ** are four options - they may never be deleted (eDelete==0), they may 
  ** be deleted as soon as they are no longer part of the window frame
  ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row 
  ** has been returned to the caller (WINDOW_RETURN_ROW), or they may
  ** be deleted after they enter the frame (WINDOW_AGGSTEP). */
  switch( pMWin->eStart ){
    case TK_FOLLOWING:
      if( pMWin->eType!=TK_RANGE && windowExprGtZero(pParse, pMWin->pStart) ){




        s.eDelete = WINDOW_RETURN_ROW;
      }


      break;

    case TK_UNBOUNDED:
      if( windowCacheFrame(pMWin)==0 ){
        if( pMWin->eEnd==TK_PRECEDING ){
          if( pMWin->eType!=TK_RANGE && windowExprGtZero(pParse, pMWin->pEnd) ){
            s.eDelete = WINDOW_AGGSTEP;
          }
        }else{
          s.eDelete = WINDOW_RETURN_ROW;
        }
      }
      break;
    default:
      s.eDelete = WINDOW_AGGINVERSE;

Changes to test/window6.test.

332
333
334
335
336
337
338
339






























340

do_execsql_test 11.2 {
  SELECT a, (SELECT y FROM t3 WHERE x=a), sum(a) OVER (ORDER BY a)
    FROM t1 ORDER BY a;
} {
  10 ten 10   15 fifteen 25   20 {} 65        20 {} 65   
  25 {} 90    30 thirty 150   30 thirty 150   50 {} 200
}































finish_test









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
do_execsql_test 11.2 {
  SELECT a, (SELECT y FROM t3 WHERE x=a), sum(a) OVER (ORDER BY a)
    FROM t1 ORDER BY a;
} {
  10 ten 10   15 fifteen 25   20 {} 65        20 {} 65   
  25 {} 90    30 thirty 150   30 thirty 150   50 {} 200
}

do_execsql_test 11.3.1 {
  SELECT a, sum(a) OVER win FROM t1
  WINDOW win AS (ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
} {
  10 10 15 25 20 45 20 65 25 90 30 120 30 150 50 200
}
do_execsql_test 11.3.2 {
  SELECT a, sum(a) OVER win FROM t1
  WINDOW win AS (ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND 0 FOLLOWING)
} {
  10 10 15 25 20 45 20 65 25 90 30 120 30 150 50 200
}
do_execsql_test 11.3.3 {
  SELECT a, sum(a) OVER win FROM t1
  WINDOW win AS (ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING)
} {
  10 10 15 25 20 45 20 65 25 90 30 120 30 150 50 200
}

do_execsql_test 11.4.1 {
  SELECT y, group_concat(y, '.') OVER win FROM t3
  WINDOW win AS (
    ORDER BY y RANGE BETWEEN UNBOUNDED PRECEDING AND 10 PRECEDING
  );
} {
  fifteen fifteen 
  ten     fifteen.ten 
  thirty  fifteen.ten.thirty
}

finish_test