mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-12 13:01:09 +03:00
When the [https://www.sqlite.org/queryplanner.html#partialsort|block sorting optimization]
is used in a scalar subquery, be sure to exit the loop as soon as the first valid output row is received. Fix for ticket [cb3aa0641d9a4]. FossilOrigin-Name: cdbb0947f9ce18d6d7e29ffab5ea6a2ee5365fbb
This commit is contained in:
21
src/select.c
21
src/select.c
@@ -54,6 +54,7 @@ struct SortCtx {
|
||||
int regReturn; /* Register holding block-output return address */
|
||||
int labelBkOut; /* Start label for the block-output subroutine */
|
||||
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
|
||||
int labelDone; /* Jump here when done, ex: LIMIT reached */
|
||||
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
|
||||
};
|
||||
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
|
||||
@@ -516,6 +517,7 @@ static void pushOntoSorter(
|
||||
int regRecord = ++pParse->nMem; /* Assembled sorter record */
|
||||
int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
|
||||
int op; /* Opcode to add sorter record to sorter */
|
||||
int iLimit; /* LIMIT counter */
|
||||
|
||||
assert( bSeq==0 || bSeq==1 );
|
||||
assert( nData==1 || regData==regOrigData );
|
||||
@@ -526,6 +528,9 @@ static void pushOntoSorter(
|
||||
regBase = pParse->nMem + 1;
|
||||
pParse->nMem += nBase;
|
||||
}
|
||||
assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
|
||||
iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
|
||||
pSort->labelDone = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
|
||||
SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
|
||||
if( bSeq ){
|
||||
@@ -534,7 +539,6 @@ static void pushOntoSorter(
|
||||
if( nPrefixReg==0 ){
|
||||
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
|
||||
if( nOBSat>0 ){
|
||||
int regPrevKey; /* The first nOBSat columns of the previous row */
|
||||
@@ -569,6 +573,10 @@ static void pushOntoSorter(
|
||||
pSort->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
|
||||
if( iLimit ){
|
||||
sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addrFirst);
|
||||
sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
|
||||
sqlite3VdbeJumpHere(v, addrJmp);
|
||||
@@ -579,14 +587,8 @@ static void pushOntoSorter(
|
||||
op = OP_IdxInsert;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
|
||||
if( pSelect->iLimit ){
|
||||
if( iLimit ){
|
||||
int addr;
|
||||
int iLimit;
|
||||
if( pSelect->iOffset ){
|
||||
iLimit = pSelect->iOffset+1;
|
||||
}else{
|
||||
iLimit = pSelect->iLimit;
|
||||
}
|
||||
addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
|
||||
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
|
||||
@@ -1190,7 +1192,7 @@ static void generateSortTail(
|
||||
SelectDest *pDest /* Write the sorted results here */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe; /* The prepared statement */
|
||||
int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
|
||||
int addrBreak = pSort->labelDone; /* Jump here to exit loop */
|
||||
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
|
||||
int addr;
|
||||
int addrOnce = 0;
|
||||
@@ -1209,6 +1211,7 @@ static void generateSortTail(
|
||||
struct ExprList_item *aOutEx = p->pEList->a;
|
||||
#endif
|
||||
|
||||
assert( addrBreak<0 );
|
||||
if( pSort->labelBkOut ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||
sqlite3VdbeGoto(v, addrBreak);
|
||||
|
||||
Reference in New Issue
Block a user