]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Pass subtype information through the aggregate ORDER BY sorter for agg-orderby-subtype
authordrh <>
Thu, 14 Dec 2023 13:58:50 +0000 (13:58 +0000)
committerdrh <>
Thu, 14 Dec 2023 13:58:50 +0000 (13:58 +0000)
aggregate functions that use subtype information.

FossilOrigin-Name: 3536f4030eab6d650b7ed729d2f71eb6cc3b5fbe16b4e96b99008d66522aaccb

manifest
manifest.uuid
src/expr.c
src/select.c
src/sqliteInt.h
src/vdbe.c
test/aggorderby.test

index 01a664e4607743102866569a47908e266db853d6..1c3619979eacb9c71cdb901a3c0a8413efc88b05 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Avoid\sinvoking\ssqlite3ExprColUsage()\son\san\sunresolve\scolumn\sreference.\ndbsqlfuzz\sfc34aa62df4de103705d11b807074687ffafbda5.
-D 2023-12-13T16:45:18.334
+C Pass\ssubtype\sinformation\sthrough\sthe\saggregate\sORDER\sBY\ssorter\sfor\naggregate\sfunctions\sthat\suse\ssubtype\sinformation.
+D 2023-12-14T13:58:50.159
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -686,7 +686,7 @@ F src/date.c 3b8d02977d160e128469de38493b4085f7c5cf4073193459909a6af3cf6d7c91
 F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
 F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
 F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
-F src/expr.c 05278def9c186b5875d6903ea26148c7461b9ce0344f0fd7be9a0dfea0a4538a
+F src/expr.c 8f8ed8a5977a54c678755e43aabb3bbe29984025d086128a93e52675987c34eb
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
 F src/func.c 472f6dcfa39cf54f89a6aec76c79c225fb880a6c14469c15d361331662b9bf43
@@ -736,12 +736,12 @@ F src/printf.c 18fbdf028345c8fbe6044f5f5bfda5a10d48d6287afef088cc21b0ca57985640
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c da0a596a645cd7a8a9fd030e5126600b5639cc63f8ead18c1b67ff5a8a9b6a7f
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c 9f55c9f3307b9888f62abe709eec245e98ff217bd14c044f93d72810bb7dc445
+F src/select.c f69e8e37c8bbe3bb02c890ad38a43c36757b87c7863d071d8ecd720732ed46cb
 F src/shell.c.in 0cd2ef4b3c814dded5436625ab664d9a973cbc4266a1768e3aa4cbf11bb41eca
 F src/sqlite.h.in adcc7dbfeea1e69d6d487139a7e90db8a48fe998f3f5bb0f85c683e6a6fa68ca
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h 5456977f4449aeb57d837229730edca0aa43059d93093fbeda48e11cffd065f8
+F src/sqliteInt.h 134457f62bb1d0ff1dd037cc23dd46b1d16efbbfc2211dc2b15c380af731d9ac
 F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -806,7 +806,7 @@ F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242
 F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
 F src/util.c b22cc9f203a8c0b9ee5338a67f8860347d14845864c10248bebe84518a781677
 F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
-F src/vdbe.c f73bead140670fac1aa4227188827ada52387a5fe0ccff0dd5af2a906754d904
+F src/vdbe.c 96ac876e57f480bd35ec8d74ed992bca6ae9deebe8b527a3a718e7b4714d6c2e
 F src/vdbe.h 88e19a982df9027ec1c177c793d1a5d34dc23d8f06e3b2d997f43688b05ee0eb
 F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
 F src/vdbeapi.c 8f57d60c89da0b60e6d4e272358c511f6bae4e24330bdb11f8b42f986d1bf21b
@@ -832,7 +832,7 @@ F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
 F test/aggnested.test ce85a6af7d59c3109e35c5f03b2cd11da1a9b1417371e2f942102d0f0d77fd62
-F test/aggorderby.test e6b98dbbf3ababa96892435d387de2dcf602ef02c2b848d2d817473066f154ba
+F test/aggorderby.test cc3abf5de64d46ff66395ca8c2346b66c2576d5aedb7bffc5b0742508856e3bf
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
 F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
 F test/alter.test 3c00eff1e2036b9f93e9cd0f3d3e63750ac87ecb5bc71b9d7bd07cbf2ac4c494
@@ -2153,8 +2153,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 3e940a6a08b0a0434650cd3d8dd286e09ad8ab805b0a4d515e57bba5d3608577
-R 12c352a17a15c54a5cfe08ba07f54fc8
+P ac9314c0e335694b48c613145f5397247bb88c51806cd0dc3ed4ec306db4bbad
+R 58bb3c6218fca3f2f88129174cf3abf4
+T *branch * agg-orderby-subtype
+T *sym-agg-orderby-subtype *
+T -sym-trunk *
 U drh
