]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change the SRT_Subroutine mode into SRT_Coroutine. Use co-routines in
authordrh <drh@noemail.net>
Fri, 20 Jun 2008 15:24:01 +0000 (15:24 +0000)
committerdrh <drh@noemail.net>
Fri, 20 Jun 2008 15:24:01 +0000 (15:24 +0000)
the INSERT processing logic. (CVS 5255)

FossilOrigin-Name: 6b9d92fc3f265ef75c9182e537812490bb818950

manifest
manifest.uuid
src/insert.c
src/select.c
src/sqliteInt.h
src/vdbe.c

index 835203e645cb9f2e5ee845a7209c485ae6a8d396..89939ec88bfaffed18cc3155d7b9f0788d135854 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sa\smode\sto\sthe\ssqlite3_test_control()\sinterface\sto\sregister\shooks\scalled\sat\sthe\sbeginning\sand\send\sof\s"benign\smalloc\sfailure"\sblocks.\sThis\sallows\smalloc()\sfailure\stesting\sto\sbe\sdone\susing\spublic\sAPIs\sonly.\s(CVS\s5254)
-D 2008-06-20T14:59:51
+C Change\sthe\sSRT_Subroutine\smode\sinto\sSRT_Coroutine.\s\sUse\sco-routines\sin\nthe\sINSERT\sprocessing\slogic.\s(CVS\s5255)
+D 2008-06-20T15:24:02
 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
 F Makefile.in ff6f90048555a0088f6a4b7406bed5e55a7c4eff
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -111,7 +111,7 @@ F src/global.c 2304cfa3288763bd2fed10caf8c6fbaa2b383f4e
 F src/hash.c eb64e48f3781100e5934f759fbe72a63a8fe78cb
 F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
 F src/hwtime.h 745961687a65ef8918cd551c02e5ccb4b8e772de
-F src/insert.c c2ead6c36566de8e3f130e7ab1431723a269d5d7
+F src/insert.c 93231fd0199f044bcefda3d857420f4d377e4056
 F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
 F src/legacy.c 3626c71fb70912abec9a4312beba753a9ce800df
 F src/loadext.c 40024a0f476c1279494876b9a002001b29e5d3e3
@@ -141,11 +141,11 @@ F src/pragma.c 70e7c865dce85fdf9df81848af2169009a56ed08
 F src/prepare.c 3c19149e75fbf3b08471a389f064da7302cad9c5
 F src/printf.c 8b063da9dcde26b7c500a01444b718d86f21bc6e
 F src/random.c 5c754319d38abdd6acd74601ee0105504adc508a
-F src/select.c 669687459e7d0193c89de06c5dbed55b4a41191c
+F src/select.c 672a4812f7bf889176b52d3257bf21d2c08009f1
 F src/shell.c a12ea645271b7876c8f080146f48e20b00d367ec
 F src/sqlite.h.in 4c41b702bf6a105a485dfb61065f941c8cb0357d
 F src/sqlite3ext.h f162a72daef5ebf8b211fe8c0ec96e85d22fbf9b
-F src/sqliteInt.h c1ef17f6f9dd356af922bc28647109c97a860976
+F src/sqliteInt.h 005b2f0aa10acd20435b46d4a9f84e20855c6f35
 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
 F src/status.c 6cb10377992505bd69f1ca1d75c1240a65f25a58
 F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822
@@ -182,7 +182,7 @@ F src/update.c 2d7143b9014e955509cc4f323f9a9584fb898f34
 F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b
 F src/util.c 920d6d5dfdf25f7b85d2093705d8716f9b387e3b
 F src/vacuum.c 14eb21b480924d87e791cd8ab6fb35ac563243ef
-F src/vdbe.c 7f80262db08ceac0abce2b93034c97aab66b71bc
+F src/vdbe.c d4b0efeedb4bfb088931addf926e99f4977346c9
 F src/vdbe.h 1e3722d471739c2b213c6283b60373290e52f7ea
 F src/vdbeInt.h de321b2c02593e1420106634ed1f5a7d77ad35a7
 F src/vdbeapi.c a7c6b8db324cf7eccff32de871dea36aa305c994
