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:
20
manifest
20
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
|
||||
|
||||
@@ -1 +1 @@
|
||||
56c8af1452dfdc8da858a2411bd6f3663a8a9326
|
||||
6b9d92fc3f265ef75c9182e537812490bb818950
|
||||
203
src/insert.c
203
src/insert.c
@@ -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;
|
||||
int rc, j1;
|
||||
|
||||
iInitCode = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
||||
iSelectLoop = sqlite3VdbeCurrentAddr(v);
|
||||
iInsertBlock = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3SelectDestInit(&dest, SRT_Subroutine, iInsertBlock);
|
||||
dest.regReturn = ++pParse->nMem;
|
||||
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 ){
|
||||
|
||||
27
src/select.c
27
src/select.c
@@ -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,...
|
||||
|
||||
@@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
21
src/vdbe.c
21
src/vdbe.c
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user