]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add support for the WINDOW clause.
authordan <dan@noemail.net>
Fri, 8 Jun 2018 20:58:27 +0000 (20:58 +0000)
committerdan <dan@noemail.net>
Fri, 8 Jun 2018 20:58:27 +0000 (20:58 +0000)
FossilOrigin-Name: 19c983b511f1c823fdfb051713681b4c779f02fa83b41189afca0a9b8b72048d

12 files changed:
manifest
manifest.uuid
src/expr.c
src/func.c
src/parse.y
src/resolve.c
src/select.c
src/sqliteInt.h
src/window.c
test/window4.tcl
test/window4.test
tool/mkkeywordhash.c

index 5f63042a2b555bd16835627d5cd8a9d03da4d79c..5205165f4368e2881116824ed8ec5af1a44428d2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Do\snot\sflatten\ssub-queries\sthat\scontain\swindow\sfunctions.
-D 2018-06-08T16:11:55.013
+C Add\ssupport\sfor\sthe\sWINDOW\sclause.
+D 2018-06-08T20:58:27.833
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
@@ -447,10 +447,10 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
 F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
 F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
 F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f
-F src/expr.c 587b4bc88f2b3b77563166e9058c191098c91f28770a40240d96c0ca74fcd050
+F src/expr.c d6db67ebe0597f87381827513ae168b202956fca35add953e294afc80fa41675
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee
-F src/func.c 3e8a85f9bfc9117964523a5e17bdbc4b0b9d707830871cbc1dc44b9b538d5d82
+F src/func.c a5ee3864264edea8fea4d2dfdf8296250cff9139343953da78d82837241659a9
 F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
 F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
 F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
@@ -484,7 +484,7 @@ F src/os_win.c ac29c25cde4cfb4adacc59cdec4aa45698ca0e29164ea127859585ccd9faa354
 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
 F src/pager.c 1bb6a57fa0465296a4d6109a1a64610a0e7adde1f3acf3ef539a9d972908ce8f
 F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
-F src/parse.y 9eaa457cff322e0dd5f52e363eab0b73f11bcd35bdced58274dead597e1a3d6a
+F src/parse.y 788f41e7558278423931dd0fdb1a4fb4657f451371d2f2c4b1d11824484c419f
 F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
 F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
@@ -493,14 +493,14 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
 F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
 F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
-F src/resolve.c 172f4c514b41dabc00cf5ada72f6de6f897881d50de5fd33a94f3d1e5c36dafc
+F src/resolve.c da9b85ec0e1a05384134cece5747a90b8da1fc5750f4705c7812d2294ca20cec
 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
-F src/select.c d48879c0a2acb79ed0db384074caef9002902765f2b35a74a7b8f403332f4b1a
+F src/select.c 0b0ce29bd7b8a7232e6f7602ddb447caa954a1fc476ff5e23ce1e5aaa6a0e0ed
 F src/shell.c.in 4d0ddf10c403710d241bf920163dcf032c21119aebb61e70840942c0eafecdf9
 F src/sqlite.h.in 63b07f76731f2b1e55c48fdb9f0508dcc6fbe3971010b8612ffd847c3c56d9a1
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
-F src/sqliteInt.h 72c13b9833611dfcbb62314f96b2c9343e6dfbbe6d156365609fed82ca4d17f0
+F src/sqliteInt.h 8cdd2f8c920cc7de683c27322d2f146079bc36ad267b63eaf9ee186ee58e287f
 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
 F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -583,7 +583,7 @@ F src/where.c 7dcb13bbcfd8c926546946556014c8f5aa0829eb8b65a6c18f8d187d265200a5
 F src/whereInt.h b09753e74bf92a8b17cf0e41ca94c44432c454544be6699b5311dcc57bf229c6
 F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
 F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
-F src/window.c 141a79da0fac93514a4c3f2530e52d22cb74622daf08fb9023668133ad4e285c
+F src/window.c 31bd22def29a71144056ddd2a9c4344648c2b89f63a76e7695defdf7ed293216
 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 f2596e9d6bf8d4441eb7a0d3272594185c3b56e8d2413a54b12e6e7557517674
 F test/window3.test e43a143131e19a27148215431cf7cec8815c32c7ec04f1cf79d068adff9be028