@@ -600,7 +600,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 4ae21e3419ad7e69dd735ca45fdc5a2de93d1840
-R d06fe14f86e9e4eba8e97f2719ced042
-U danielk1977
-Z 42b4e7b0df5b9e47be1696346ec789df
+P 56c8af1452dfdc8da858a2411bd6f3663a8a9326
+R 6f87c80d4f9e9e0ffaab864f69d1e048
+U drh
+Z d407ea393f3d0c3bac61db977c722528
index d41af96b3573c83ef74f67a1993e38b1140ae202..56acee8b61ebdc34f0549febb4dbfda435cfc893 100644 (file)
@@ -1 +1 @@
-56c8af1452dfdc8da858a2411bd6f3663a8a9326
\ No newline at end of file
+6b9d92fc3f265ef75c9182e537812490bb818950
\ No newline at end of file
index 42ce65f854c1d458cc014af1e21ddc7d69cfa223..856228352f973b4be0ed515335b41b04aa55ba4c 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.240 2008/06/06 15:04:37 drh Exp $
+** $Id: insert.c,v 1.241 2008/06/20 15:24:02 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -269,7 +269,8 @@ static int xferOptimization(
 **
 ** The code generated follows one of four templates.  For a simple
 ** select with data coming from a VALUES clause, the code executes
-** once straight down through.  The template looks like this:
+** once straight down through.  Pseudo-code follows (we call this
+** the "1st template"):
 **
 **         open write cursor to <table> and its indices
 **         puts VALUES clause expressions onto the stack
@@ -287,7 +288,7 @@ static int xferOptimization(
 ** schemas, including all the same indices, then a special optimization
 ** is invoked that copies raw records from <table2> over to <table1>.
 ** See the xferOptimization() function for the implementation of this
-** template.  This is the second template.
+** template.  This is the 2nd template.
 **
 **         open a write cursor to <table>
 **         open read cursor on <table2>
@@ -300,45 +301,58 @@ static int xferOptimization(
 **           close cursors
 **         end foreach
 **
-** The third template is for when the second template does not apply
+** The 3rd template is for when the second template does not apply
 ** 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
 **         loop over the rows in the SELECT
-**           gosub C
+**           load values into registers R..R+n
+**           yield X
 **         end loop
 **         cleanup after the SELECT
-**         goto D
-**      B: open write cursor to <table> and its indices
+**         EOF <- 1
+**         yield X
 **         goto A
-**      C: insert the select result into <table>
-**         return
+**      B: open write cursor to <table> and its indices
+**      C: yield X
+**         if EOF goto D
+**         insert the select result into <table> from R..R+n
+**         goto C
 **      D: cleanup
 **
-** The fourth template is used if the insert statement takes its
+** The 4th template is used if the insert statement takes its
 ** values from a SELECT but the data is being inserted into a table
 ** that is also read as part of the SELECT.  In the third form,
 ** 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
 **         loop over the tables in the SELECT
-**           gosub C
+**           load value into register R..R+n
+**           yield X
 **         end loop
 **         cleanup after the SELECT
-**         goto D
-**      C: insert the select result into the intermediate table
-**         return
-**      B: open a cursor to an intermediate table
-**         goto A
-**      D: open write cursor to <table> and its indices
-**         loop over the intermediate table
+**         EOF <- 1
+**         yield X
+**         halt-error
+**      B: open temp table
+**      L: yield X
+**         if EOF goto M
+**         insert row from R..R+n into temp table
+**         goto L
+**      M: open write cursor to <table> and its indices
+**         rewind temp table
+**      C: loop over rows of intermediate table
 **           transfer values form intermediate table into <table>
-**         end the loop
-**         cleanup
+**         end loop
+**      D: cleanup
 */
 void sqlite3Insert(
   Parse *pParse,        /* Parser context */
@@ -362,10 +376,9 @@ void sqlite3Insert(
   int endOfLoop;        /* Label for the end of the insertion loop */
   int useTempTable = 0; /* Store SELECT results in intermediate table */
   int srcTab = 0;       /* Data comes from this temporary cursor if >=0 */
-  int iCont=0,iBreak=0; /* Beginning and end of the loop over srcTab */
-  int iSelectLoop = 0;  /* Address of code that implements the SELECT */
-  int iCleanup = 0;     /* Address of the cleanup code */
-  int iInsertBlock = 0; /* Address of the subroutine used to insert data */
+  int addrInsTop = 0;   /* Jump to label "D" */
+  int addrCont = 0;     /* Top of insert loop. Label "C" in templates 3 and 4 */
+  int addrSelect = 0;   /* Address of coroutine that implements the SELECT */
   SelectDest dest;      /* Destination for SELECT on rhs of INSERT */
   int newIdx = -1;      /* Cursor for the NEW pseudo-table */
   int iDb;              /* Index of database holding TABLE */
@@ -380,6 +393,7 @@ void sqlite3Insert(
   int regRowid;         /* registers holding insert rowid */
   int regData;          /* register holding first column to insert */
   int regRecord;        /* Holds the assemblied row record */
+  int regEof;           /* Register recording end of SELECT data */
   int *aRegIdx = 0;     /* One register allocated to each index */
 
 
@@ -461,6 +475,8 @@ void sqlite3Insert(
   **
   ** Then special optimizations can be applied that make the transfer
   ** very fast and which reduce fragmentation of indices.
+  **
+  ** This is the 2nd template.
   */
   if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
     assert( !triggers_exist );
@@ -475,75 +491,104 @@ void sqlite3Insert(
   regAutoinc = autoIncBegin(pParse, iDb, pTab);
 
   /* Figure out how many columns of data are supplied.  If the data
-  ** is coming from a SELECT statement, then this step also generates
-  ** all the code to implement the SELECT statement and invoke a subroutine
-  ** to process each row of the result. (Template 2.) If the SELECT
-  ** statement uses the the table that is being inserted into, then the
-  ** subroutine is also coded here.  That subroutine stores the SELECT
-  ** results in a temporary table. (Template 3.)
+  ** is coming from a SELECT statement, then generate a co-routine that
+  ** produces a single row of the SELECT on each invocation.  The
+  ** co-routine is the common header to the 3rd and 4th templates.
   */
   if( pSelect ){
     /* Data is coming from a SELECT.  Generate code to implement that SELECT
+    ** as a co-routine.  The code is common to both the 3rd and 4th
+    ** templates:
+    **
+    **         EOF <- 0
+    **         X <- A
+    **         goto B
+    **      A: setup for the SELECT
+    **         loop over the tables in the SELECT
+    **           load value into register R..R+n
+    **           yield X
+    **         end loop
+    **         cleanup after the SELECT
+    **         EOF <- 1
+    **         yield X
+    **         halt-error
+    **
+    ** On each invocation of the co-routine, it puts a single row of the
+    ** SELECT result into registers dest.iMem...dest.iMem+dest.nMem-1.
+    ** (These output registers are allocated by sqlite3Select().)  When
+    ** the SELECT completes, it sets the EOF flag stored in regEof.
     */
-    int rc, iInitCode;
-
-    iInitCode = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
-    iSelectLoop = sqlite3VdbeCurrentAddr(v);
-    iInsertBlock = sqlite3VdbeMakeLabel(v);
-    sqlite3SelectDestInit(&dest, SRT_Subroutine, iInsertBlock);
-    dest.regReturn = ++pParse->nMem;
+    int rc, j1;
+
+    regEof = ++pParse->nMem;
+    sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof);      /* EOF <- 0 */
+    VdbeComment((v, "SELECT eof flag"));
+    sqlite3SelectDestInit(&dest, SRT_Coroutine, 0);
+    dest.regCoroutine = ++pParse->nMem;
+    addrSelect = sqlite3VdbeCurrentAddr(v)+2;
+    sqlite3VdbeAddOp2(v, OP_Integer, addrSelect-1, dest.regCoroutine);
+    j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+    VdbeComment((v, "Jump over SELECT coroutine"));
 
     /* Resolve the expressions in the SELECT statement and execute it. */
     rc = sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);
     if( rc || pParse->nErr || db->mallocFailed ){
       goto insert_cleanup;
     }
+    sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof);         /* EOF <- 1 */
+    sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine);   /* yield X */
+    sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
+    VdbeComment((v, "End of SELECT coroutine"));
+    sqlite3VdbeJumpHere(v, j1);                          /* label B: */
 
     regFromSelect = dest.iMem;
-    iCleanup = sqlite3VdbeMakeLabel(v);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, iCleanup);
     assert( pSelect->pEList );
     nColumn = pSelect->pEList->nExpr;
+    assert( dest.nMem==nColumn );
 
     /* Set useTempTable to TRUE if the result of the SELECT statement
-    ** should be written into a temporary table.  Set to FALSE if each
-    ** row of the SELECT can be written directly into the result table.
+    ** should be written into a temporary table (template 4).  Set to
+    ** FALSE if each* row of the SELECT can be written directly into
+    ** the destination table (template 3).
     **
     ** A temp table must be used if the table being updated is also one
     ** of the tables being read by the SELECT statement.  Also use a 
     ** temp table in the case of row triggers.
     */
-    if( triggers_exist || readsTable(v, iSelectLoop, iDb, pTab) ){
+    if( triggers_exist || readsTable(v, addrSelect, iDb, pTab) ){
       useTempTable = 1;
     }
 
     if( useTempTable ){
-      /* Generate the subroutine that SELECT calls to process each row of
-      ** the result.  Store the result in a temporary table
+      /* Invoke the coroutine to extract information from the SELECT
+      ** and add it to a transient table srcTab.  The code generated
+      ** here is from the 4th template:
+      **
+      **      B: open temp table
+      **      L: yield X
+      **         if EOF goto M
+      **         insert row from R..R+n into temp table
+      **         goto L
+      **      M: ...
       */
-      int regRec, regRowid;
+      int regRec;      /* Register to hold packed record */
+      int regRowid;    /* Register to hold temp table ROWID */
+      int addrTop;     /* Label "L" */
+      int addrIf;      /* Address of jump to M */
 
       srcTab = pParse->nTab++;
       regRec = sqlite3GetTempReg(pParse);
       regRowid = sqlite3GetTempReg(pParse);
-      sqlite3VdbeResolveLabel(v, iInsertBlock);
+      sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
+      addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine);
+      addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof);
       sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
       sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid);
       sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regRowid);
-      sqlite3VdbeAddOp1(v, OP_Return, dest.regReturn);
+      sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
+      sqlite3VdbeJumpHere(v, addrIf);
       sqlite3ReleaseTempReg(pParse, regRec);
       sqlite3ReleaseTempReg(pParse, regRowid);
-
-      /* The following code runs first because the GOTO at the very top
-      ** of the program jumps to it.  Create the temporary table, then jump
-      ** back up and execute the SELECT code above.
-      */
-      sqlite3VdbeJumpHere(v, iInitCode);
-      sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
-      sqlite3VdbeResolveLabel(v, iCleanup);
-    }else{
-      sqlite3VdbeJumpHere(v, iInitCode);
     }
   }else{
     /* This is the case if the data for the INSERT is coming from a VALUES
@@ -657,18 +702,31 @@ void sqlite3Insert(
     }
   }
 
-  /* If the data source is a temporary table, then we have to create
-  ** a loop because there might be multiple rows of data.  If the data
-  ** source is a subroutine call from the SELECT statement, then we need
-  ** to launch the SELECT statement processing.
-  */
+  /* This is the top of the main insertion loop */
   if( useTempTable ){
-    iBreak = sqlite3VdbeMakeLabel(v);
-    sqlite3VdbeAddOp2(v, OP_Rewind, srcTab, iBreak);
-    iCont = sqlite3VdbeCurrentAddr(v);
+    /* This block codes the top of loop only.  The complete loop is the
+    ** following pseudocode (template 4):
+    **
+    **         rewind temp table
+    **      C: loop over rows of intermediate table
+    **           transfer values form intermediate table into <table>
+    **         end loop
+    **      D: ...
+    */
+    addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab);
+    addrCont = sqlite3VdbeCurrentAddr(v);
   }else if( pSelect ){
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
-    sqlite3VdbeResolveLabel(v, iInsertBlock);
+    /* This block codes the top of loop only.  The complete loop is the
+    ** following pseudocode (template 3):
+    **
+    **      C: yield X
+    **         if EOF goto D
+    **         insert the select result into <table> from R..R+n
+    **         goto C
+    **      D: ...
+    */
+    addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine);
+    addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof);
   }
 
   /* Allocate registers for holding the rowid of the new row,
@@ -893,16 +951,17 @@ void sqlite3Insert(
     }
   }
 
-  /* The bottom of the loop, if the data source is a SELECT statement
+  /* The bottom of the main insertion loop, if the data source
+  ** is a SELECT statement.
   */
   sqlite3VdbeResolveLabel(v, endOfLoop);
   if( useTempTable ){
-    sqlite3VdbeAddOp2(v, OP_Next, srcTab, iCont);
-    sqlite3VdbeResolveLabel(v, iBreak);
+    sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont);
+    sqlite3VdbeJumpHere(v, addrInsTop);
     sqlite3VdbeAddOp1(v, OP_Close, srcTab);
   }else if( pSelect ){
-    sqlite3VdbeAddOp1(v, OP_Return, dest.regReturn);
-    sqlite3VdbeResolveLabel(v, iCleanup);
+    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrCont);
+    sqlite3VdbeJumpHere(v, addrInsTop);
   }
 
   if( !IsVirtual(pTab) && !isView ){
index 70f37dc2904c5ed4fd2a219f7c0be3bfac88da56..f66214de0b9652c68ad4c8816a1cfb2db0cd8bc1 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.430 2008/06/06 15:04:37 drh Exp $
+** $Id: select.c,v 1.431 2008/06/20 15:24:02 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -39,7 +39,7 @@ static void clearSelect(Select *p){
 void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
   pDest->eDest = eDest;
   pDest->iParm = iParm;
-  pDest->regReturn = 0;
+  pDest->regCoroutine = 0;
   pDest->affinity = 0;
   pDest->iMem = 0;
   pDest->nMem = 0;
@@ -704,15 +704,15 @@ static void selectInnerLoop(
     ** case of a subroutine, the subroutine itself is responsible for
     ** popping the data from the stack.
     */
-    case SRT_Subroutine:
+    case SRT_Coroutine:
     case SRT_Callback: {
       if( pOrderBy ){
         int r1 = sqlite3GetTempReg(pParse);
         sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
         pushOntoSorter(pParse, pOrderBy, p, r1);
         sqlite3ReleaseTempReg(pParse, r1);
-      }else if( eDest==SRT_Subroutine ){
-        sqlite3VdbeAddOp2(v, OP_Gosub, pDest->regReturn, iParm);
+      }else if( eDest==SRT_Coroutine ){
+        sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
       }else{
         sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn);
         sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn);
@@ -810,7 +810,7 @@ static void generateSortTail(
   int regRowid;
 
   iTab = pOrderBy->iECursor;
-  if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
+  if( eDest==SRT_Callback || eDest==SRT_Coroutine ){
     pseudoTab = pParse->nTab++;
     sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nColumn);
     sqlite3VdbeAddOp2(v, OP_OpenPseudo, pseudoTab, eDest==SRT_Callback);
@@ -847,7 +847,7 @@ static void generateSortTail(
     }
 #endif
     case SRT_Callback:
-    case SRT_Subroutine: {
+    case SRT_Coroutine: {
       int i;
       sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid);
       sqlite3VdbeAddOp3(v, OP_Insert, pseudoTab, regRow, regRowid);
@@ -858,8 +858,8 @@ static void generateSortTail(
       if( eDest==SRT_Callback ){
         sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn);
         sqlite3ExprCacheAffinityChange(pParse, pDest->iMem, nColumn);
-      }else{
-        sqlite3VdbeAddOp2(v, OP_Gosub, pDest->regReturn, iParm);
+      }else if( eDest==SRT_Coroutine ){
+        sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
       }
       break;
     }
@@ -883,7 +883,7 @@ static void generateSortTail(
   sqlite3VdbeResolveLabel(v, cont);
   sqlite3VdbeAddOp2(v, OP_Next, iTab, addr);
   sqlite3VdbeResolveLabel(v, brk);
-  if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
+  if( eDest==SRT_Callback || eDest==SRT_Coroutine ){
     sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
   }
 
@@ -2992,9 +2992,8 @@ void sqlite3SelectMask(Parse *pParse, Select *p, u32 mask){
 **                     the result there. The cursor is left open after
 **                     returning.
 **
-**     SRT_Subroutine  For each row returned, push the results onto the
-**                     vdbe stack and call the subroutine (via OP_Gosub)
-**                     at address pDest->iParm.
+**     SRT_Coroutine   Invoke a co-routine to compute a single row of 
+**                     the result
 **
 **     SRT_Exists      Store a 1 in memory cell pDest->iParm if the result
 **                     set is not empty.
@@ -3486,7 +3485,7 @@ int sqlite3Select(
       }
 
       /* Generate code that runs whenever the GROUP BY changes.
-      ** Change in the GROUP BY are detected by the previous code
+      ** Changes in the GROUP BY are detected by the previous code
       ** block.  If there were no changes, this block is skipped.
       **
       ** This code copies current group by terms in b0,b1,b2,...
index 682bcacedffd4435d495f7f5ab010dbe6a2cd328..d91383d4b8ccdb79150bfb6c1f5700e17f54043b 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.720 2008/06/20 14:59:51 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.721 2008/06/20 15:24:02 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1438,7 +1438,7 @@ struct Select {
 #define SRT_Set          7  /* Store non-null results as keys in an index */
 #define SRT_Table        8  /* Store result as data with an automatic rowid */
 #define SRT_EphemTab     9  /* Create transient tab and store like SRT_Table */
-#define SRT_Subroutine  10  /* Call a subroutine to handle results */
+#define SRT_Coroutine   10  /* Generate a single row of result */
 
 /*
 ** A structure used to customize the behaviour of sqlite3Select(). See
@@ -1449,9 +1449,10 @@ struct SelectDest {
   u8 eDest;         /* How to dispose of the results */
   u8 affinity;      /* Affinity used when eDest==SRT_Set */
   int iParm;        /* A parameter used by the eDest disposal method */
-  int regReturn;    /* Return address register for SRT_Subroutine */
+  int regCoroutine; /* Program counter register for SRT_Coroutine */
   int iMem;         /* Base register where results are written */
   int nMem;         /* Number of registers allocated */
+  int eofMem;       /* Register holding EOF flag */
 };
 
 /*
index 75af3f3f950dea2f339230d58093359543f08f02..2c0d12a70a0ff69e3ba53272fdc9119c16aa76ba 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.750 2008/06/20 14:59:51 danielk1977 Exp $
+** $Id: vdbe.c,v 1.751 2008/06/20 15:24:02 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -785,6 +785,25 @@ case OP_Return: {           /* in1 */
   break;
 }
 
+/* Opcode:  Yield P1 * * * *
+**
+** Swap the program counter with the value in register P1.
+*/
+case OP_Yield: {
+  int pcDest;
+  assert( pOp->p1>0 );
+  assert( pOp->p1<=p->nMem );
+  pIn1 = &p->aMem[pOp->p1];
+  assert( (pIn1->flags & MEM_Dyn)==0 );
+  pIn1->flags = MEM_Int;
+  pcDest = pIn1->u.i;
+  pIn1->u.i = pc;
+  REGISTER_TRACE(pOp->p1, pIn1);
+  pc = pcDest;
+  break;
+}
+
+
 /* Opcode:  Halt P1 P2 * P4 *
 **
 ** Exit immediately.  All open cursors, Fifos, etc are closed