]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Strive to use sort-and-merge for compounds in CTEs.
authordrh <>
Tue, 20 Jan 2026 20:10:41 +0000 (20:10 +0000)
committerdrh <>
Tue, 20 Jan 2026 20:10:41 +0000 (20:10 +0000)
FossilOrigin-Name: 73ed1c790bb386a2981bf7076d23d37e09fa9db3966a7a164b8964fdb14fdad2

manifest
manifest.uuid
src/select.c

index 1634a474ff98509d5ff2609f33780f84fdb085f4..4f35eb5b0a5fdc79c9cd43c4cd1f737857198a92 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sanother\stest\scase\sto\swork\swith\sunion-by-merge.
-D 2026-01-20T18:20:26.522
+C Strive\sto\suse\ssort-and-merge\sfor\scompounds\sin\sCTEs.
+D 2026-01-20T20:10:41.063
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -738,7 +738,7 @@ F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c db7af5c5e3cdcbf4ce443f5540cfa782e0fd4de5481af9814c188f05aef8193c
+F src/select.c a300ac348b149c82da7172c5e3f26db241da78bf49c845123d1e58857bb8962b
 F src/shell.c.in 3bc4c6aa962bdf950dc144c2138eb4bc734bf7e305f2ac42dbda5a83c4a4c660
 F src/sqlite.h.in 476f3efeb5dd26ad94dcbce262ca7eb9d042d797a92d624059c67ef37d5b3ab4
 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
@@ -2193,8 +2193,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 305ae331f5e791941c12b04b727656ac8d80f7c5cb6343277b979a456eb3b834
-R 1dcd216b82c87d29b591dc0d9d114a92
+P 8279c10e2465838010508f6018aa6fdb0e07ca3639f65e727a03a4222573ea57
+R 16b4bd1b72d09c171ba72aad5924a60e
 U drh
-Z 1a9bb683198c5bd95f9016dd1a04cf65
+Z a45ecc98b465af55dedd358b42f7fbbf
 # Remove this line to create a well-formed Fossil manifest.
index 333cc0f013b2251184ce7f1aa5ef5f7da75a8ec8..2502e2af769bd505a62cd90cbdfbad08943f8d30 100644 (file)
@@ -1 +1 @@
-8279c10e2465838010508f6018aa6fdb0e07ca3639f65e727a03a4222573ea57
+73ed1c790bb386a2981bf7076d23d37e09fa9db3966a7a164b8964fdb14fdad2
index abd0fee8a50109fe4a40f98d66908f5f1accbe82..5abfa1f8ea570dfe28e40828d06acded5bbc7815 100644 (file)
@@ -2779,7 +2779,6 @@ static void generateWithRecursiveQuery(
   /* Store the results of the setup-query in Queue. */
   pSetup = pFirstRec->pPrior;
   pSetup->pNext = 0;
-  pSetup->selFlags |= SF_NoMerge;
   ExplainQueryPlan((pParse, 1, "SETUP"));
   rc = sqlite3Select(pParse, pSetup, &destQueue);
   pSetup->pNext = p;
@@ -3325,8 +3324,8 @@ void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
 ** Code an output subroutine for a coroutine implementation of a
 ** SELECT statement.
 **
-** The data to be output is contained in pIn->iSdst.  There are
-** pIn->nSdst columns to be output.  pDest is where the output should
+** The data to be output is contained in an array of pIn->nSdst registers
+** starting at register pIn->iSdst.  pDest is where the output should
 ** be sent.
 **
 ** regReturn is the number of the register holding the subroutine
@@ -3381,13 +3380,31 @@ static int generateOutputSubroutine(
   switch( pDest->eDest ){
     /* Store the result as data using a unique key.
     */
+    case SRT_Fifo:
+    case SRT_DistFifo:
     case SRT_EphemTab: {
       int r1 = sqlite3GetTempReg(pParse);
       int r2 = sqlite3GetTempReg(pParse);
+      int iParm = pDest->iSDParm;
       sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1);
-      sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iSDParm, r2);
-      sqlite3VdbeAddOp3(v, OP_Insert, pDest->iSDParm, r1, r2);
+#ifndef SQLITE_OMIT_CTE
+      if( pDest->eDest==SRT_DistFifo ){
+        /* If the destination is DistFifo, then cursor (iParm+1) is open
+        ** on an ephemeral index. If the current row is already present
+        ** in the index, do not write it to the output. If not, add the
+        ** current row to the index and proceed with writing it to the
+        ** output table as well.  */
+        int addr = sqlite3VdbeCurrentAddr(v) + 4; /* After OP_Insert */
+        sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); /* 20260120a */
+        VdbeCoverage(v);
+        sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,
+                             pIn->iSdst, pIn->nSdst);
+      }
+#endif
+      sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
+      sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
       sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+      /* The OP_Found at 20260120a jumps here, after the OP_Insert */
       sqlite3ReleaseTempReg(pParse, r2);
       sqlite3ReleaseTempReg(pParse, r1);
       break;
@@ -3439,6 +3456,55 @@ static int generateOutputSubroutine(
       break;
     }
 
+#ifndef SQLITE_OMIT_CTE
+    /* Write the results into a priority queue that is order according to
+    ** pDest->pOrderBy (in pSO).  pDest->iSDParm (in iParm) is the cursor for an
+    ** index with pSO->nExpr+2 columns.  Build a key using pSO for the first
+    ** pSO->nExpr columns, then make sure all keys are unique by adding a
+    ** final OP_Sequence column.  The last column is the record as a blob.
+    */
+    case SRT_DistQueue:
+    case SRT_Queue: {
+      int nKey;
+      int r1, r2, r3, ii;
+      int addrTest = 0;
+      ExprList *pSO;
+      int iParm = pDest->iSDParm;
+      pSO = pDest->pOrderBy;
+      assert( pSO );
+      nKey = pSO->nExpr;
+      r1 = sqlite3GetTempReg(pParse);
+      r2 = sqlite3GetTempRange(pParse, nKey+2);
+      r3 = r2+nKey+1;
+      if( pDest->eDest==SRT_DistQueue ){
+        /* If the destination is DistQueue, then cursor (iParm+1) is open
+        ** on a second ephemeral index that holds all values every previously
+        ** added to the queue. */
+        addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0,
+                                        pIn->iSdst, pIn->nSdst);
+        VdbeCoverage(v);
+      }
+      sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r3);
+      if( pDest->eDest==SRT_DistQueue ){
+        sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3);
+        sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
+      }
+      for(ii=0; ii<nKey; ii++){
+        sqlite3VdbeAddOp2(v, OP_SCopy,
+                          pIn->iSdst + pSO->a[ii].u.x.iOrderByCol - 1,
+                          r2+ii);
+      }
+      sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey);
+      sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1);
+      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2);
+      if( addrTest ) sqlite3VdbeJumpHere(v, addrTest);
+      sqlite3ReleaseTempReg(pParse, r1);
+      sqlite3ReleaseTempRange(pParse, r2, nKey+2);
+      break;
+    }
+#endif /* SQLITE_OMIT_CTE */
+
+
     /* If none of the above, then the result destination must be
     ** SRT_Output.  This routine is never called with any other
     ** destination other than the ones handled above or SRT_Output.