-F test/window4.tcl 9e5698ffb729676b88290a7048ae9bb9b0d31efe0b630e51f9ce796cca737f8c
-F test/window4.test 316bf0844fa4966488b3c9d2e69a360f5b4de87022ca44f5a96a62243d9db796
+F test/window4.tcl 2da10ad7a6eedc584c3faa551ff6d0a7f8cc18dee95416d05af389f88ef0ac1a
+F test/window4.test bef29a267ee9ac7ca421ef69ba37d19f7e93988f1c052cb09cbb946f309c5cbe
 F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
 F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
 F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
@@ -1668,7 +1668,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
 F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
 F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
 F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
-F tool/mkkeywordhash.c dd4d201d646dd4e236b93be17589e89a19b329a8840e559f91db3bdc361f3c39
+F tool/mkkeywordhash.c a0fd254852ac92ddea42ea04d1f41d50298590fc1121a815ddeb18f9b2af4193
 F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6a13ea
 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
 F tool/mkopcodeh.tcl 17d1ccc05a926e19e3a9679ea3e4d1aaa15ba753e2fa7363e6e81c80e0ef8b86
@@ -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 89bbc9ba8f66853a7530453f146c9df1baacd8558468016cefa7602911f7578a
-R dccf8398447f81129241381719cad17d
+P 236cb75bd1f0d5eb86aa5f52d8d548e7263c34633833dcea9dfc934f142113b8
+R 42923cbfbd64d075a9e38b7b4b4b969d
 U dan
-Z 5f65d7a3a3ae3236c28a203eff6b68d3
+Z dee7bf2abe4eeccc35a23aee41391161
index 6a827c374a236a66765223694d554ece3258c035..9c7373451d81ce0fefdaf090d0384524af512642 100644 (file)
@@ -1 +1 @@
-236cb75bd1f0d5eb86aa5f52d8d548e7263c34633833dcea9dfc934f142113b8
\ No newline at end of file
+19c983b511f1c823fdfb051713681b4c779f02fa83b41189afca0a9b8b72048d
\ No newline at end of file
index af4201edf7aa5897d31b579a8062f5d78705e58f..819a14bced3f85dc0bb541e7d8063b37282a6777 100644 (file)
@@ -1480,6 +1480,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
     pNew->nSelectRow = p->nSelectRow;
     pNew->pWith = withDup(db, p->pWith);
     pNew->pWin = 0;
+    pNew->pWinDefn = 0;           /* TODO!! */
     sqlite3SelectSetName(pNew, p->zSelName);
     *pp = pNew;
     pp = &pNew->pPrior;
