Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | When rewriting the parse-tree for window functions, ensure that the inserted subqueries have an accurate SF_Aggregate bit set. This change also coincidentally fixes ticket [0899cf62f597d7e7], even thought that was not the issue we were working on at the time. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | early-winfunc-rewrite-dev |
Files: | files | file ages | folders |
SHA3-256: |
2cddb24e911588d9bb3840fe6edfbad5 |
User & Date: | drh 2020-06-06 14:44:38 |
Context
2020-06-06
| ||
20:48 | Merge multiple changes from trunk to address concerns with window-function parse-tree rewriting. (check-in: 05418b2a user: drh tags: branch-3.32-early-winfunc-rewrite) | |
14:58 | Remove an incorrect assert() added earlier today. (check-in: 3926ff17 user: drh tags: early-winfunc-rewrite-dev) | |
14:44 | When rewriting the parse-tree for window functions, ensure that the inserted subqueries have an accurate SF_Aggregate bit set. This change also coincidentally fixes ticket [0899cf62f597d7e7], even thought that was not the issue we were working on at the time. (check-in: 2cddb24e user: drh tags: early-winfunc-rewrite-dev) | |
14:29 | Fix an assert() failure that could occur if an ORDER BY expression attached to a compound query contains a subquery that (a) is itself a compound query, (b) uses window functions and (c) has an ORDER BY clause that includes another sub-query. (check-in: c96914ea user: dan tags: early-winfunc-rewrite-dev) | |
Changes
Changes to src/resolve.c.
︙ | ︙ | |||
1020 1021 1022 1023 1024 1025 1026 | pNC2 = pNC2->pNext; } assert( pDef!=0 || IN_RENAME_OBJECT ); if( pNC2 && pDef ){ assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); | < | 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 | pNC2 = pNC2->pNext; } assert( pDef!=0 || IN_RENAME_OBJECT ); if( pNC2 && pDef ){ assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); } } pNC->ncFlags |= savedAllowFlags; } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function */ |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
6207 6208 6209 6210 6211 6212 6213 | sqlite3WindowCodeInit(pParse, p); } #endif assert( WHERE_USE_LIMIT==SF_FixedLimit ); /* Begin the database scan. */ | | | 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 | sqlite3WindowCodeInit(pParse, p); } #endif assert( WHERE_USE_LIMIT==SF_FixedLimit ); /* Begin the database scan. */ SELECTTRACE(1,pParse,p,("WhereBegin-A\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, p->pEList, wctrlFlags, p->nSelectRow); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ |
︙ | ︙ | |||
6438 6439 6440 6441 6442 6443 6444 | /* Begin a loop that will extract all source rows in GROUP BY order. ** This might involve two separate loops with an OP_Sort in between, or ** it might be a single loop that uses an index to extract information ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); | | | 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 | /* Begin a loop that will extract all source rows in GROUP BY order. ** This might involve two separate loops with an OP_Sort in between, or ** it might be a single loop that uses an index to extract information ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); SELECTTRACE(1,pParse,p,("WhereBegin-B\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 ); if( pWInfo==0 ) goto select_end; if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be |
︙ | ︙ | |||
6713 6714 6715 6716 6717 6718 6719 | ** minMaxFlag will have been previously set to either ** WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX and pMinMaxOrderBy will ** be an appropriate ORDER BY expression for the optimization. */ assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 ); assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 ); | | | 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 | ** minMaxFlag will have been previously set to either ** WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX and pMinMaxOrderBy will ** be an appropriate ORDER BY expression for the optimization. */ assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 ); assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 ); SELECTTRACE(1,pParse,p,("WhereBegin-C\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy, 0, minMaxFlag, 0); if( pWInfo==0 ){ goto select_end; } updateAccumulator(pParse, regAcc, &sAggInfo); if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc); |
︙ | ︙ |
Changes to src/window.c.
︙ | ︙ | |||
919 920 921 922 923 924 925 926 927 | /* ** 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){ | > > > > > | | < | > > > | 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 | /* ** 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 ** ** In addition to increasing pExpr->op2, set pWalker->eCode to 1 if ** any top-level aggregate functions are encountered. This is needed ** to accurately set the SF_Aggregate flag on the new window-function ** subquery. */ static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION ){ if( pExpr->op2>=pWalker->walkerDepth ){ pExpr->op2++; }else if( pExpr->op2==pWalker->walkerDepth-1 ){ pWalker->eCode = 1; } } 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 |
︙ | ︙ | |||
952 953 954 955 956 957 958 | Expr *pHaving = p->pHaving; ExprList *pSort = 0; ExprList *pSublist = 0; /* Expression list for sub-query */ Window *pMWin = p->pWin; /* Master window object */ Window *pWin; /* Window object iterator */ Table *pTab; | < | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 | Expr *pHaving = p->pHaving; ExprList *pSort = 0; ExprList *pSublist = 0; /* Expression list for sub-query */ Window *pMWin = p->pWin; /* Master window object */ Window *pWin; /* Window object iterator */ Table *pTab; pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ){ return sqlite3ErrorToParser(db, SQLITE_NOMEM); } p->pSrc = 0; |
︙ | ︙ | |||
1043 1044 1045 1046 1047 1048 1049 | 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); | < > | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | 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); 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; assert( pTab->zName==0 ); pTab->zName = sqlite3MPrintf(db, "$wintab_%p", pTab); 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); if( w.eCode ) pSub->selFlags |= SF_Aggregate; } }else{ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; sqlite3DbFree(db, pTab); } |
︙ | ︙ |
Changes to test/window1.test.
︙ | ︙ | |||
1813 1814 1815 1816 1817 1818 1819 1820 1821 | SELECT c AS x FROM t4 UNION SELECT d FROM t4 ORDER BY (SELECT e FROM t4) ) ); } {1 {1st ORDER BY term does not match any column in the result set}} finish_test | > > > > > > > > > > > > > > > > > > > | 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 | SELECT c AS x FROM t4 UNION SELECT d FROM t4 ORDER BY (SELECT e FROM t4) ) ); } {1 {1st ORDER BY term does not match any column in the result set}} # 2020-06-06 various dbsqlfuzz finds and # ticket 0899cf62f597d7e7 # reset_db do_execsql_test 57.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(NULL,NULL,NULL); SELECT sum(a), min(b) OVER (), count(c) OVER (ORDER BY b) FROM t1; } {{} {} 0} do_execsql_test 57.2 { CREATE TABLE v0 ( v1 INTEGER PRIMARY KEY ) ; INSERT INTO v0 VALUES ( 10 ) ; SELECT DISTINCT v1, lead(v1) OVER() FROM v0 GROUP BY v1 ORDER BY 2; } {10 {}} finish_test |