Add opcodes OP_InitCoroutine and OP_EndCoroutine. Use these to remove the

need for separate boolean registers to record when a co-routine has finished.

FossilOrigin-Name: 5a88b6a7aef3a0d5380e19eee2ee38439cc9b08b
This commit is contained in:
drh 2014-02-07 22:21:07 +00:00
commit 642364a48b
9 changed files with 121 additions and 139 deletions

View File

@ -1,5 +1,5 @@
C Fix\sredundant\sdefinitions\sof\s_LARGE_FILE\sand\s_LARGEFILE_SOURCE.
D 2014-02-07T19:33:31.352
C Add\sopcodes\sOP_InitCoroutine\sand\sOP_EndCoroutine.\s\sUse\sthese\sto\sremove\sthe\nneed\sfor\sseparate\sboolean\sregisters\sto\srecord\swhen\sa\sco-routine\shas\sfinished.
D 2014-02-07T22:21:07.782
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -183,7 +183,7 @@ F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c a4450f0c46a9f221622e6551ab0953b03c4f8ee8
F src/insert.c b50cb5a51edb0d6e1a99e04b232b8632a54e522a
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
@ -219,7 +219,7 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c b78f5e62c283aca2e38657938bc1fec1051df728
F src/select.c 47d93e6f0b58000e2093e7b489bdca778884f82a
F src/shell.c 7dedf7367ee49050b0366bf8dbc8ec2bd15b42c7
F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
@ -280,20 +280,20 @@ F src/update.c a7df6fffce6bfedc578fda6136dd33e34a63f8ee
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
F src/util.c 15ac2627f548f5481d0d7e6c4eb67be673027695
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c 575189caf33bc3f2b9557f420e9b815afcd5ace8
F src/vdbe.c e7bb0587ad4866c0db5fe3b83104c4df8f93d19f
F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26
F src/vdbeInt.h 42db251e9f863401ff847b90d5fe1614c89a6a56
F src/vdbeInt.h b5d62957a408c4bea649484008e5f98335b09e97
F src/vdbeapi.c ce4e68ea4842cc6081046f533d088dcf01d247ad
F src/vdbeaux.c a3327afa8cfcc5bb3d38f2b2a599bac5fb63c6be
F src/vdbeaux.c 3fd95b226330e1d50aedb40d750effe726ebb3fb
F src/vdbeblob.c 9542e116c1db5ed813977581d506c176e117c0ec
F src/vdbemem.c 23cdc14ed43e0aafa57bd72b9bf3d5b1641afa91
F src/vdbemem.c c0bcc02d6816ab4218ac0f94b63c8ee78a0f739f
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
F src/where.c bacb79fb31e082c9c599e68e5e9f161e1d5430ca
F src/where.c 8c2aada8b44140382406cf07b84ff2f6127cb39e
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@ -1152,7 +1152,8 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P ea4d23d1c0df4fde2e532daa081888712f465884
R fe35814af819067492f7e22674ab8b60
P 4043d879795bfad55af35e9cb48e0a42eb4087ae a522f364a6b8ca6f69c353b30609a2166f6e94cf
R fcb91b77c89313a695cdcaff36627dad
T +closed a522f364a6b8ca6f69c353b30609a2166f6e94cf
U drh
Z bbbf5c390e5238e969c1eb355ec42634
Z 935dc7a454a2a09335ff0c234e8fb57e

View File

@ -1 +1 @@
4043d879795bfad55af35e9cb48e0a42eb4087ae
5a88b6a7aef3a0d5380e19eee2ee38439cc9b08b

View File

