1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-08 03:22:21 +03:00

Change the SRT_Subroutine mode into SRT_Coroutine. Use co-routines in

the INSERT processing logic. (CVS 5255)

FossilOrigin-Name: 6b9d92fc3f265ef75c9182e537812490bb818950
This commit is contained in:
drh
2008-06-20 15:24:01 +00:00
parent 2d1d86fbbe
commit e00ee6eb37
6 changed files with 179 additions and 101 deletions

View File

@@ -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) C Change\sthe\sSRT_Subroutine\smode\sinto\sSRT_Coroutine.\s\sUse\sco-routines\sin\nthe\sINSERT\sprocessing\slogic.\s(CVS\s5255)
D 2008-06-20T14:59:51 D 2008-06-20T15:24:02
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in ff6f90048555a0088f6a4b7406bed5e55a7c4eff F Makefile.in ff6f90048555a0088f6a4b7406bed5e55a7c4eff
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -111,7 +111,7 @@ F src/global.c 2304cfa3288763bd2fed10caf8c6fbaa2b383f4e
F src/hash.c eb64e48f3781100e5934f759fbe72a63a8fe78cb F src/hash.c eb64e48f3781100e5934f759fbe72a63a8fe78cb
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
F src/hwtime.h 745961687a65ef8918cd551c02e5ccb4b8e772de F src/hwtime.h 745961687a65ef8918cd551c02e5ccb4b8e772de
F src/insert.c c2ead6c36566de8e3f130e7ab1431723a269d5d7 F src/insert.c 93231fd0199f044bcefda3d857420f4d377e4056
F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
F src/legacy.c 3626c71fb70912abec9a4312beba753a9ce800df F src/legacy.c 3626c71fb70912abec9a4312beba753a9ce800df
F src/loadext.c 40024a0f476c1279494876b9a002001b29e5d3e3 F src/loadext.c 40024a0f476c1279494876b9a002001b29e5d3e3
@@ -141,11 +141,11 @@ F src/pragma.c 70e7c865dce85fdf9df81848af2169009a56ed08
F src/prepare.c 3c19149e75fbf3b08471a389f064da7302cad9c5 F src/prepare.c 3c19149e75fbf3b08471a389f064da7302cad9c5
F src/printf.c 8b063da9dcde26b7c500a01444b718d86f21bc6e F src/printf.c 8b063da9dcde26b7c500a01444b718d86f21bc6e
F src/random.c 5c754319d38abdd6acd74601ee0105504adc508a F src/random.c 5c754319d38abdd6acd74601ee0105504adc508a
F src/select.c 669687459e7d0193c89de06c5dbed55b4a41191c F src/select.c 672a4812f7bf889176b52d3257bf21d2c08009f1
F src/shell.c a12ea645271b7876c8f080146f48e20b00d367ec F src/shell.c a12ea645271b7876c8f080146f48e20b00d367ec
F src/sqlite.h.in 4c41b702bf6a105a485dfb61065f941c8cb0357d F src/sqlite.h.in 4c41b702bf6a105a485dfb61065f941c8cb0357d
F src/sqlite3ext.h f162a72daef5ebf8b211fe8c0ec96e85d22fbf9b F src/sqlite3ext.h f162a72daef5ebf8b211fe8c0ec96e85d22fbf9b
F src/sqliteInt.h c1ef17f6f9dd356af922bc28647109c97a860976 F src/sqliteInt.h 005b2f0aa10acd20435b46d4a9f84e20855c6f35
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/status.c 6cb10377992505bd69f1ca1d75c1240a65f25a58 F src/status.c 6cb10377992505bd69f1ca1d75c1240a65f25a58
F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822 F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822
@@ -182,7 +182,7 @@ F src/update.c 2d7143b9014e955509cc4f323f9a9584fb898f34
F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b
F src/util.c 920d6d5dfdf25f7b85d2093705d8716f9b387e3b F src/util.c 920d6d5dfdf25f7b85d2093705d8716f9b387e3b
F src/vacuum.c 14eb21b480924d87e791cd8ab6fb35ac563243ef F src/vacuum.c 14eb21b480924d87e791cd8ab6fb35ac563243ef
F src/vdbe.c 7f80262db08ceac0abce2b93034c97aab66b71bc F src/vdbe.c d4b0efeedb4bfb088931addf926e99f4977346c9
F src/vdbe.h 1e3722d471739c2b213c6283b60373290e52f7ea F src/vdbe.h 1e3722d471739c2b213c6283b60373290e52f7ea
F src/vdbeInt.h de321b2c02593e1420106634ed1f5a7d77ad35a7 F src/vdbeInt.h de321b2c02593e1420106634ed1f5a7d77ad35a7
F src/vdbeapi.c a7c6b8db324cf7eccff32de871dea36aa305c994 F src/vdbeapi.c a7c6b8db324cf7eccff32de871dea36aa305c994
@@ -600,7 +600,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P 4ae21e3419ad7e69dd735ca45fdc5a2de93d1840 P 56c8af1452dfdc8da858a2411bd6f3663a8a9326
R d06fe14f86e9e4eba8e97f2719ced042 R 6f87c80d4f9e9e0ffaab864f69d1e048
U danielk1977 U drh
Z 42b4e7b0df5b9e47be1696346ec789df Z d407ea393f3d0c3bac61db977c722528

