/ Check-in [3e23cfc8]
Login

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

Overview
Comment:Fix problems with using window-functions in correlated sub-queries.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | exp-window-functions
Files: files | file ages | folders
SHA3-256:3e23cfc8133342a4de6813afdc33d726f06d625424b16d0999fb22be51bf8913
User & Date: dan 2018-06-23 19:29:56
Context
2018-06-25
11:42
Fix another problem that could cause a crash when a window function was used in a view. check-in: e954145a user: dan tags: exp-window-functions
2018-06-23
19:29
Fix problems with using window-functions in correlated sub-queries. check-in: 3e23cfc8 user: dan tags: exp-window-functions
16:26
Fix a problem with using LIMIT in window-function queries. check-in: c1abd2dd user: dan tags: exp-window-functions
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/resolve.c.

770
771
772
773
774
775
776
777
778
779
780
781
782
783








784
785
786
787
788
789
790
791
792
793
794
795
796


797
798
799
800
801



802
803
804
805
806
807
808

809
810
811
812
813
814
815
...
819
820
821
822
823
824
825
826
827

828
829
830
831
832
833
834
      ){
        const char *zType;
        if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){
          zType = "window";
        }else{
          zType = "aggregate";
        }
#else
      if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
        const char *zType = "aggregate";
#endif
        sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()", zType, nId,zId);
        pNC->nErr++;
        is_agg = 0;








      }else if( no_such_func && pParse->db->init.busy==0
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
                && pParse->explain==0
#endif
      ){
        sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
        pNC->nErr++;
      }else if( wrong_num_args ){
        sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
             nId, zId);
        pNC->nErr++;
      }
      if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg;


      sqlite3WalkExprList(pWalker, pList);
      if( is_agg ){
#ifndef SQLITE_OMIT_WINDOWFUNC
        if( pExpr->pWin ){
          Select *pSel = pNC->pWinSelect;



          sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->pWin, pDef);
          if( 0==pSel->pWin 
           || 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->pWin) 
          ){
            pExpr->pWin->pNextWin = pSel->pWin;
            pSel->pWin = pExpr->pWin;
          }

        }else
#endif /* SQLITE_OMIT_WINDOWFUNC */
        {
          NameContext *pNC2 = pNC;
          pExpr->op = TK_AGG_FUNCTION;
          pExpr->op2 = 0;
          while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
................................................................................
          assert( pDef!=0 );
          if( pNC2 ){
            assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
            testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
            pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);

          }
        }
        pNC->ncFlags |= NC_AllowAgg;

      }
      /* FIX ME:  Compute pExpr->affinity based on the expected return
      ** type of the function 
      */
      return WRC_Prune;
    }
#ifndef SQLITE_OMIT_SUBQUERY







<
<
<
<



>
>
>
>
>
>
>
>
|











|
>
>





>
>
>







>







 







<
|
>







770
771
772
773
774
775
776




777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
...
829
830
831
832
833
834
835

836
837
838
839
840
841
842
843
844
      ){
        const char *zType;
        if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){
          zType = "window";
        }else{
          zType = "aggregate";
        }




        sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()", zType, nId,zId);
        pNC->nErr++;
        is_agg = 0;
      }
#else
      if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
        sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
        pNC->nErr++;
        is_agg = 0;
      }
#endif
      else if( no_such_func && pParse->db->init.busy==0
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
                && pParse->explain==0
#endif
      ){
        sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
        pNC->nErr++;
      }else if( wrong_num_args ){
        sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
             nId, zId);
        pNC->nErr++;
      }
      if( is_agg ){
        pNC->ncFlags &= ~(pExpr->pWin ? NC_AllowWin : NC_AllowAgg);
      }
      sqlite3WalkExprList(pWalker, pList);
      if( is_agg ){
#ifndef SQLITE_OMIT_WINDOWFUNC
        if( pExpr->pWin ){
          Select *pSel = pNC->pWinSelect;
          sqlite3WalkExprList(pWalker, pExpr->pWin->pPartition);
          sqlite3WalkExprList(pWalker, pExpr->pWin->pOrderBy);
          sqlite3WalkExpr(pWalker, pExpr->pWin->pFilter);
          sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->pWin, pDef);
          if( 0==pSel->pWin 
           || 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->pWin) 
          ){
            pExpr->pWin->pNextWin = pSel->pWin;
            pSel->pWin = pExpr->pWin;
          }
          pNC->ncFlags |= NC_AllowWin;
        }else
#endif /* SQLITE_OMIT_WINDOWFUNC */
        {
          NameContext *pNC2 = pNC;
          pExpr->op = TK_AGG_FUNCTION;
          pExpr->op2 = 0;
          while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
................................................................................
          assert( pDef!=0 );
          if( pNC2 ){
            assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
            testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
            pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);

          }

          pNC->ncFlags |= NC_AllowAgg;
        }
      }
      /* FIX ME:  Compute pExpr->affinity based on the expected return
      ** type of the function 
      */
      return WRC_Prune;
    }
