]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Get rid of the OP_Undef and OP_IsUndef opcodes in favor of higher-level
authordrh <drh@noemail.net>
Fri, 7 Feb 2014 18:27:53 +0000 (18:27 +0000)
committerdrh <drh@noemail.net>
Fri, 7 Feb 2014 18:27:53 +0000 (18:27 +0000)
OP_InitCoroutine and OP_EndCoroutine.

FossilOrigin-Name: 1ec0e9dd4b26d9f597adc8e062317d4866c5a6a6

manifest
manifest.uuid
src/insert.c
src/select.c
src/vdbe.c
src/where.c

index 9feb2fda5b1cd301dc6d7a586cac3863af4b10d3..87abf54582189e4337124ed87dadda660004472a 100644 (file)
--- 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
index a1ffd679c60a0e46c7a71b10330a26a69659e5f9..dfcfb30fb08fc9014ac39673835f30ad2be4f456 100644 (file)
@@ -1 +1 @@
-6fb7448550f28a3c93053e125faeaf11de1011d0
\ No newline at end of file
+1ec0e9dd4b26d9f597adc8e062317d4866c5a6a6
\ No newline at end of file
index edf277876fa53b2b13cb801fb3924534809f6020..c7e60a478eafddf7aab7fc60a3a024fc847018d3 100644 (file)
@@ -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 <table> and its indices
-**      C: yield X
-**         if R=undefined goto D
+**      C: yield X, at EOF goto D
 **         insert the select result into <table> 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 <table> 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 <table>
     **         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 <table> 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,
index f923766c85ec8545bf8c02ffb836d77c18b98daf..c82e3d30c5bd136ca891e545ecaba9bb2f0c92ae 100644 (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,9 +2713,7 @@ 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);
@@ -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{
index ab025ac48da07203b33b083e8fcf1db17c3e2b7b..dd854d7c18a97727adba31410bf7a21497e847cb 100644 (file)
@@ -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.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 );
@@ -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
 **
index a900dd0b8401c6cc6789222b77b01af4d82b02a6..5ae72e9152fc87a697baed35ed49028f528e6c5c 100644 (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);
+    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