@ -349,17 +349,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){
** co-routine. Run the co-routine to its next breakpoint
** by calling "OP_Yield $X" where $X is pDest->iSDParm.
**
** pDest->iSDParm+1 The register holding the "completed" flag for the
** co-routine. This register is 0 if the previous Yield
** generated a new result row, or 1 if the subquery
** has completed. If the Yield is called again
** after this register becomes 1, then the VDBE will
** halt with an SQLITE_INTERNAL error.
**
** pDest->iSdst First result register.
**
** pDest->nSdst Number of result registers.
**
** At EOF the first result register will be marked as "undefined" so that
** the caller can know when to stop reading results.
**
** This routine handles all of the register allocation and fills in the
** pDest structure appropriately.
**
@ -370,7 +366,6 @@ void sqlite3AutoincrementEnd(Parse *pParse){
** reg[pDest->iSdst+pDest->nSdst-1]:
**
** X <- A
** EOF <- 0
** goto B
** A: setup for the SELECT
** loop rows in the SELECT
@ -378,16 +373,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){
** yield X
** end loop
** cleanup after the SELECT
** EOF <- 1
** yield X
** halt-error
** end co-routine R
** B:
**
** To use this subroutine, the caller generates code as follows:
**
** [ Co-routine generated by this subroutine, shown above ]
** S: yield X
** if EOF goto E
** S: yield X, at EOF goto E
** if skip this row, goto C
** if terminate loop, goto E
** deal with this row
@ -396,31 +388,21 @@ void sqlite3AutoincrementEnd(Parse *pParse){
*/
int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
int regYield; /* Register holding co-routine entry-point */
int regEof; /* Register holding co-routine completion flag */
int addrTop; /* Top of the co-routine */
int j1; /* Jump instruction */
int rc; /* Result code */
Vdbe *v; /* VDBE under construction */
regYield = ++pParse->nMem;
regEof = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
addrTop = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_Integer, addrTop+2, regYield); /* X <- A */
VdbeComment((v, "Co-routine entry point"));
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
VdbeComment((v, "Co-routine completion flag"));
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield);
j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
rc = sqlite3Select(pParse, pSelect, pDest);
assert( pParse->nErr==0 || rc );
if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM;
if( rc ) return rc;
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
VdbeComment((v, "End of coroutine"));
sqlite3VdbeJumpHere(v, j1); /* label B: */
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
return rc;
}
@ -488,7 +470,6 @@ static int xferOptimization(
** and the SELECT clause does not read from <table> at any time.
** The generated code follows this template:
**
** EOF <- 0
** X <- A
** goto B
** A: setup for the SELECT
@ -497,12 +478,9 @@ static int xferOptimization(
** yield X
** end loop
** cleanup after the SELECT
** EOF <- 1
** yield X
** goto A
** end-coroutine X
** B: open write cursor to <table> and its indices
** C: yield X
** if EOF goto D
** C: yield X, at EOF goto D
** insert the select result into <table> from R..R+n
** goto C
** D: cleanup
@ -513,7 +491,6 @@ static int xferOptimization(
** we have to use a intermediate table to store the results of
** the select. The template is like this:
**
** EOF <- 0
** X <- A
** goto B
** A: setup for the SELECT
@ -522,12 +499,9 @@ static int xferOptimization(
** yield X
** end loop
** cleanup after the SELECT
** EOF <- 1
** yield X
** halt-error
** end co-routine R
** B: open temp table
** L: yield X
** if EOF goto M
** L: yield X, at EOF goto M
** insert row from R..R+n into temp table
** goto L
** M: open write cursor to <table> and its indices
@ -576,7 +550,6 @@ void sqlite3Insert(
int regIns; /* Block of regs holding rowid+data being inserted */
int regRowid; /* registers holding insert rowid */
int regData; /* register holding first column to insert */
int regEof = 0; /* Register recording end of SELECT data */
int *aRegIdx = 0; /* One register allocated to each index */
#ifndef SQLITE_OMIT_TRIGGER
@ -689,7 +662,6 @@ void sqlite3Insert(
int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
if( rc ) goto insert_cleanup;
regEof = dest.iSDParm + 1;
regFromSelect = dest.iSdst;
assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr;
@ -714,8 +686,7 @@ void sqlite3Insert(
** here is from the 4th template:
**
** B: open temp table
** L: yield X
** if EOF goto M
** L: yield X, goto M at EOF
** insert row from R..R+n into temp table
** goto L
** M: ...
@ -723,19 +694,17 @@ void sqlite3Insert(
int regRec; /* Register to hold packed record */
int regTempRowid; /* Register to hold temp table ROWID */
int addrTop; /* Label "L" */
int addrIf; /* Address of jump to M */
srcTab = pParse->nTab++;
regRec = sqlite3GetTempReg(pParse);
regTempRowid = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
sqlite3VdbeJumpHere(v, addrIf);
sqlite3VdbeJumpHere(v, addrTop);
sqlite3ReleaseTempReg(pParse, regRec);
sqlite3ReleaseTempReg(pParse, regTempRowid);
}
@ -847,7 +816,7 @@ void sqlite3Insert(
/* This block codes the top of loop only. The complete loop is the
** following pseudocode (template 4):
**
** rewind temp table
** rewind temp table, if empty goto D
** C: loop over rows of intermediate table
** transfer values form intermediate table into <table>
** end loop
@ -859,14 +828,12 @@ void sqlite3Insert(
/* This block codes the top of loop only. The complete loop is the
** following pseudocode (template 3):
**
** C: yield X
** if EOF goto D
** C: yield X, at EOF goto D
** insert the select result into <table> from R..R+n
** goto C
** D: ...
*/
addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof);
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
}
/* Allocate registers for holding the rowid of the new row,

View File

@ -765,12 +765,8 @@ static void selectInnerLoop(
}
#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
/* Send the data to the callback function or to a subroutine. In the
** case of a subroutine, the subroutine itself is responsible for
** popping the data from the stack.
*/
case SRT_Coroutine:
case SRT_Output: {
case SRT_Coroutine: /* Send data to a co-routine */
case SRT_Output: { /* Return the results */
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pOrderBy ){
@ -2572,9 +2568,7 @@ static int multiSelectOrderBy(
SelectDest destA; /* Destination for coroutine A */
SelectDest destB; /* Destination for coroutine B */
int regAddrA; /* Address register for select-A coroutine */
int regEofA; /* Flag to indicate when select-A is complete */
int regAddrB; /* Address register for select-B coroutine */
int regEofB; /* Flag to indicate when select-B is complete */
int addrSelectA; /* Address of the select-A coroutine */
int addrSelectB; /* Address of the select-B coroutine */
int regOutA; /* Address register for the output-A subroutine */
@ -2582,6 +2576,7 @@ static int multiSelectOrderBy(
int addrOutA; /* Address of the output-A subroutine */
int addrOutB = 0; /* Address of the output-B subroutine */
int addrEofA; /* Address of the select-A-exhausted subroutine */
int addrEofA_noB; /* Alternate addrEofA if B is uninitialized */
int addrEofB; /* Address of the select-B-exhausted subroutine */
int addrAltB; /* Address of the A<B subroutine */
int addrAeqB; /* Address of the A==B subroutine */
@ -2718,37 +2713,30 @@ static int multiSelectOrderBy(
p->pOffset = 0;
regAddrA = ++pParse->nMem;
regEofA = ++pParse->nMem;
regAddrB = ++pParse->nMem;
regEofB = ++pParse->nMem;
regOutA = ++pParse->nMem;
regOutB = ++pParse->nMem;
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
/* Jump past the various subroutines and coroutines to the main
** merge loop
*/
j1 = sqlite3VdbeAddOp0(v, OP_Goto);
addrSelectA = sqlite3VdbeCurrentAddr(v);
/* Generate a coroutine to evaluate the SELECT statement to the
** left of the compound operator - the "A" select.
*/
VdbeNoopComment((v, "Begin coroutine for left SELECT"));
addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
VdbeComment((v, "left SELECT"));
pPrior->iLimit = regLimitA;
explainSetInteger(iSub1, pParse->iNextSelectId);
sqlite3Select(pParse, pPrior, &destA);
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
VdbeNoopComment((v, "End coroutine for left SELECT"));
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
sqlite3VdbeJumpHere(v, j1);
/* Generate a coroutine to evaluate the SELECT statement on
** the right - the "B" select
*/
addrSelectB = sqlite3VdbeCurrentAddr(v);
VdbeNoopComment((v, "Begin coroutine for right SELECT"));
addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
VdbeComment((v, "right SELECT"));
savedLimit = p->iLimit;
savedOffset = p->iOffset;
p->iLimit = regLimitB;
@ -2757,9 +2745,7 @@ static int multiSelectOrderBy(
sqlite3Select(pParse, p, &destB);
p->iLimit = savedLimit;
p->iOffset = savedOffset;
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB);
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
VdbeNoopComment((v, "End coroutine for right SELECT"));
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
/* Generate a subroutine that outputs the current row of the A
** select as the next output row of the compound select.
@ -2783,13 +2769,12 @@ static int multiSelectOrderBy(
/* Generate a subroutine to run when the results from select A
** are exhausted and only data in select B remains.
*/
VdbeNoopComment((v, "eof-A subroutine"));
if( op==TK_EXCEPT || op==TK_INTERSECT ){
addrEofA = sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd);
addrEofA_noB = addrEofA = labelEnd;
}else{
addrEofA = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
VdbeNoopComment((v, "eof-A subroutine"));
addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
p->nSelectRow += pPrior->nSelectRow;
}
@ -2802,9 +2787,8 @@ static int multiSelectOrderBy(
if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
}else{
VdbeNoopComment((v, "eof-B subroutine"));
addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofB);
}
@ -2812,8 +2796,7 @@ static int multiSelectOrderBy(
*/
VdbeNoopComment((v, "A-lt-B subroutine"));
addrAltB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
/* Generate code to handle the case of A==B
@ -2826,8 +2809,7 @@ static int multiSelectOrderBy(
}else{
VdbeNoopComment((v, "A-eq-B subroutine"));
addrAeqB =
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
}
@ -2838,19 +2820,14 @@ static int multiSelectOrderBy(
if( op==TK_ALL || op==TK_UNION ){
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
}
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
/* This code runs once to initialize everything.
*/
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB);
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrA, addrSelectA);
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrB, addrSelectB);
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
/* Implement the main merge loop
*/
@ -4559,9 +4536,7 @@ int sqlite3Select(
** set on each invocation.
*/
int addrTop;
int addrEof;
pItem->regReturn = ++pParse->nMem;
addrEof = ++pParse->nMem;
/* Before coding the OP_Goto to jump to the start of the main routine,
** ensure that the jump to the verify-schema routine has already
** been coded. Otherwise, the verify-schema would likely be coded as
@ -4574,10 +4549,8 @@ int sqlite3Select(
sqlite3VdbeAddOp0(v, OP_Goto);
addrTop = sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor);
sqlite3VdbeChangeP5(v, 1);
VdbeComment((v, "coroutine for %s", pItem->pTab->zName));
VdbeComment((v, "coroutine %s", pItem->pTab->zName));
pItem->addrFillSub = addrTop;
sqlite3VdbeAddOp2(v, OP_Integer, 0, addrEof);
sqlite3VdbeChangeP5(v, 1);
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
@ -4585,9 +4558,7 @@ int sqlite3Select(
pItem->viaCoroutine = 1;
sqlite3VdbeChangeP2(v, addrTop, dest.iSdst);
sqlite3VdbeChangeP3(v, addrTop, dest.nSdst);
sqlite3VdbeAddOp2(v, OP_Integer, 1, addrEof);
sqlite3VdbeAddOp1(v, OP_Yield, pItem->regReturn);
VdbeComment((v, "end %s", pItem->pTab->zName));
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
sqlite3VdbeJumpHere(v, addrTop-1);
sqlite3ClearTempRegCache(pParse);
}else{

View File

@ -393,7 +393,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
** Print the value of a register for tracing purposes:
*/
static void memTracePrint(Mem *p){
if( p->flags & MEM_Invalid ){
if( p->flags & MEM_Undefined ){
printf(" undefined");
}else if( p->flags & MEM_Null ){
printf(" NULL");
@ -702,7 +702,6 @@ check_for_interrupt:
}
/* Opcode: Gosub P1 P2 * * *
** Synopsis: r[P1]=pc; pc=P2
**
** Write the current address onto register P1
** and then jump to address P2.
@ -720,23 +719,67 @@ case OP_Gosub: { /* jump */
}
/* Opcode: Return P1 * * * *
** Synopsis: pc=r[P1]+1
**
** Jump to the next instruction after the address in register P1.
** Jump to the next instruction after the address in register P1. After
** the jump, register P1 becomes undefined.
*/
case OP_Return: { /* in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags & MEM_Int );
assert( pIn1->flags==MEM_Int );
pc = (int)pIn1->u.i;
pIn1->flags = MEM_Undefined;
break;
}
/* Opcode: Yield P1 * * * *
** Synopsis: swap(pc,r[P1])
/* Opcode: InitCoroutine P1 P2 P3 * *
**
** Set up register P1 so that it will OP_Yield to the co-routine
** located at address P3.
**
** If P2!=0 then the co-routine implementation immediately follows
** this opcode. So jump over the co-routine implementation to
** address P2.
*/
case OP_InitCoroutine: { /* jump */
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
assert( pOp->p2>=0 && pOp->p2<p->nOp );
assert( pOp->p3>=0 && pOp->p3<p->nOp );
pOut = &aMem[pOp->p1];
assert( !VdbeMemDynamic(pOut) );
pOut->u.i = pOp->p3 - 1;
pOut->flags = MEM_Int;
if( pOp->p2 ) pc = pOp->p2 - 1;
break;
}
/* Opcode: EndCoroutine P1 * * * *
**
** The instruction at the address in register P1 is an OP_Yield.
** Jump to the P2 parameter of that OP_Yield.
** After the jump, register P1 becomes undefined.
*/
case OP_EndCoroutine: { /* in1 */
VdbeOp *pCaller;
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags==MEM_Int );
assert( pIn1->u.i>=0 && pIn1->u.i<p->nOp );
pCaller = &aOp[pIn1->u.i];
assert( pCaller->opcode==OP_Yield );
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
pc = pCaller->p2 - 1;
pIn1->flags = MEM_Undefined;
break;
}
/* Opcode: Yield P1 P2 * * *
**
** Swap the program counter with the value in register P1.
**
** If the co-routine ends with OP_Yield or OP_Return then continue
** to the next instruction. But if the co-routine ends with
** OP_EndCoroutine, jump immediately to P2.
*/
case OP_Yield: { /* in1 */
case OP_Yield: { /* in1, jump */
int pcDest;
pIn1 = &aMem[pOp->p1];
assert( (pIn1->flags & MEM_Dyn)==0 );
@ -974,7 +1017,7 @@ case OP_Null: { /* out2-prerelease */
}
/* Opcode: Blob P1 P2 * P4
/* Opcode: Blob P1 P2 * P4 *
** Synopsis: r[P2]=P4 (len=P1)
**
** P4 points to a blob of data P1 bytes long. Store this
@ -5191,7 +5234,7 @@ case OP_Program: { /* jump */
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
pMem->flags = MEM_Invalid;
pMem->flags = MEM_Undefined;
pMem->db = db;
}
}else{

View File

@ -198,7 +198,7 @@ struct Mem {
#define MEM_Blob 0x0010 /* Value is a BLOB */
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
#define MEM_Invalid 0x0080 /* Value is undefined */
#define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
#define MEM_TypeMask 0x01ff /* Mask of type bits */
@ -230,7 +230,7 @@ struct Mem {
** is for use inside assert() statements only.
*/
#ifdef SQLITE_DEBUG
#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
#define memIsValid(M) ((M)->flags & MEM_Undefined)==0
#endif
/*
@ -425,9 +425,10 @@ int sqlite3VdbeMemNumerify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
void sqlite3VdbeMemReleaseExternal(Mem *p);
#define VdbeMemDynamic(X) \
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
#define VdbeMemRelease(X) \
if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \
sqlite3VdbeMemReleaseExternal(X);
if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X);
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
const char *sqlite3OpcodeName(int);
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);

View File

@ -1234,7 +1234,7 @@ static void releaseMemArray(Mem *p, int N){
p->zMalloc = 0;
}
p->flags = MEM_Invalid;
p->flags = MEM_Undefined;
}
db->mallocFailed = malloc_failed;
}
@ -1702,7 +1702,7 @@ void sqlite3VdbeMakeReady(
p->aMem--; /* aMem[] goes from 1..nMem */
p->nMem = nMem; /* not from 0..nMem-1 */
for(n=1; n<=nMem; n++){
p->aMem[n].flags = MEM_Invalid;
p->aMem[n].flags = MEM_Undefined;
p->aMem[n].db = db;
}
}
@ -1814,7 +1814,7 @@ static void Cleanup(Vdbe *p){
int i;
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
if( p->aMem ){
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid );
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
}
#endif

View File

@ -587,7 +587,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
Mem *pX;
for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
if( pX->pScopyFrom==pMem ){
pX->flags |= MEM_Invalid;
pX->flags |= MEM_Undefined;
pX->pScopyFrom = 0;
}
}

View File

@ -2785,10 +2785,9 @@ static Bitmask codeOneLoopStart(
/* Special case of a FROM clause subquery implemented as a co-routine */
if( pTabItem->viaCoroutine ){
int regYield = pTabItem->regReturn;
sqlite3VdbeAddOp2(v, OP_Integer, pTabItem->addrFillSub-1, regYield);
pLevel->p2 = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
VdbeComment((v, "next row of co-routine %s", pTabItem->pTab->zName));
sqlite3VdbeAddOp2(v, OP_If, regYield+1, addrBrk);
pLevel->op = OP_Goto;
}else