From c0bb4459d35a30dee53be3ffdfc4ad2bd8659da4 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 12 Jun 2018 20:53:38 +0000 Subject: [PATCH] Fix another issue to do with window-functions in aggregate queries. FossilOrigin-Name: 6413e38a174044c28fa9b8b937e6c972d144547a246e6f2882e782538300d042 --- manifest | 18 +++++----- manifest.uuid | 2 +- src/btree.c | 5 +++ src/window.c | 91 +++++++++++++++++++++++++++++++++++------------ test/window4.tcl | 8 +++++ test/window4.test | 8 +++++ 6 files changed, 100 insertions(+), 32 deletions(-) diff --git a/manifest b/manifest index 7cc7cd4f7f..27851dacfd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\ssome\sproblems\swith\susing\swindow-functions\sin\saggregate\squeries. -D 2018-06-12T18:40:17.751 +C Fix\sanother\sissue\sto\sdo\swith\swindow-functions\sin\saggregate\squeries. +D 2018-06-12T20:53:38.832 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 498b77b89a8cb42f2ee20fcd6317f279a45c0d6ff40d27825f94b69884c09bbe @@ -436,7 +436,7 @@ F src/auth.c a38f3c63c974787ecf75e3213f8cac6568b9a7af7591fb0372ec0517dd16dca8 F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 671207d68ac2fb32c782f9b65cd6f8a861757044b1448098cb08fab4fcf02947 +F src/btree.c 50425f7f26b10919bd14fa1af534b92c339bf7aac4b1ac8c70404f4e6f8220d8 F src/btree.h 7b557914561f60a0eb76c2e22c23ab5b82f87b734a91c1b9385654b6474fdf7f F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96 F src/build.c 3b3bfa88800739e1f11313dcecfba5ef8e4757b6c929cdf7de9fcfc01002b81f @@ -583,7 +583,7 @@ F src/where.c fe1a6f97c12cc9472ccce86166ba3f827cf61d6ae770c036a6396b63863baac4 F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4 F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96 F src/whereexpr.c 6f022d6cc9daf56495f191b199352f783aff5cf268ba136b4d8cea3fb62d8c7d -F src/window.c 5fc1e9a4367bdd6c5afd318a36ec0b1f702fa1e3384621501873ec6b3e94651a +F src/window.c 45d149fe9926b7e9c610ef5234b6eef08f22cbdff855aa3f367b6af17499e90b F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d @@ -1622,8 +1622,8 @@ F test/window2.tcl 0983de5eade5eeda49469244799d5331bfe3199fca3f6c6d2a836aa08f4fb F test/window2.test 79747b2edde4ad424e0752b27529aedc86e91f3d8d88846fa17ff0cb67f65086 F test/window3.tcl 654d61d73e10db089b22514d498bb23ec310f720c0f4b5f69f67fda83d672048 F test/window3.test 41727668ee31d2ba50f78efcb5bf1bda2c5cffd889aa65243511004669d1ac25 -F test/window4.tcl e64db87bac34d9a726f2b97c40f4adbfc21650a26b7015b18f357062266a0062 -F test/window4.test 36df9adf8b305b427fee8c9604a958e8fecb85c2ba21f6819ad3e87610253001 +F test/window4.tcl a77a7ab3c60517abe06307e4204d65d11f5474c8062f30f536755dd083bf8224 +F test/window4.test 0fb98450ff5478f91b4f8c9440d4463ded30a7337029da4272894ccff0f227e2 F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96 F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d @@ -1740,7 +1740,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0cd55e98a478740032f5569ddc00fa5b0e063e90db6e00ac7598c9b7c2fffeee -R a9e6944f8f988df57ad1f0cd1beda118 +P fe7081e0952950f577234fcbb58f3c1efa4579267654fd2f713dc4804e470e7e +R 7cbc79b684a204310b1cd3eb56d614ea U dan -Z e98e199ae454a383acf0272ef0289805 +Z 4b5b4b6d9afcbd2c7bfd885559718021 diff --git a/manifest.uuid b/manifest.uuid index 1fb6535a25..5adea5b5a2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fe7081e0952950f577234fcbb58f3c1efa4579267654fd2f713dc4804e470e7e \ No newline at end of file +6413e38a174044c28fa9b8b937e6c972d144547a246e6f2882e782538300d042 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 0e0d043104..35e13478b6 100644 --- a/src/btree.c +++ b/src/btree.c @@ -5185,6 +5185,11 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ return rc; } +/* +** This function is a no-op if cursor pCur does not point to a valid row. +** Otherwise, if pCur is valid, configure it so that the next call to +** sqlite3BtreeNext() is a no-op. +*/ void sqlite3BtreeSkipNext(BtCursor *pCur){ if( pCur->eState==CURSOR_VALID ){ pCur->eState = CURSOR_SKIPNEXT; diff --git a/src/window.c b/src/window.c index 6d66fb82d7..de3b778226 100644 --- a/src/window.c +++ b/src/window.c @@ -129,6 +129,11 @@ ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ** ** See sqlite3WindowUpdate() for details. +** +** As well as some of the built-in window functions, aggregate window +** functions min() and max() are implemented using VDBE instructions if +** the start of the window frame is declared as anything other than +** UNBOUNDED PRECEDING. */ /* @@ -471,11 +476,28 @@ void sqlite3WindowFunctions(void){ sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs)); } +/* +** This function is called immediately after resolving the function name +** for a window function within a SELECT statement. Argument pList is a +** linked list of WINDOW definitions for the current SELECT statement. +** Argument pFunc is the function definition just resolved and pWin +** is the Window object representing the associated OVER clause. This +** function updates the contents of pWin as follows: +** +** * If the OVER clause refered to a named window (as in "max(x) OVER win"), +** search list pList for a matching WINDOW definition, and update pWin +** accordingly. If no such WINDOW clause can be found, leave an error +** in pParse. +** +** * If the function is a built-in window function that requires the +** window to be coerced (see "BUILT-IN WINDOW FUNCTIONS" at the top +** of this file), pWin is updated here. +*/ void sqlite3WindowUpdate( Parse *pParse, - Window *pList, - Window *pWin, - FuncDef *pFunc + Window *pList, /* List of named windows for this SELECT */ + Window *pWin, /* Window frame to update */ + FuncDef *pFunc /* Window function definition */ ){ if( pWin->zName ){ Window *p; @@ -523,16 +545,21 @@ void sqlite3WindowUpdate( pWin->pFunc = pFunc; } +/* +** Context object passed through sqlite3WalkExprList() to +** selectWindowRewriteExprCb() by selectWindowRewriteEList(). +*/ typedef struct WindowRewrite WindowRewrite; struct WindowRewrite { Window *pWin; ExprList *pSub; }; -static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){ - return WRC_Prune; -} - +/* +** Callback function used by selectWindowRewriteEList(). If necessary, +** this function appends to the output expression-list and updates +** expression (*ppExpr) in place. +*/ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ struct WindowRewrite *p = pWalker->u.pRewrite; Parse *pParse = pWalker->pParse; @@ -578,7 +605,24 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ return WRC_Continue; } +static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){ + return WRC_Prune; +} + +/* +** Iterate through each expression in expression-list pEList. For each: +** +** * TK_COLUMN, +** * aggregate function, or +** * window function with a Window object that is not a member of the +** linked list passed as the second argument (pWin) +** +** Append the node to output expression-list (*ppSub). And replace it +** with a TK_COLUMN that reads the (N-1)th element of table +** pWin->iEphCsr, where N is the number of elements in (*ppSub) after +** appending the new one. +*/ static int selectWindowRewriteEList( Parse *pParse, Window *pWin, @@ -606,6 +650,10 @@ static int selectWindowRewriteEList( return rc; } +/* +** Append a copy of each expression in expression-list pAppend to +** expression list pList. Return a pointer to the result list. +*/ static ExprList *exprListAppendList( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ @@ -627,21 +675,8 @@ static ExprList *exprListAppendList( ** 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. The simplest version of the -** transformation is: -** -** SELECT win(args...) OVER () FROM ORDER BY -** -** to -** -** SELECT win(args...) FROM ( -** SELECT args... FROM ORDER BY -** ) ORDER BY -** -** where may contain WHERE, GROUP BY and HAVING clauses, and -** is the concatenation of the PARTITION BY and ORDER BY clauses in the -** OVER clause. -** +** are invoked in the correct order as described under "SELECT REWRITING" +** at the top of this file. */ int sqlite3WindowRewrite(Parse *pParse, Select *p){ int rc = SQLITE_OK; @@ -726,6 +761,9 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ return rc; } +/* +** Free the Window object passed as the second argument. +*/ void sqlite3WindowDelete(sqlite3 *db, Window *p){ if( p ){ sqlite3ExprDelete(db, p->pFilter); @@ -738,6 +776,9 @@ void sqlite3WindowDelete(sqlite3 *db, Window *p){ } } +/* +** Free the linked list of Window objects starting at the second argument. +*/ void sqlite3WindowListDelete(sqlite3 *db, Window *p){ while( p ){ Window *pNext = p->pNextWin; @@ -746,6 +787,9 @@ void sqlite3WindowListDelete(sqlite3 *db, Window *p){ } } +/* +** Allocate and return a new Window object. +*/ Window *sqlite3WindowAlloc( Parse *pParse, int eType, @@ -768,6 +812,9 @@ Window *sqlite3WindowAlloc( return pWin; } +/* +** Attach window object pWin to expression p. +*/ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ p->pWin = pWin; diff --git a/test/window4.tcl b/test/window4.tcl index c0eb2b7abb..fcb6e61212 100644 --- a/test/window4.tcl +++ b/test/window4.tcl @@ -149,6 +149,14 @@ execsql_test 4.1 { SELECT max(c), max(b) OVER (ORDER BY b) FROM ttt GROUP BY b; } +execsql_test 4.2 { + SELECT max(b) OVER (ORDER BY max(c)) FROM ttt GROUP BY b; +} + +execsql_test 4.3 { + SELECT abs(max(b) OVER (ORDER BY b)) FROM ttt GROUP BY b; +} + finish_test diff --git a/test/window4.test b/test/window4.test index 307465e843..f29bce7525 100644 --- a/test/window4.test +++ b/test/window4.test @@ -231,4 +231,12 @@ do_execsql_test 4.1 { SELECT max(c), max(b) OVER (ORDER BY b) FROM ttt GROUP BY b; } {3 1 4 2 5 3} +do_execsql_test 4.2 { + SELECT max(b) OVER (ORDER BY max(c)) FROM ttt GROUP BY b; +} {1 2 3} + +do_execsql_test 4.3 { + SELECT abs(max(b) OVER (ORDER BY b)) FROM ttt GROUP BY b; +} {1 2 3} + finish_test