-C Add\sa\scomment\sto\ssqlite3Stat4Value()\sexplaining\sthat\sit\sread\sa\sfew\sbytes\spast\sthe\send\sof\sthe\sspecified\sbuffer.
-D 2026-01-28T10:52:53.788
+C Improved\s(faster)\sbytecode\sfor\sthe\smerge\salgorithm.
+D 2026-01-28T16:59:34.852
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c 89db4768dc2ffed05755e072006dd13455cd387a2c169f167b48c1d48c56b257
+F src/select.c 4bee1bb231771e7c6e5aef243b1f74c3d330df5a005909d5e2c338fb1510fe55
F src/shell.c.in d7c1041d6ad00bee2515842a1950640afe424df2e89ad2d6e3b9e68b184824a5
F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 631c8d44cd1624ddc45babd3f0d810908c2a368784744262042c63506ff2e333
-R 9d3d16bae5779cc20645971566ff547b
-U dan
-Z 967d464084320ff484ef70ae7aceb51f
+P b95644eafdd42293096a3760af8b2110f3c7d83feecdeff5ff9f008d9748e874
+R e12fe81159464b3fa2ae49533a88f39a
+U drh
+Z 443016052e3b7e21943bf488170474d9
# Remove this line to create a well-formed Fossil manifest.
*/
static KeyInfo *multiSelectByMergeKeyInfo(Parse *pParse, Select *p, int nExtra){
ExprList *pOrderBy = p->pOrderBy;
- int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0;
+ int nOrderBy = (pOrderBy!=0) ? pOrderBy->nExpr : 0;
sqlite3 *db = pParse->db;
KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1);
if( pRet ){
** AeqB: ...
** AgtB: ...
** Init: initialize coroutine registers
-** yield coA
-** if eof(A) goto EofA
-** yield coB
-** if eof(B) goto EofB
+** yield coA, on eof goto EofA
+** yield coB, on eof goto EofB
** Cmpr: Compare A, B
** Jump AltB, AeqB, AgtB
** End: ...
}
/* Compute the comparison permutation and keyinfo that is used with
- ** the permutation used to determine if the next
- ** row of results comes from selectA or selectB. Also add explicit
- ** collations to the ORDER BY clause terms so that when the subqueries
- ** to the right and the left are evaluated, they use the correct
- ** collation.
+ ** the permutation to determine if the next row of results comes
+ ** from selectA or selectB. Also add literal collations to the
+ ** ORDER BY clause terms so that when selectA and selectB are
+ ** evaluated, they use the correct collation.
*/
aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
if( aPermute ){
struct ExprList_item *pItem;
+ int bKeep = 0;
aPermute[0] = nOrderBy;
for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
assert( pItem!=0 );
assert( pItem->u.x.iOrderByCol>0 );
assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
aPermute[i] = pItem->u.x.iOrderByCol - 1;
+ if( aPermute[i]!=i-1 ) bKeep = 1;
+ }
+ if( bKeep==0 ){
+ sqlite3DbFreeNN(db, aPermute);
+ aPermute = 0;
}
- pKeyMerge = multiSelectByMergeKeyInfo(pParse, p, 1);
- }else{
- pKeyMerge = 0;
}
+ pKeyMerge = multiSelectByMergeKeyInfo(pParse, p, 1);
/* Allocate a range of temporary registers and the KeyInfo needed
** for the logic that removes duplicate result rows when the
/* Generate code to handle the case of A<B
*/
- VdbeNoopComment((v, "SUBR: A-lt-B"));
addrAltB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
VdbeComment((v, "out-A"));
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA); VdbeCoverage(v);
addrAeqB = addrAltB;
addrAltB++;
}else{
- VdbeNoopComment((v, "SUBR: A-eq-B"));
- addrAeqB =
- sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA); VdbeCoverage(v);
- VdbeComment((v, "next-A"));
- sqlite3VdbeGoto(v, labelCmpr);
+ addrAeqB = addrAltB + 1;
}
/* Generate code to handle the case of A>B
*/
- VdbeNoopComment((v, "SUBR: A-gt-B"));
addrAgtB = sqlite3VdbeCurrentAddr(v);
if( op==TK_ALL || op==TK_UNION ){
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
VdbeComment((v, "out-B"));
+ sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
+ VdbeComment((v, "next-B"));
+ sqlite3VdbeGoto(v, labelCmpr);
+ }else{
+ addrAgtB++; /* Just do next-B. Might as well use the next-B call
+ ** in the next code block */
}
- sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
- VdbeComment((v, "next-B"));
- sqlite3VdbeGoto(v, labelCmpr);
/* This code runs once to initialize everything.
*/
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v);
+ VdbeComment((v, "next-A"));
+ /* v--- Also the A>B case for EXCEPT and INTERSECT */
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
+ VdbeComment((v, "next-B"));
/* Implement the main merge loop
*/
+ if( aPermute!=0 ){
+ sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY);
+ }
sqlite3VdbeResolveLabel(v, labelCmpr);
- sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY);
sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
(char*)pKeyMerge, P4_KEYINFO);
- sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
+ if( aPermute!=0 ){
+ sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
+ }
sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
VdbeCoverageIf(v, op==TK_ALL);
VdbeCoverageIf(v, op==TK_UNION);