From 81cf13ec7b271740b6c6b7ccd00206e666c6cdc6 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Feb 2014 18:27:53 +0000 Subject: [PATCH] Get rid of the OP_Undef and OP_IsUndef opcodes in favor of higher-level OP_InitCoroutine and OP_EndCoroutine. FossilOrigin-Name: 1ec0e9dd4b26d9f597adc8e062317d4866c5a6a6 --- manifest | 21 ++++++++------ manifest.uuid | 2 +- src/insert.c | 44 +++++++++-------------------- src/select.c | 70 +++++++++++++++------------------------------ src/vdbe.c | 78 ++++++++++++++++++++++++++++++--------------------- src/where.c | 5 ++-- 6 files changed, 97 insertions(+), 123 deletions(-) diff --git a/manifest b/manifest index 9feb2fda5b..87abf54582 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sOP_Undef\sand\sOP_IsUndef\sopcodes.\s\sWith\sthese,\suse\sthe\sfirst\sregister\nin\sthe\sresult\sregister\srange\sas\sthe\sflag\sto\sindicate\sEOF\son\san\sINSERT\sfrom\na\sSELECT,\srather\sthan\sallocating\sa\sseparate\sboolean\sregister\sfor\sthat\stask. -D 2014-02-07T13:20:31.855 +C Get\srid\sof\sthe\sOP_Undef\sand\sOP_IsUndef\sopcodes\sin\sfavor\sof\shigher-level\nOP_InitCoroutine\sand\sOP_EndCoroutine. +D 2014-02-07T18:27:53.008 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 fa98632fbf46e01c7b4d2130558c74b42947f50d +F src/insert.c 5997c3fbd5957b323f851d84d2ede380519cf2f6 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 01d0eca0938b588daabb36cd73e395309bdc6097 F src/shell.c 7dedf7367ee49050b0366bf8dbc8ec2bd15b42c7 F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e @@ -280,7 +280,7 @@ F src/update.c a7df6fffce6bfedc578fda6136dd33e34a63f8ee F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c 15ac2627f548f5481d0d7e6c4eb67be673027695 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c 8697f15ad86604c5a8d598b1566e1594a7956469 +F src/vdbe.c 10ddcf5fd28ff23655b6e953e345c45b42642472 F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26 F src/vdbeInt.h bd6d5e70fe7c80f6aa4c56c34589762b9e933929 F src/vdbeapi.c ce4e68ea4842cc6081046f533d088dcf01d247ad @@ -293,7 +293,7 @@ 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 07179d15d72c1dfffaf7d175d7e26517de04971e F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1152,7 +1152,10 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P be24fbc22106e508975e316abe0471edd3833291 -R 7163c03b39a8cc1205867ee33d31d20c +P 6fb7448550f28a3c93053e125faeaf11de1011d0 +R 0b346c83ba3e4f94eace870fa077c226 +T *branch * coroutine-refactor +T *sym-coroutine-refactor * +T -sym-trunk * U drh -Z 84c60c97897782670b677e52594a24b3 +Z 037b150ffb17771c8c249859dd8749bd diff --git a/manifest.uuid b/manifest.uuid index a1ffd679c6..dfcfb30fb0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6fb7448550f28a3c93053e125faeaf11de1011d0 \ No newline at end of file +1ec0e9dd4b26d9f597adc8e062317d4866c5a6a6 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index edf277876f..c7e60a478e 100644 --- a/src/insert.c +++ b/src/insert.c @@ -373,16 +373,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){ ** yield X ** end loop ** cleanup after the SELECT -** R <- undefined (signals EOF) -** 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 R==undefined goto E +** S: yield X, at EOF goto E ** if skip this row, goto C ** if terminate loop, goto E ** deal with this row @@ -399,18 +396,14 @@ int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){ regYield = ++pParse->nMem; v = sqlite3GetVdbe(pParse); addrTop = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_Integer, addrTop+1, regYield); /* X <- A */ - VdbeComment((v, "Co-routine entry point")); + sqlite3VdbeAddOp2(v, OP_InitCoroutine, regYield, addrTop+2); 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; - sqlite3VdbeAddOp1(v, OP_Undef, pDest->iSdst); /* Signal EOF */ - sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */ - sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort); - VdbeComment((v, "End of coroutine")); + sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); sqlite3VdbeJumpHere(v, j1); /* label B: */ return rc; } @@ -487,12 +480,9 @@ static int xferOptimization( ** yield X ** end loop ** cleanup after the SELECT -** R <- undefined (signals EOF) -** yield X -** goto A +** end-coroutine X ** B: open write cursor to and its indices -** C: yield X -** if R=undefined goto D +** C: yield X, at EOF goto D ** insert the select result into
from R..R+n ** goto C ** D: cleanup @@ -511,12 +501,9 @@ static int xferOptimization( ** yield X ** end loop ** cleanup after the SELECT -** R <- undefined (signals EOF) -** yield X -** halt-error +** end co-routine R ** B: open temp table -** L: yield X -** if R=undefined 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
and its indices @@ -701,8 +688,7 @@ void sqlite3Insert( ** here is from the 4th template: ** ** B: open temp table - ** L: yield X - ** if R=undefined goto M + ** L: yield X, goto M at EOF ** insert row from R..R+n into temp table ** goto L ** M: ... @@ -710,19 +696,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_IsUndef, regFromSelect); 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); } @@ -834,7 +818,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
** end loop @@ -846,14 +830,12 @@ void sqlite3Insert( /* This block codes the top of loop only. The complete loop is the ** following pseudocode (template 3): ** - ** C: yield X - ** if R=undefined goto D + ** C: yield X, at EOF goto D ** insert the select result into
from R..R+n ** goto C ** D: ... */ - addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); - addrInsTop = sqlite3VdbeAddOp1(v, OP_IsUndef, dest.iSdst); + addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); } /* Allocate registers for holding the rowid of the new row, diff --git a/src/select.c b/src/select.c index f923766c85..c82e3d30c5 100644 --- a/src/select.c +++ b/src/select.c @@ -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 ApOffset = 0; regAddrA = ++pParse->nMem; - regEofA = ++pParse->nMem; regAddrB = ++pParse->nMem; - regEofB = ++pParse->nMem; regOutA = ++pParse->nMem; regOutB = ++pParse->nMem; sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); @@ -2730,25 +2723,23 @@ static int multiSelectOrderBy( ** 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")); + VdbeNoopComment((v, "coroutine for left SELECT")); + addrSelectA = sqlite3VdbeCurrentAddr(v); 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); /* Generate a coroutine to evaluate the SELECT statement on ** the right - the "B" select */ + VdbeNoopComment((v, "coroutine for right SELECT")); addrSelectB = sqlite3VdbeCurrentAddr(v); - VdbeNoopComment((v, "Begin coroutine for right SELECT")); savedLimit = p->iLimit; savedOffset = p->iOffset; p->iLimit = regLimitB; @@ -2757,9 +2748,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 +2772,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 +2790,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 +2799,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 +2812,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 +2823,16 @@ 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_InitCoroutine, regAddrA, addrSelectA); + sqlite3VdbeAddOp2(v, OP_InitCoroutine, regAddrB, addrSelectB); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); /* Implement the main merge loop */ @@ -4559,9 +4541,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 +4554,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 +4563,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{ diff --git a/src/vdbe.c b/src/vdbe.c index ab025ac48d..dd854d7c18 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -720,20 +720,62 @@ case OP_Gosub: { /* jump */ /* Opcode: Return P1 * * * * ** -** 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 * * * * +/* Opcode: InitCoroutine P1 P2 * * * +** +** Identify the co-routine at address P2 using the register P1 +** as its return address. Run this opcode prior to the first +** OP_Yield to invoke the co-routine. +*/ +case OP_InitCoroutine: { /* jump */ + assert( pOp->p1>0 ); + assert( pOp->p1<=(p->nMem-p->nCursor) ); + pOut = &aMem[pOp->p1]; + memAboutToChange(p, pOut); + VdbeMemRelease(pOut); + pOut->u.i = pOp->p2 - 1; + pOut->flags = MEM_Int; + 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.inOp ); + pCaller = &aOp[pIn1->u.i]; + assert( pCaller->opcode==OP_Yield ); + assert( pCaller->p2>=0 && pCaller->p2nOp ); + 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 ); @@ -985,21 +1027,6 @@ case OP_Blob: { /* out2-prerelease */ break; } -/* Opcode: Undef P1 * * * * -** Synopsis: r[P1]=undef -** -** Mark register P1 as undefined. -*/ -case OP_Undef: { - assert( pOp->p1>0 ); - assert( pOp->p1<=(p->nMem-p->nCursor) ); - pOut = &aMem[pOp->p1]; - memAboutToChange(p, pOut); - VdbeMemRelease(pOut); - pOut->flags = MEM_Undefined; - break; -} - /* Opcode: Variable P1 P2 * P4 * ** Synopsis: r[P2]=parameter(P1,P4) ** @@ -2154,19 +2181,6 @@ case OP_IfNot: { /* jump, in1 */ break; } -/* Opcode: IsUndef P1 P2 * * * -** Synopsis: if r[P1]==undefined goto P2 -** -** Jump to P2 if the value in register P1 is undefined -*/ -case OP_IsUndef: { /* jump */ - pIn1 = &aMem[pOp->p1]; - if( (pIn1->flags & MEM_Undefined)!=0 ){ - pc = pOp->p2 - 1; - } - break; -} - /* Opcode: IsNull P1 P2 * * * ** Synopsis: if r[P1]==NULL goto P2 ** diff --git a/src/where.c b/src/where.c index a900dd0b84..5ae72e9152 100644 --- a/src/where.c +++ b/src/where.c @@ -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); + sqlite3VdbeAddOp2(v, OP_InitCoroutine, regYield, 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