-Z 9d3792e688e126d78c7c047eb33fe2f8
+Z a9d93266587a253c256405246043cc2e
 # Remove this line to create a well-formed Fossil manifest.
index 3cebbeb2a11e2069f5414d676435b77b5d578864..edaca4798038ba7e5988e2f482122b014a49a45c 100644 (file)
@@ -1 +1 @@
-ac9314c0e335694b48c613145f5397247bb88c51806cd0dc3ed4ec306db4bbad
\ No newline at end of file
+3536f4030eab6d650b7ed729d2f71eb6cc3b5fbe16b4e96b99008d66522aaccb
\ No newline at end of file
index b5e903d456cb11612e6c3611f1b4ad805a96ceed..756fcc5699812b3b87b835256c24163b5ca50711 100644 (file)
@@ -6821,6 +6821,8 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
               }else{
                 pItem->bOBPayload = 1;
               }
+              pItem->bUseSubtype =
+                    (pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0;
             }else{
               pItem->iOBTab = -1;
             }
index 1beaf5307d52fdcd5a75ad22538cbbf865c8c55a..d5b94e2da2268b6b20739534e309cc104d7eb6ba 100644 (file)
@@ -6659,6 +6659,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
       assert( pFunc->pFExpr->pLeft!=0 );
       assert( pFunc->pFExpr->pLeft->op==TK_ORDER );
       assert( ExprUseXList(pFunc->pFExpr->pLeft) );
+      assert( pFunc->pFunc!=0 );
       pOBList = pFunc->pFExpr->pLeft->x.pList;
       if( !pFunc->bOBUnique ){
         nExtra++;  /* One extra column for the OP_Sequence */
@@ -6668,6 +6669,9 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
         assert( ExprUseXList(pFunc->pFExpr) );
         nExtra += pFunc->pFExpr->x.pList->nExpr;
       }
+      if( pFunc->bUseSubtype ){
+        nExtra += pFunc->pFExpr->x.pList->nExpr;
+      }
       pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra);
       if( !pFunc->bOBUnique && pParse->nErr==0 ){
         pKeyInfo->nKeyField++;
@@ -6694,16 +6698,17 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
     assert( ExprUseXList(pF->pFExpr) );
     pList = pF->pFExpr->x.pList;
     if( pF->iOBTab>=0 ){
-      /* For an ORDER BY aggregate, calls to OP_AggStep where deferred and
-      ** all content was stored in emphermal table pF->iOBTab.  Extract that
-      ** content now (in ORDER BY order) and make all calls to OP_AggStep
+      /* For an ORDER BY aggregate, calls to OP_AggStep were deferred.  Inputs
+      ** were stored in emphermal table pF->iOBTab.  Here, we extract those
+      ** inputs (in ORDER BY order) and make all calls to OP_AggStep
       ** before doing the OP_AggFinal call. */
       int iTop;        /* Start of loop for extracting columns */
       int nArg;        /* Number of columns to extract */
       int nKey;        /* Key columns to be skipped */
       int regAgg;      /* Extract into this array */
       int j;           /* Loop counter */
-      
+     
+      assert( pF->pFunc!=0 );
       nArg = pList->nExpr;
       regAgg = sqlite3GetTempRange(pParse, nArg);
 
@@ -6720,6 +6725,15 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
       for(j=nArg-1; j>=0; j--){
         sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j);
       }
+      if( pF->bUseSubtype ){
+        int regSubtype = sqlite3GetTempReg(pParse);
+        int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0);
+        for(j=nArg-1; j>=0; j--){
+          sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype);
+          sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j);
+        }
+        sqlite3ReleaseTempReg(pParse, regSubtype);
+      }
       sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
       sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
       sqlite3VdbeChangeP5(v, (u8)nArg);