#ifndef SQLITE_OMIT_SUBQUERY

Changes to src/walker.c.

50
51
52
53
54
55
56






57
58
59
60
61
62
63
        pExpr = pExpr->pRight;
        continue;
      }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
        if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
      }else if( pExpr->x.pList ){
        if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
      }






    }
    break;
  }
  return WRC_Continue;
}
int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
  return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;







>
>
>
>
>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
        pExpr = pExpr->pRight;
        continue;
      }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
        if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
      }else if( pExpr->x.pList ){
        if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
      }
      if( pExpr->pWin ){
        Window *pWin = pExpr->pWin;
        if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort;
        if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort;
        if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort;
      }
    }
    break;
  }
  return WRC_Continue;
}
int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
  return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;

Changes to test/window1.test.

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
...
436
437
438
439
440
441
442
443



































































444
445
do_catchsql_test 7.1.3 {
  SELECT count(*) FROM t1 GROUP BY y HAVING nth_value(x, 1) OVER (ORDER BY y);
} {1 {misuse of window function nth_value()}}
do_catchsql_test 7.1.4 {
  SELECT count(*) FROM t1 GROUP BY nth_value(x, 1) OVER (ORDER BY y);
} {1 {misuse of window function nth_value()}}
do_catchsql_test 7.1.5 {
  SELECT count(*) FROM t1 LIMIT nth_value(x, 1) OVER (ORDER BY y);
} {1 {no such column: x}}
do_catchsql_test 7.1.6 {
  SELECT trim(x) OVER (ORDER BY y) FROM t1;
} {1 {trim() may not be used as a window function}}
do_catchsql_test 7.1.7 {
  SELECT max(x) OVER abc FROM t1 WINDOW def AS (ORDER BY y);
} {1 {no such window: abc}}
................................................................................
} {
  Alice North      56 
  Charles North   101 
  Darrell South     8 
  Frank South      30 
  Grant South      53 
}




































































finish_test








|







 








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


245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
do_catchsql_test 7.1.3 {
  SELECT count(*) FROM t1 GROUP BY y HAVING nth_value(x, 1) OVER (ORDER BY y);
} {1 {misuse of window function nth_value()}}
do_catchsql_test 7.1.4 {
  SELECT count(*) FROM t1 GROUP BY nth_value(x, 1) OVER (ORDER BY y);
} {1 {misuse of window function nth_value()}}
do_catchsql_test 7.1.5 {
  SELECT count(*) FROM t1 LIMIT nth_value(x, 1) OVER ();
} {1 {no such column: x}}
do_catchsql_test 7.1.6 {
  SELECT trim(x) OVER (ORDER BY y) FROM t1;
} {1 {trim() may not be used as a window function}}
do_catchsql_test 7.1.7 {
  SELECT max(x) OVER abc FROM t1 WINDOW def AS (ORDER BY y);
} {1 {no such window: abc}}
................................................................................
} {
  Alice North      56 
  Charles North   101 
  Darrell South     8 
  Frank South      30 
  Grant South      53 
}

do_execsql_test 10.5 {
  SELECT emp, region, sum(total) OVER win FROM sales
  WINDOW win AS (
    PARTITION BY region ORDER BY total 
    ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
  )
} {
  Horace East       1  
  Brad North      101
  Alice North      79 
  Charles North    45 
  Darrell South   152
  Frank South     144 
  Grant South     122 
  Elizabeth South  99
}

do_execsql_test 10.6 {
  SELECT emp, region, sum(total) OVER win FROM sales
  WINDOW win AS (
    PARTITION BY region ORDER BY total 
    ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
  ) LIMIT 5 OFFSET 2
} {
  Alice North      79 
  Charles North    45 
  Darrell South   152
  Frank South     144 
  Grant South     122 
}

do_execsql_test 10.7 {
  SELECT emp, region, (
    SELECT sum(total) OVER (
      ORDER BY total RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
    ) || outer.emp FROM sales
  ) FROM sales AS outer;
} {
  Alice North 254Alice 
  Frank South 254Frank 
  Charles North 254Charles 
  Darrell South 254Darrell 
  Grant South 254Grant 
  Brad North 254Brad 
  Elizabeth South 254Elizabeth 
  Horace East 254Horace
}

breakpoint
do_execsql_test 10.8 {
  SELECT emp, region, (
    SELECT sum(total) FILTER (WHERE sales.emp!=outer.emp) OVER (
      ORDER BY total RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
    ) FROM sales
  ) FROM sales AS outer;
} {
  Alice North 220 
  Frank South 232 
  Charles North 209 
  Darrell South 246
  Grant South 231 
  Brad North 232 
  Elizabeth South 155 
  Horace East 253
}


finish_test