]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a problem that could occur when a scalar subquery had both a DISTINCT and OFFSET... distinct-offset-subquery-fix
authordan <Dan Kennedy>
Wed, 3 Dec 2025 14:39:25 +0000 (14:39 +0000)
committerdan <Dan Kennedy>
Wed, 3 Dec 2025 14:39:25 +0000 (14:39 +0000)
FossilOrigin-Name: 496bbff910b73775b16c1ccb95dadf37416d3f3032722a1140f2a9134666d7f1

manifest
manifest.tags
manifest.uuid
src/expr.c
src/select.c
test/subquery2.test

index 73febf3f6369e48be9b136fe0dff578c7f0041af..9e978b448161dd95b9d05865b394032ab1f29bf3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Clarification\sof\scomment\stext\sin\sexpr.c.\s\sNo\schanges\sto\scode.
-D 2025-12-03T12:07:35.684
+C Fix\sa\sproblem\sthat\scould\soccur\swhen\sa\sscalar\ssubquery\shad\sboth\sa\sDISTINCT\sand\sOFFSET\sclause.\sFirst\sreported\sby\s[forum:41bd7af485\s|\sforum\spost\s41bd7af485].
+D 2025-12-03T14:39:25.881
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -687,7 +687,7 @@ F src/date.c e19e0cfff9a41bfdd884c655755f6f00bca4c1a22272b56e0dd6667b7ea893a2
 F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
 F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
 F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
-F src/expr.c 684f391581c62cb0ff6e37e05b5642e5a5c938f07897fbf6d0ae58de96a2c555
+F src/expr.c 0f65d201a4f1f3ff1bb49a40af896fd7082a7f28dae138d0b9150d94b0db1e5b
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
 F src/func.c 0b802107498048d3dcac0b757720bcb8506507ce02159e213ab8161458eb293b
@@ -736,7 +736,7 @@ F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c 6a509cddd815d64f6141e539fff633a518a393772a44dffb4490f7fc3f0d83a9
+F src/select.c e556448217b0d6d42f47cfa79bc9b667a9cb26cedce77cf41f91be2bd535a6ca
 F src/shell.c.in 62b286951404fd72c116bb3b96b5ee9330de4dc4c8753ca33967ca1a47b3b972
 F src/sqlite.h.in 706cacea5308b0244fb6cec92e08310fb427a125375c64137cc1f878ae4cf5c0
 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
@@ -1675,7 +1675,7 @@ F test/strict1.test a7f9091603fe71cdc62baab0766684cba12a97ec69bfbb70be965532669c
 F test/strict2.test b22c7a98b5000aef937f1990776497f0e979b1a23bc4f63e2d53b00e59b20070
 F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49
 F test/subquery.test 23087f9b1c15ab9cc5231d04946bdebc51db527c95eb9d7434a2222127e17a84
-F test/subquery2.test 5f06ec2dbce42a3f595ab1b73b146592f9ce001cd4ff023d887d643d3560c281
+F test/subquery2.test ab96ff3fa9c4e3dce0d699f74e61c50250ed4335bc8f400e127707d552a8999e
 F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303
 F test/substr.test a673e3763e247e9b5e497a6cacbaf3da2bd8ec8921c0677145c109f2e633f36b
 F test/subtype1.test 96fd2a59bfc845c955b5f339d23b37ef4d50de5f8a04acd1450a68605fa2e3e7
@@ -2183,8 +2183,11 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P bccc0d65b0fb617f6c8eb111b6717d3ad419f80d3495dc5c6a69ccd0771b3d9d
-R b657241f08cf4f1a9f15fdda4d21e254
-U drh
-Z 32d06a64dcd8b620cb1a299ac970a7bc
+P afe5ee64f1cde4945c878220b029f2a22578c2bccda4fddc005c4e6a4718c6cd
+R 047e6324568940b4556b75113b868f2a
+T *branch * distinct-offset-subquery-fix
+T *sym-distinct-offset-subquery-fix *
+T -sym-trunk *
+U dan
+Z 769c0bdc01c64bb06852dc79c8e1f0eb
 # Remove this line to create a well-formed Fossil manifest.
