SQLite

Check-in [ad7bb70a]
Login

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

Overview
Comment:When rewriting a query for window functions, if the rewrite changes the depth of TK_AGG_FUNCTION nodes, be sure to adjust the Expr.op2 field appropriately. Fix for ticket [7a5279a25c57adf1]
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: ad7bb70af9bb68d192137188bb2528f1e9e43ad164c925174ca1dafc9e1f5339
User & Date: drh 2020-05-24 03:38:37
Context
2020-05-24
12:36
Version number to 3.32.1. (check-in: 56e5063c user: drh tags: trunk)
03:38
When rewriting a query for window functions, if the rewrite changes the depth of TK_AGG_FUNCTION nodes, be sure to adjust the Expr.op2 field appropriately. Fix for ticket [7a5279a25c57adf1] (check-in: ad7bb70a user: drh tags: trunk)
03:01
Move some utility Walker callbacks into the walker.c source file, as they seem to belong there better. (check-in: dac43823 user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/resolve.c.

20
21
22
23
24
25
26


27
28
29
30
31
32
33
** Walk the expression tree pExpr and increase the aggregate function
** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node.
** This needs to occur when copying a TK_AGG_FUNCTION node from an
** outer query into an inner subquery.
**
** incrAggFunctionDepth(pExpr,n) is the main routine.  incrAggDepth(..)
** is a helper function - a callback for the tree walker.


*/
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
  if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
  return WRC_Continue;
}
static void incrAggFunctionDepth(Expr *pExpr, int N){
  if( N>0 ){







>
>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
** Walk the expression tree pExpr and increase the aggregate function
** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node.
** This needs to occur when copying a TK_AGG_FUNCTION node from an
** outer query into an inner subquery.
**
** incrAggFunctionDepth(pExpr,n) is the main routine.  incrAggDepth(..)
** is a helper function - a callback for the tree walker.
**
** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c
*/
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
  if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
  return WRC_Continue;
}
static void incrAggFunctionDepth(Expr *pExpr, int N){
  if( N>0 ){

Changes to src/window.c.

911
912
913
914
915
916
917

















918
919
920
921
922
923
924
      }
      pList = sqlite3ExprListAppend(pParse, pList, pDup);
      if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
    }
  }
  return pList;
}


















/*
** If the SELECT statement passed as the second argument does not invoke
** any SQL window functions, this function is a no-op. Otherwise, it 
** rewrites the SELECT statement so that window function xStep functions
** are invoked in the correct order as described under "SELECT REWRITING"
** at the top of this file.







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







911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
      }
      pList = sqlite3ExprListAppend(pParse, pList, pDup);
      if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
    }
  }
  return pList;
}

/*
** When rewriting a query, if the new subquery in the FROM clause
** contains TK_AGG_FUNCTION nodes that refer to an outer query,
** then we have to increase the Expr->op2 values of those nodes
** due to the extra subquery layer that was added.
**
** See also the incrAggDepth() routine in resolve.c
*/
static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){
  if( pExpr->op==TK_AGG_FUNCTION
   && pExpr->op2>=pWalker->walkerDepth
  ){
    pExpr->op2++;
  }
  return WRC_Continue;
}

/*
** If the SELECT statement passed as the second argument does not invoke
** any SQL window functions, this function is a no-op. Otherwise, it 
** rewrites the SELECT statement so that window function xStep functions
** are invoked in the correct order as described under "SELECT REWRITING"
** at the top of this file.
1021
1022
1023
1024
1025
1026
1027

1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042





1043
1044
1045
1046
1047
1048
1049

    pSub = sqlite3SelectNew(
        pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
    );
    p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
    if( p->pSrc ){
      Table *pTab2;

      p->pSrc->a[0].pSelect = pSub;
      sqlite3SrcListAssignCursors(pParse, p->pSrc);
      pSub->selFlags |= SF_Expanded;
      pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
      pSub->selFlags |= (selFlags & SF_Aggregate);
      if( pTab2==0 ){
        /* Might actually be some other kind of error, but in that case
        ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get
        ** the correct error message regardless. */
        rc = SQLITE_NOMEM;
      }else{
        memcpy(pTab, pTab2, sizeof(Table));
        pTab->tabFlags |= TF_Ephemeral;
        p->pSrc->a[0].pTab = pTab;
        pTab = pTab2;





      }
    }else{
      sqlite3SelectDelete(db, pSub);
    }
    if( db->mallocFailed ) rc = SQLITE_NOMEM;
    sqlite3DbFree(db, pTab);
  }







>















>
>
>
>
>







1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072

    pSub = sqlite3SelectNew(
        pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
    );
    p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
    if( p->pSrc ){
      Table *pTab2;
      Walker w;
      p->pSrc->a[0].pSelect = pSub;
      sqlite3SrcListAssignCursors(pParse, p->pSrc);
      pSub->selFlags |= SF_Expanded;
      pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
      pSub->selFlags |= (selFlags & SF_Aggregate);
      if( pTab2==0 ){
        /* Might actually be some other kind of error, but in that case
        ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get
        ** the correct error message regardless. */
        rc = SQLITE_NOMEM;
      }else{
        memcpy(pTab, pTab2, sizeof(Table));
        pTab->tabFlags |= TF_Ephemeral;
        p->pSrc->a[0].pTab = pTab;
        pTab = pTab2;
        memset(&w, 0, sizeof(w));
        w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
        w.xSelectCallback = sqlite3WalkerDepthIncrease;
        w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
        sqlite3WalkSelect(&w, pSub);
      }
    }else{
      sqlite3SelectDelete(db, pSub);
    }
    if( db->mallocFailed ) rc = SQLITE_NOMEM;
    sqlite3DbFree(db, pTab);
  }

Changes to test/window1.test.

1722
1723
1724
1725
1726
1727
1728
















1729
1730
1731
             RANGE BETWEEN 5 PRECEDING AND 0 PRECEDING );
} {
  1 356 356 4 
  2 399 399 2 
  3 158 158 2 
  4 938 938 4
}


















finish_test







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



1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
             RANGE BETWEEN 5 PRECEDING AND 0 PRECEDING );
} {
  1 356 356 4 
  2 399 399 2 
  3 158 158 2 
  4 938 938 4
}

# 2020-05-23
# ticket 7a5279a25c57adf1
#
reset_db
do_execsql_test 53.0 {
  CREATE TABLE a(c UNIQUE);
  INSERT INTO a VALUES(4),(0),(9),(-9);
  SELECT a.c
    FROM a
    JOIN a AS b ON a.c=4
    JOIN a AS e ON a.c=e.c
   WHERE a.c=(SELECT (SELECT coalesce(lead(2) OVER(),0) + sum(d.c))
                FROM a AS d
               WHERE a.c);
} {4 4 4 4}


finish_test