index 62a545e3de5661dd1c1021b60a0ecde55d977b46..f9903095d2aa6fd3c88e753f95e15f84d9345dbd 100644 (file)
@@ -1665,7 +1665,7 @@ static void groupConcatStep(
 
   if( pAccum ){
     sqlite3 *db = sqlite3_context_db_handle(context);
-    int firstTerm = pAccum->nChar==0;
+    int firstTerm = pAccum->mxAlloc==0;
     pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
     if( !firstTerm ){
       if( argc==2 ){
@@ -1703,6 +1703,7 @@ static void groupConcatInverse(
       pAccum->nChar -= n;
       memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar);
     }
+    if( pAccum->nChar==0 ) pAccum->mxAlloc = 0;
   }
 }
 static void groupConcatFinalize(sqlite3_context *context){
index e52991d6708e81f5312744eef832c3df8c185721..fa6064a14fdd3c771b37ed4b0eb7105b261a013f 100644 (file)
@@ -529,11 +529,13 @@ multiselect_op(A) ::= UNION ALL.             {A = TK_ALL;}
 multiselect_op(A) ::= EXCEPT|INTERSECT(OP).  {A = @OP; /*A-overwrites-OP*/}
 %endif SQLITE_OMIT_COMPOUND_SELECT
 oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
-                 groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
+                 groupby_opt(P) having_opt(Q) windowdefn_opt(R)
+                 orderby_opt(Z) limit_opt(L). {
 #if SELECTTRACE_ENABLED
   Token s = S; /*A-overwrites-S*/
 #endif
   A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L);
+  if( A ) A->pWinDefn = R;
 #if SELECTTRACE_ENABLED
   /* Populate the Select.zSelName[] string that is used to help with
   ** query planner debugging, to differentiate between multiple Select
@@ -1005,7 +1007,7 @@ expr(A) ::= CAST LP expr(E) AS typetoken(T) RP. {
   sqlite3ExprAttachSubtrees(pParse->db, A, E, 0);
 }
 %endif  SQLITE_OMIT_CAST
-expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP window(Z). {
+expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP over_opt(Z). {
   if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
     sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
   }
@@ -1015,7 +1017,7 @@ expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP window(Z). {
     A->flags |= EP_Distinct;
   }
 }
-expr(A) ::= id(X) LP STAR RP window(Z). {
+expr(A) ::= id(X) LP STAR RP over_opt(Z). {
   A = sqlite3ExprFunction(pParse, 0, &X);
   sqlite3WindowAttach(pParse, A, Z);
 }
@@ -1023,6 +1025,30 @@ term(A) ::= CTIME_KW(OP). {
   A = sqlite3ExprFunction(pParse, 0, &OP);
 }
 
+%type windowdefn_opt {Window*}
+%destructor windowdefn_opt {sqlite3WindowDelete(pParse->db, $$);}
+windowdefn_opt(A) ::= . { A = 0; }
+windowdefn_opt(A) ::= WINDOW windowdefn_list(B). { A = B; }
+
+%type windowdefn_list {Window*}
+%destructor windowdefn_list {sqlite3WindowDelete(pParse->db, $$);}
+windowdefn_list(A) ::= windowdefn(Z). { A = Z; }
+windowdefn_list(A) ::= windowdefn_list(Y) COMMA windowdefn(Z). {
+  if( Z ) Z->pNextWin = Y;
+  A = Z;
+}
+
+%type windowdefn {Window*}
+%destructor windowdefn {sqlite3WindowDelete(pParse->db, $$);}
+windowdefn(A) ::= nm(X) AS window(Y). {
+  if( Y ){
+    Y->zName = sqlite3DbStrNDup(pParse->db, X.z, X.n);
+  }
+  A = Y;
+}
+
+%type over_opt {Window*}
+%destructor over_opt {sqlite3WindowDelete(pParse->db, $$);}
 
 %type window {Window*}
 %destructor window {sqlite3WindowDelete(pParse->db, $$);}
@@ -1030,6 +1056,10 @@ term(A) ::= CTIME_KW(OP). {
 %type frame_opt {Window*}
 %destructor frame_opt {sqlite3WindowDelete(pParse->db, $$);}
 
+%type window_or_nm {Window*}
+%destructor window_or_nm {
+sqlite3WindowDelete(pParse->db, $$);}
+
 %type part_opt {ExprList*}
 %destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);}
 
@@ -1041,11 +1071,23 @@ term(A) ::= CTIME_KW(OP). {
 %type frame_bound {struct FrameBound}
 %destructor frame_bound {sqlite3ExprDelete(pParse->db, $$.pExpr);}
 
-window(A) ::= . { A = 0; }
-window(A) ::= filter_opt(W) OVER LP part_opt(X) orderby_opt(Y) frame_opt(Z) RP.{
-  if( Z ){
-    A = Z;
-    A->pFilter = W;
+over_opt(A) ::= . { A = 0; }
+over_opt(A) ::= filter_opt(W) OVER window_or_nm(Z). {
+  A = Z;
+  if( A ) A->pFilter = W;
+}
+
+window_or_nm(A) ::= window(Z). {A = Z;}
+window_or_nm(A) ::= nm(Z). {
+  A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+  if( A ){
+    A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n);
+  }
+}
+
+window(A) ::= LP part_opt(X) orderby_opt(Y) frame_opt(Z) RP. {
+  A = Z;
+  if( A ){
     A->pPartition = X;
     A->pOrderBy = Y;
   }
index 47f22a9718a93a03f677bbe45a1c687551886b54..cf0ca280eaf2d5c2a474681400a92cf756c9b032 100644 (file)
@@ -779,12 +779,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
       sqlite3WalkExprList(pWalker, pList);
       if( is_agg ){
         if( pExpr->pWin ){
-          sqlite3WindowUpdate(pParse, pExpr->pWin, pDef);
-          if( 0==pNC->pWin 
-           || 0==sqlite3WindowCompare(pParse, pNC->pWin, 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 = pNC->pWin;
-            pNC->pWin = pExpr->pWin;
+            pExpr->pWin->pNextWin = pSel->pWin;
+            pSel->pWin = pExpr->pWin;
           }
           pExpr->pWin->pFunc = pDef;
           pExpr->pWin->nArg = (pExpr->x.pList ? pExpr->x.pList->nExpr : 0);
@@ -1262,6 +1263,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
     */
     memset(&sNC, 0, sizeof(sNC));
     sNC.pParse = pParse;
+    sNC.pWinSelect = p;
     if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){
       return WRC_Abort;
     }
@@ -1423,9 +1425,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
       return WRC_Abort;
     }
 