View File

@@ -1 +1 @@
56c8af1452dfdc8da858a2411bd6f3663a8a9326 6b9d92fc3f265ef75c9182e537812490bb818950

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite. ** 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" #include "sqliteInt.h"
@@ -269,7 +269,8 @@ static int xferOptimization(
** **
** The code generated follows one of four templates. For a simple ** The code generated follows one of four templates. For a simple
** select with data coming from a VALUES clause, the code executes ** 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 ** open write cursor to <table> and its indices
** puts VALUES clause expressions onto the stack ** puts VALUES clause expressions onto the stack
@@ -287,7 +288,7 @@ static int xferOptimization(
** schemas, including all the same indices, then a special optimization ** schemas, including all the same indices, then a special optimization
** is invoked that copies raw records from <table2> over to <table1>. ** is invoked that copies raw records from <table2> over to <table1>.
** See the xferOptimization() function for the implementation of this ** 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 a write cursor to <table>
** open read cursor on <table2> ** open read cursor on <table2>
@@ -300,45 +301,58 @@ static int xferOptimization(
** close cursors ** close cursors
** end foreach ** 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. ** and the SELECT clause does not read from <table> at any time.
** The generated code follows this template: ** The generated code follows this template:
** **
** EOF <- 0
** X <- A
** goto B ** goto B
** A: setup for the SELECT ** A: setup for the SELECT
** loop over the rows in the SELECT ** loop over the rows in the SELECT
** gosub C ** load values into registers R..R+n
** yield X
** end loop ** end loop
** cleanup after the SELECT ** cleanup after the SELECT
** goto D ** EOF <- 1
** B: open write cursor to <table> and its indices ** yield X
** goto A ** goto A
** C: insert the select result into <table> ** B: open write cursor to <table> and its indices
** return ** C: yield X
** if EOF goto D
** insert the select result into <table> from R..R+n
** goto C
** D: cleanup ** 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 ** 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, ** 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 ** we have to use a intermediate table to store the results of
** the select. The template is like this: ** the select. The template is like this:
** **
** EOF <- 0
** X <- A
** goto B ** goto B
** A: setup for the SELECT ** A: setup for the SELECT
** loop over the tables in the SELECT ** loop over the tables in the SELECT
** gosub C ** load value into register R..R+n
** yield X
** end loop ** end loop
** cleanup after the SELECT ** cleanup after the SELECT
** goto D ** EOF <- 1
** C: insert the select result into the intermediate table ** yield X
** return ** halt-error
** B: open a cursor to an intermediate table ** B: open temp table
** goto A ** L: yield X
** D: open write cursor to <table> and its indices ** if EOF goto M
** loop over the intermediate table ** 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> ** transfer values form intermediate table into <table>
** end the loop ** end loop
** cleanup ** D: cleanup
*/ */
void sqlite3Insert( void sqlite3Insert(
Parse *pParse, /* Parser context */ Parse *pParse, /* Parser context */
@@ -362,10 +376,9 @@ void sqlite3Insert(
int endOfLoop; /* Label for the end of the insertion loop */ int endOfLoop; /* Label for the end of the insertion loop */
int useTempTable = 0; /* Store SELECT results in intermediate table */ int useTempTable = 0; /* Store SELECT results in intermediate table */
int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ 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 addrInsTop = 0; /* Jump to label "D" */
int iSelectLoop = 0; /* Address of code that implements the SELECT */ int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */
int iCleanup = 0; /* Address of the cleanup code */ int addrSelect = 0; /* Address of coroutine that implements the SELECT */
int iInsertBlock = 0; /* Address of the subroutine used to insert data */
SelectDest dest; /* Destination for SELECT on rhs of INSERT */ SelectDest dest; /* Destination for SELECT on rhs of INSERT */
int newIdx = -1; /* Cursor for the NEW pseudo-table */ int newIdx = -1; /* Cursor for the NEW pseudo-table */
int iDb; /* Index of database holding TABLE */ int iDb; /* Index of database holding TABLE */
@@ -380,6 +393,7 @@ void sqlite3Insert(
int regRowid; /* registers holding insert rowid */ int regRowid; /* registers holding insert rowid */
int regData; /* register holding first column to insert */ int regData; /* register holding first column to insert */
int regRecord; /* Holds the assemblied row record */ int regRecord; /* Holds the assemblied row record */
int regEof; /* Register recording end of SELECT data */
int *aRegIdx = 0; /* One register allocated to each index */ 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 ** Then special optimizations can be applied that make the transfer
** very fast and which reduce fragmentation of indices. ** very fast and which reduce fragmentation of indices.
**
** This is the 2nd template.
*/ */
if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){ if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
assert( !triggers_exist ); assert( !triggers_exist );
@@ -475,75 +491,104 @@ void sqlite3Insert(
regAutoinc = autoIncBegin(pParse, iDb, pTab); regAutoinc = autoIncBegin(pParse, iDb, pTab);
/* Figure out how many columns of data are supplied. If the data /* Figure out how many columns of data are supplied. If the data
** is coming from a SELECT statement, then this step also generates ** is coming from a SELECT statement, then generate a co-routine that
** all the code to implement the SELECT statement and invoke a subroutine ** produces a single row of the SELECT on each invocation. The
** to process each row of the result. (Template 2.) If the SELECT ** co-routine is the common header to the 3rd and 4th templates.
** 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.)
*/ */
if( pSelect ){ if( pSelect ){
/* Data is coming from a SELECT. Generate code to implement that SELECT /* 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; int rc, j1;
iInitCode = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); regEof = ++pParse->nMem;
iSelectLoop = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
iInsertBlock = sqlite3VdbeMakeLabel(v); VdbeComment((v, "SELECT eof flag"));
sqlite3SelectDestInit(&dest, SRT_Subroutine, iInsertBlock); sqlite3SelectDestInit(&dest, SRT_Coroutine, 0);
dest.regReturn = ++pParse->nMem; 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. */ /* Resolve the expressions in the SELECT statement and execute it. */
rc = sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0); rc = sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);
if( rc || pParse->nErr || db->mallocFailed ){ if( rc || pParse->nErr || db->mallocFailed ){
goto insert_cleanup; 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; regFromSelect = dest.iMem;
iCleanup = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, iCleanup);
assert( pSelect->pEList ); assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr; nColumn = pSelect->pEList->nExpr;
assert( dest.nMem==nColumn );
/* Set useTempTable to TRUE if the result of the SELECT statement /* Set useTempTable to TRUE if the result of the SELECT statement
** should be written into a temporary table. Set to FALSE if each ** should be written into a temporary table (template 4). Set to
** row of the SELECT can be written directly into the result table. ** 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 ** 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 ** of the tables being read by the SELECT statement. Also use a
** temp table in the case of row triggers. ** 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; useTempTable = 1;
} }
if( useTempTable ){ if( useTempTable ){
/* Generate the subroutine that SELECT calls to process each row of /* Invoke the coroutine to extract information from the SELECT
** the result. Store the result in a temporary table ** 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++; srcTab = pParse->nTab++;
regRec = sqlite3GetTempReg(pParse); regRec = sqlite3GetTempReg(pParse);
regRowid = 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); sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid); sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, 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, regRec);
sqlite3ReleaseTempReg(pParse, regRowid); 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{ }else{
/* This is the case if the data for the INSERT is coming from a VALUES /* 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 /* This is the top of the main insertion loop */
** 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.
*/
if( useTempTable ){ if( useTempTable ){
iBreak = sqlite3VdbeMakeLabel(v); /* This block codes the top of loop only. The complete loop is the
sqlite3VdbeAddOp2(v, OP_Rewind, srcTab, iBreak); ** following pseudocode (template 4):
iCont = sqlite3VdbeCurrentAddr(v); **
** 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 ){ }else if( pSelect ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop); /* This block codes the top of loop only. The complete loop is the
sqlite3VdbeResolveLabel(v, iInsertBlock); ** 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, /* 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); sqlite3VdbeResolveLabel(v, endOfLoop);
if( useTempTable ){ if( useTempTable ){
sqlite3VdbeAddOp2(v, OP_Next, srcTab, iCont); sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont);
sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeJumpHere(v, addrInsTop);
sqlite3VdbeAddOp1(v, OP_Close, srcTab); sqlite3VdbeAddOp1(v, OP_Close, srcTab);
}else if( pSelect ){ }else if( pSelect ){
sqlite3VdbeAddOp1(v, OP_Return, dest.regReturn); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrCont);
sqlite3VdbeResolveLabel(v, iCleanup); sqlite3VdbeJumpHere(v, addrInsTop);
} }
if( !IsVirtual(pTab) && !isView ){ if( !IsVirtual(pTab) && !isView ){

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite. ** 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" #include "sqliteInt.h"
@@ -39,7 +39,7 @@ static void clearSelect(Select *p){
void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){ void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
pDest->eDest = eDest; pDest->eDest = eDest;
pDest->iParm = iParm; pDest->iParm = iParm;
pDest->regReturn = 0; pDest->regCoroutine = 0;
pDest->affinity = 0; pDest->affinity = 0;
pDest->iMem = 0; pDest->iMem = 0;
pDest->nMem = 0; pDest->nMem = 0;
@@ -704,15 +704,15 @@ static void selectInnerLoop(
** case of a subroutine, the subroutine itself is responsible for ** case of a subroutine, the subroutine itself is responsible for
** popping the data from the stack. ** popping the data from the stack.
*/ */
case SRT_Subroutine: case SRT_Coroutine:
case SRT_Callback: { case SRT_Callback: {
if( pOrderBy ){ if( pOrderBy ){
int r1 = sqlite3GetTempReg(pParse); int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
pushOntoSorter(pParse, pOrderBy, p, r1); pushOntoSorter(pParse, pOrderBy, p, r1);
sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r1);
}else if( eDest==SRT_Subroutine ){ }else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp2(v, OP_Gosub, pDest->regReturn, iParm); sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
}else{ }else{
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn); sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn);
sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn); sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn);
@@ -810,7 +810,7 @@ static void generateSortTail(
int regRowid; int regRowid;
iTab = pOrderBy->iECursor; iTab = pOrderBy->iECursor;
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ if( eDest==SRT_Callback || eDest==SRT_Coroutine ){
pseudoTab = pParse->nTab++; pseudoTab = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nColumn); sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nColumn);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, pseudoTab, eDest==SRT_Callback); sqlite3VdbeAddOp2(v, OP_OpenPseudo, pseudoTab, eDest==SRT_Callback);
@@ -847,7 +847,7 @@ static void generateSortTail(
} }
#endif #endif
case SRT_Callback: case SRT_Callback:
case SRT_Subroutine: { case SRT_Coroutine: {
int i; int i;
sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid); sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, pseudoTab, regRow, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, pseudoTab, regRow, regRowid);
@@ -858,8 +858,8 @@ static void generateSortTail(
if( eDest==SRT_Callback ){ if( eDest==SRT_Callback ){
sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn); sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn);
sqlite3ExprCacheAffinityChange(pParse, pDest->iMem, nColumn); sqlite3ExprCacheAffinityChange(pParse, pDest->iMem, nColumn);
}else{ }else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp2(v, OP_Gosub, pDest->regReturn, iParm); sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
} }
break; break;
} }
@@ -883,7 +883,7 @@ static void generateSortTail(
sqlite3VdbeResolveLabel(v, cont); sqlite3VdbeResolveLabel(v, cont);
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr);
sqlite3VdbeResolveLabel(v, brk); sqlite3VdbeResolveLabel(v, brk);
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ if( eDest==SRT_Callback || eDest==SRT_Coroutine ){
sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0); 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 ** the result there. The cursor is left open after
** returning. ** returning.
** **
** SRT_Subroutine For each row returned, push the results onto the ** SRT_Coroutine Invoke a co-routine to compute a single row of
** vdbe stack and call the subroutine (via OP_Gosub) ** the result
** at address pDest->iParm.
** **
** SRT_Exists Store a 1 in memory cell pDest->iParm if the result ** SRT_Exists Store a 1 in memory cell pDest->iParm if the result
** set is not empty. ** set is not empty.
@@ -3486,7 +3485,7 @@ int sqlite3Select(
} }
/* Generate code that runs whenever the GROUP BY changes. /* 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. ** block. If there were no changes, this block is skipped.
** **
** This code copies current group by terms in b0,b1,b2,... ** This code copies current group by terms in b0,b1,b2,...

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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_ #ifndef _SQLITEINT_H_
#define _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_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_Table 8 /* Store result as data with an automatic rowid */
#define SRT_EphemTab 9 /* Create transient tab and store like SRT_Table */ #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 ** 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 eDest; /* How to dispose of the results */
u8 affinity; /* Affinity used when eDest==SRT_Set */ u8 affinity; /* Affinity used when eDest==SRT_Set */
int iParm; /* A parameter used by the eDest disposal method */ 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 iMem; /* Base register where results are written */
int nMem; /* Number of registers allocated */ int nMem; /* Number of registers allocated */
int eofMem; /* Register holding EOF flag */
}; };
/* /*

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -785,6 +785,25 @@ case OP_Return: { /* in1 */
break; 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 * /* Opcode: Halt P1 P2 * P4 *
** **
** Exit immediately. All open cursors, Fifos, etc are closed ** Exit immediately. All open cursors, Fifos, etc are closed