index bec971799ff1b8ee641c166c7aeb22d12c785393..90125c283842a1d27306c3dd2ba9760c412ff068 100644 (file)
@@ -1,2 +1,2 @@
-branch trunk
-tag trunk
+branch distinct-offset-subquery-fix
+tag distinct-offset-subquery-fix
index 87aad9cf83144338efd1cdc1ecef86687ed4b3d0..dfe56a33cb2ff7ab5d5795fccccb2fea804a6b06 100644 (file)
@@ -1 +1 @@
-afe5ee64f1cde4945c878220b029f2a22578c2bccda4fddc005c4e6a4718c6cd
+496bbff910b73775b16c1ccb95dadf37416d3f3032722a1140f2a9134666d7f1
index 2eb271cec57297be666c38d46ea176cae8392af9..8a47b978daf05aaf55d8d6af0a1b9f834a20f3ee 100644 (file)
@@ -3891,9 +3891,22 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
   pParse->nMem += nReg;
   if( pExpr->op==TK_SELECT ){
     dest.eDest = SRT_Mem;
-    dest.iSdst = dest.iSDParm;
+    if( (pSel->selFlags&SF_Distinct) && pSel->pLimit && pSel->pLimit->pRight ){
+      /* If there is both a DISTINCT and an OFFSET clause, then allocate
+      ** a separate dest.iSdst array for sqlite3Select() and other
+      ** routines to populate. In this case results will be copied over
+      ** into the dest.iSDParm array only after OFFSET processing. This
+      ** ensures that in the case where OFFSET excludes all rows, the
+      ** dest.iSDParm array is not left populated with the contents of the
+      ** last row visited - it should be all NULLs if all rows were
+      ** excluded by OFFSET.  */ 
+      dest.iSdst = pParse->nMem+1;
+      pParse->nMem += nReg;
+    }else{
+      dest.iSdst = dest.iSDParm;
+    }
     dest.nSdst = nReg;
-    sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
+    sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, pParse->nMem);
     VdbeComment((v, "Init subquery result"));
   }else{
     dest.eDest = SRT_Exists;
index 0a00e769bab355757755cea0ce64a6b866ab0022..4aac5a27b16948331742126bd7e5fe2c75e6687e 100644 (file)
@@ -1445,9 +1445,14 @@ static void selectInnerLoop(
         assert( nResultCol<=pDest->nSdst );
         pushOntoSorter(
             pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
+        pDest->iSDParm = regResult;
       }else{
         assert( nResultCol==pDest->nSdst );
-        assert( regResult==iParm );
+        if( regResult!=iParm ){
+          /* This occurs in cases where the SELECT had both a DISTINCT and
+          ** an OFFSET clause.  */
+          sqlite3VdbeAddOp3(v, OP_Copy, regResult, iParm, nResultCol-1);
+        }
         /* The LIMIT clause will jump out of the loop for us */
       }
       break;
index 8513dc75c89631dce58eb2a8d15b6c3e3f122132..99a1e903f88bcaefd9537b2265c2d2fe359f2646 100644 (file)
@@ -215,4 +215,72 @@ do_execsql_test 5.1 {
   SELECT ( SELECT y FROM t2 WHERE x = y ORDER BY y, z) FROM t1;
 } {ALFKI ANATR}
 
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 6.0 {
+  CREATE TABLE t1(x);
+  INSERT INTO t1 VALUES(1234);
+}
+
+do_execsql_test 6.1 {
+  SELECT DISTINCT 'string' FROM t1 LIMIT 1 OFFSET 5;
+}
+
+do_execsql_test 6.2 {
+  SELECT (
+      SELECT 'string' FROM t1 LIMIT 1 OFFSET 5
+  );
+} {{}}
+
+do_execsql_test 6.3 {
+  SELECT (
+      SELECT DISTINCT 'string' FROM t1 LIMIT 1 OFFSET 5
+  );
+} {{}}
+
+do_execsql_test 6.4 {
+  SELECT (
+      SELECT DISTINCT 'string' FROM t1 ORDER BY 1 LIMIT 1 OFFSET 5
+  );
+} {{}}
+
+do_execsql_test 6.5 {
+  SELECT (
+      SELECT 'string' FROM t1 ORDER BY 1 LIMIT 1 OFFSET 5
+  );
+} {{}}
+
+do_execsql_test 6.6 {
+  SELECT (SELECT DISTINCT x, x FROM t1 LIMIT 1 OFFSET 5)==(1234, 1234)
+} {{}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 7.0 {
+  CREATE TABLE t1(x);
+  CREATE INDEX i1 ON t1(x);
+  INSERT INTO t1 VALUES(1234);
+}
+
+do_execsql_test 7.1 {
+  SELECT (
+    SELECT DISTINCT 'string' FROM t1 ORDER BY x LIMIT 1 OFFSET 5
+  );
+} {{}}
+
+do_execsql_test 7.2 {
+  DROP INDEX i1;
+  CREATE UNIQUE INDEX i1 ON t1(x);
+}
+
+do_execsql_test 7.3 {
+  SELECT (
+    SELECT DISTINCT x FROM t1 ORDER BY 1 LIMIT 1 OFFSET 5
+  );
+} {{}}
+
+do_execsql_test 7.4 {
+  SELECT (SELECT DISTINCT x FROM t1 ORDER BY +x LIMIT 1 OFFSET 0);
+} {1234}
+
 finish_test