-    p->pWin = sNC.pWin;
-    sNC.pWin = 0;
-
     /* Advance to the next term of the compound
     */
     p = p->pPrior;
index fcafe742d72d1fe438d4ca62941464a93e8e3ee1..48e1afd4ad2e9ad8180db3292fd534cbf80fdd28 100644 (file)
@@ -96,6 +96,9 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
     sqlite3ExprDelete(db, p->pHaving);
     sqlite3ExprListDelete(db, p->pOrderBy);
     sqlite3ExprDelete(db, p->pLimit);
+    if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
+      sqlite3WindowListDelete(db, p->pWinDefn);
+    }
     if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
     if( bFree ) sqlite3DbFreeNN(db, p);
     p = pPrior;
@@ -163,6 +166,7 @@ Select *sqlite3SelectNew(
   pNew->pLimit = pLimit;
   pNew->pWith = 0;
   pNew->pWin = 0;
+  pNew->pWinDefn = 0;
   if( pParse->db->mallocFailed ) {
     clearSelect(pParse->db, pNew, pNew!=&standin);
     pNew = 0;
index d2b7730888557dae7629284613197fc3c78b333f..5eaab0d6a317e84c51deda08702467319fda8dfb 100644 (file)
@@ -2715,7 +2715,7 @@ struct NameContext {
   int nRef;            /* Number of names resolved by this context */
   int nErr;            /* Number of errors encountered while resolving names */
   u16 ncFlags;         /* Zero or more NC_* flags defined below */
-  Window *pWin;        /* List of window functions in this context */
+  Select *pWinSelect;  /* SELECT statement for any window functions */
 };
 
 /*
@@ -2807,6 +2807,7 @@ struct Select {
   Expr *pLimit;          /* LIMIT expression. NULL means not used. */
   With *pWith;           /* WITH clause attached to this select. Or NULL. */
   Window *pWin;          /* List of window functions */
+  Window *pWinDefn;      /* List of named window definitions */
 };
 
 /*
@@ -3472,15 +3473,18 @@ struct TreeView {
 #endif /* SQLITE_DEBUG */
 
 struct Window {
-  Expr *pFilter;
-  ExprList *pPartition;
-  ExprList *pOrderBy;
+  char *zName;            /* Name of window (may be NULL) */
+  ExprList *pPartition;   /* PARTITION BY clause */
+  ExprList *pOrderBy;     /* ORDER BY clause */
   u8 eType;               /* TK_RANGE or TK_ROWS */
   u8 eStart;              /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
   u8 eEnd;                /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
   Expr *pStart;           /* Expression for "<expr> PRECEDING" */
   Expr *pEnd;             /* Expression for "<expr> FOLLOWING" */
+
   Window *pNextWin;       /* Next window function belonging to this SELECT */
+
+  Expr *pFilter;
   FuncDef *pFunc;
   int nArg;
 
@@ -3498,6 +3502,7 @@ struct Window {
 };
 
 void sqlite3WindowDelete(sqlite3*, Window*);
+void sqlite3WindowListDelete(sqlite3 *db, Window *p);
 Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*);
 void sqlite3WindowAttach(Parse*, Expr*, Window*);
 int sqlite3WindowCompare(Parse*, Window*, Window*);
@@ -3505,7 +3510,7 @@ void sqlite3WindowCodeInit(Parse*, Window*);
 void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
 int sqlite3WindowRewrite(Parse*, Select*);
 int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
-void sqlite3WindowUpdate(Parse*, Window*, FuncDef*);
+void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
 Window *sqlite3WindowDup(sqlite3 *db, Window *p);
 
 /*
index d2b6e23a642255a5a2cc3f61b94af015f5b6a20a..446f5c129a4ecc6abfc51cbe90b5ea41cd293931 100644 (file)
@@ -387,7 +387,28 @@ void sqlite3WindowFunctions(void){
   sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs));
 }
 
-void sqlite3WindowUpdate(Parse *pParse, Window *pWin, FuncDef *pFunc){
+void sqlite3WindowUpdate(
+  Parse *pParse, 
+  Window *pList, 
+  Window *pWin, 
+  FuncDef *pFunc
+){
+  if( pWin->zName ){
+    Window *p;
+    for(p=pList; p; p=p->pNextWin){
+      if( sqlite3StrICmp(p->zName, pWin->zName)==0 ) break;
+    }
+    if( p==0 ){
+      sqlite3ErrorMsg(pParse, "no such window: %s", pWin->zName);
+      return;
+    }
+    pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0);
+    pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0);
+    pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0);
+    pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0);
+    pWin->eStart = p->eStart;
+    pWin->eEnd = p->eEnd;
+  }
   if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){
     sqlite3 *db = pParse->db;
     if( pFunc->xSFunc==row_numberStepFunc || pFunc->xSFunc==ntileStepFunc ){
@@ -615,10 +636,19 @@ void sqlite3WindowDelete(sqlite3 *db, Window *p){
     sqlite3ExprListDelete(db, p->pOrderBy);
     sqlite3ExprDelete(db, p->pEnd);
     sqlite3ExprDelete(db, p->pStart);
+    sqlite3DbFree(db, p->zName);
     sqlite3DbFree(db, p);
   }
 }
 
+void sqlite3WindowListDelete(sqlite3 *db, Window *p){
+  while( p ){
+    Window *pNext = p->pNextWin;
+    sqlite3WindowDelete(db, p);
+    p = pNext;
+  }
+}
+
 Window *sqlite3WindowAlloc(
   Parse *pParse, 
   int eType,
index 0b34fcdc8f1e0c12182023ac7ae592644a3a598b..9b5299310affac8b362ae414a823072952378f48 100644 (file)
@@ -90,5 +90,12 @@ execsql_test 3.2 {
   SELECT a, nth_value(c, d) OVER (PARTITION BY b ORDER BY a) FROM t5
 }
 
+execsql_test 3.3 {
+  SELECT a, count(*) OVER abc, count(*) OVER def FROM t5
+  WINDOW abc AS (ORDER BY a), 
+         def AS (ORDER BY a DESC)
+  ORDER BY a;
+}
+
 finish_test
 
index 102f3d57e880e34cf043dc729cf51aa22a0c4177..fd49752e71a3e8f1f4266ee298838f17508840a0 100644 (file)
@@ -169,4 +169,11 @@ do_execsql_test 3.2 {
   SELECT a, nth_value(c, d) OVER (PARTITION BY b ORDER BY a) FROM t5
 } {1 {}   3 {}   5 one   2 {}   4 four}
 
+do_execsql_test 3.3 {
+  SELECT a, count(*) OVER abc, count(*) OVER def FROM t5
+  WINDOW abc AS (ORDER BY a), 
+         def AS (ORDER BY a DESC)
+  ORDER BY a;
+} {1 1 5   2 2 4   3 3 3   4 4 2   5 5 1}
+
 finish_test
index 75e691894f420ef7e19c05ed58fb46639846a260..86b0b7dd6bbe1da19df2b0f8461c71c4035ac3ee 100644 (file)
@@ -284,6 +284,7 @@ static Keyword aKeywordTable[] = {
   { "VALUES",           "TK_VALUES",       ALWAYS                 },
   { "VIEW",             "TK_VIEW",         VIEW                   },
   { "VIRTUAL",          "TK_VIRTUAL",      VTAB                   },
+  { "WINDOW",           "TK_WINDOW",       ALWAYS                 },
   { "WITH",             "TK_WITH",         CTE                    },
   { "WITHOUT",          "TK_WITHOUT",      ALWAYS                 },
   { "WHEN",             "TK_WHEN",         ALWAYS                 },