@@ -6774,6 +6788,7 @@ static void updateAccumulator(
     ExprList *pList;
     assert( ExprUseXList(pF->pFExpr) );
     assert( !IsWindowFunc(pF->pFExpr) );
+    assert( pF->pFunc!=0 );
     pList = pF->pFExpr->x.pList;
     if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
       Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
@@ -6818,6 +6833,9 @@ static void updateAccumulator(
       if( pF->bOBPayload ){
         regAggSz += nArg;
       }
+      if( pF->bUseSubtype ){
+        regAggSz += nArg;
+      }
       regAggSz++;  /* One extra register to hold result of MakeRecord */
       regAgg = sqlite3GetTempRange(pParse, regAggSz);
       regDistinct = regAgg;
@@ -6830,6 +6848,14 @@ static void updateAccumulator(
       if( pF->bOBPayload ){
         regDistinct = regAgg+jj;
         sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP);
+        jj += nArg;
+      }
+      if( pF->bUseSubtype ){
+        int kk;
+        int regBase = pF->bOBPayload ? regDistinct : regAgg;
+        for(kk=0; kk<nArg; kk++, jj++){
+          sqlite3VdbeAddOp2(v, OP_GetSubtype, regBase+kk, regAgg+jj);
+        }
       }
     }else if( pList ){
       nArg = pList->nExpr;
index 7d6596909c78ae1ad22ba5782e09897673ab07fc..a21425a14449e2379643f6de1ed3d6ddf2cc3c51 100644 (file)
@@ -2866,6 +2866,7 @@ struct AggInfo {
     int iOBTab;              /* Ephemeral table to implement ORDER BY */
     u8 bOBPayload;           /* iOBTab has payload columns separate from key */
     u8 bOBUnique;            /* Enforce uniqueness on iOBTab keys */
+    u8 bUseSubtype;          /* Transfer subtype info through sorter */
   } *aFunc;
   int nFunc;              /* Number of entries in aFunc[] */
   u32 selId;              /* Select to which this AggInfo belongs */
index 4f710d9a201fbdd43031360e8de00fe88479b410..6d45bbbbbd6927a91652b3b411c8e946e496b51d 100644 (file)
@@ -8674,6 +8674,42 @@ case OP_ClrSubtype: {   /* in1 */
   break;
 }
 
+/* Opcode: GetSubtype P1 P2 * * *
+** Synopsis:  r[P2] = r[P1].subtype
+**
+** Extract the subtype value from register P1 and write that subtype
+** into register P2.  If P1 has no subtype, then P1 gets a NULL.
+*/
+case OP_GetSubtype: {   /* in1 out2 */
+  pIn1 = &aMem[pOp->p1];
+  pOut = &aMem[pOp->p2];
+  if( pIn1->flags & MEM_Subtype ){
+    sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype);
+  }else{
+    sqlite3VdbeMemSetNull(pOut);
+  }
+  break;
+}
+
+/* Opcode: SetSubtype P1 P2 * * *
+** Synopsis:  r[P2].subtype = r[P1]
+**
+** Set the subtype value of register P2 to the integer from register P1.
+** If P1 is NULL, clear the subtype from p2.
+*/
+case OP_SetSubtype: {   /* in1 out2 */
+  pIn1 = &aMem[pOp->p1];
+  pOut = &aMem[pOp->p2];
+  if( pIn1->flags & MEM_Null ){
+    pOut->flags &= ~MEM_Subtype;
+  }else{
+    assert( pIn1->flags & MEM_Int );
+    pOut->flags |= MEM_Subtype;
+    pOut->eSubtype = (u8)(pIn1->u.i & 0xff);
+  }
+  break;
+}
+
 /* Opcode: FilterAdd P1 * P3 P4 *
 ** Synopsis: filter(P1) += key(P3@P4)
 **
index f94c5ec898f3032076e2654415ec27c206d81072..eed1f83a7e00474f92d6520973a77915531f583b 100644 (file)
@@ -118,5 +118,45 @@ do_execsql_test aggorderby-8.2 {
   SELECT sum(DISTINCT x ORDER BY y) FROM c;
 } 6
 
+# Subtype information is transfered through the sorter for aggregates
+# that make use of subtype info.
+#
+do_execsql_test aggorderby-9.0 {
+  WITH c(x,y) AS (VALUES
+    ('{a:3}', 3),
+    ('[1,1]', 1),
+    ('[4,4]', 4),
+    ('{x:2}', 2))
+  SELECT json_group_array(json(x) ORDER BY y) FROM c;
+} {{[[1,1],{"x":2},{"a":3},[4,4]]}}
+do_execsql_test aggorderby-9.1 {
+  WITH c(x,y) AS (VALUES
+    ('[4,4]', 4),
+    ('{a:3}', 3),
+    ('[4,4]', 4),
+    ('[1,1]', 1),
+    ('[4,4]', 4),
+    ('{x:2}', 2))
+  SELECT json_group_array(DISTINCT json(x) ORDER BY y) FROM c;
+} {{[[1,1],{"x":2},{"a":3},[4,4]]}}
+do_execsql_test aggorderby-9.2 {
+  WITH c(x,y) AS (VALUES
+    ('{a:3}', 3),
+    ('[1,1]', 1),
+    ('[4,4]', 4),
+    ('{x:2}', 2))
+  SELECT json_group_array(json(x) ORDER BY json(x)) FROM c;
+} {{[[1,1],[4,4],{"a":3},{"x":2}]}}
+do_execsql_test aggorderby-9.3 {
+  WITH c(x,y) AS (VALUES
+    ('[4,4]', 4),
+    ('{a:3}', 3),
+    ('[4,4]', 4),
+    ('[1,1]', 1),
+    ('[4,4]', 4),
+    ('{x:2}', 2))
+  SELECT json_group_array(DISTINCT json(x) ORDER BY json(x)) FROM c;
+} {{[[1,1],[4,4],{"a":3},{"x":2}]}}
+
 
 finish_test