Factor out the code that generates a co-routine for evaluating the SELECT
on the RHS of an INSERT statement so that the same code can potentially be reused in other places. FossilOrigin-Name: a93ee09cdc15987848bf9023e69892ce9a5f989e
This commit is contained in:
parent
6ec6549158
commit
5f08526937
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C Improved\salignment\sof\sfields\sin\sthe\sExpr\sobject\sgives\san\s8-byte\ssize\nreduction\son\s64-bit\smachines.
|
||||
D 2012-09-13T19:59:09.165
|
||||
C Factor\sout\sthe\scode\sthat\sgenerates\sa\sco-routine\sfor\sevaluating\sthe\sSELECT\non\sthe\sRHS\sof\san\sINSERT\sstatement\sso\sthat\sthe\ssame\scode\scan\spotentially\nbe\sreused\sin\sother\splaces.
|
||||
D 2012-09-15T13:29:23.328
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -138,7 +138,7 @@ F src/global.c 4cfdca5cb0edd33c4d021baec4ede958cb2c793b
|
||||
F src/hash.c a4031441741932da9e7a65bee2b36b5d0e81c073
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c b090d0a9fb9ff2dbdeaf66aedccf98cd13b1af60
|
||||
F src/insert.c 6e2aa7fbb5d4c5f34d412772751ed0aff0b9e87b
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
|
||||
@ -179,7 +179,7 @@ F src/shell.c 87953c5d9c73d9494db97d1607e2e2280418f261
|
||||
F src/sqlite.h.in d1071b0fc6de9a0d11392bc01305803122c3ec61
|
||||
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h 03ad3f925f07599cc39a7eebdb250c7f17fd57e6
|
||||
F src/sqliteInt.h 0423f0a673e7365827584e86dfbab8c33cf32cf8
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@ -1013,7 +1013,7 @@ F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
|
||||
P 0ebe7cc57408d6d85910cc976fb8af4436d6e594
|
||||
R b742c79022ff08cfe99db98bba004b78
|
||||
P 6b252a0d1a78db7bf2d650bafc214ea4064eef9e
|
||||
R df7cddb2132aa1a021f32020fc480477
|
||||
U drh
|
||||
Z 3cb58e8f20dd1433c3550c4182838eb5
|
||||
Z c609d2d14d939fff56bf9fbc82b9e705
|
||||
|
@ -1 +1 @@
|
||||
6b252a0d1a78db7bf2d650bafc214ea4064eef9e
|
||||
a93ee09cdc15987848bf9023e69892ce9a5f989e
|
140
src/insert.c
140
src/insert.c
@ -320,6 +320,97 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
|
||||
|
||||
/*
|
||||
** Generate code for a co-routine that will evaluate a subquery one
|
||||
** row at a time.
|
||||
**
|
||||
** The pSelect parameter is the subquery that the co-routine will evaluation.
|
||||
** Information about the location of co-routine and the registers it will use
|
||||
** is returned by filling in the pDest object.
|
||||
**
|
||||
** Registers are allocated as follows:
|
||||
**
|
||||
** pDest->iSDParm The register holding the next entry-point of the
|
||||
** co-routine. Run the co-routine to its next breakpoint
|
||||
** by calling "OP_Yield $X" where $X is pDest->iSDParm.
|
||||
**
|
||||
** pDest->iSDParm+1 The register holding the "completed" flag for the
|
||||
** co-routine. This register is 0 if the previous Yield
|
||||
** generated a new result row, or 1 if the subquery
|
||||
** has completed. If the Yield is called again
|
||||
** after this register becomes 1, then the VDBE will
|
||||
** halt with an SQLITE_INTERNAL error.
|
||||
**
|
||||
** pDest->iSdst First result register.
|
||||
**
|
||||
** pDest->nSdst Number of result registers.
|
||||
**
|
||||
** This routine handles all of the register allocation and fills in the
|
||||
** pDest structure appropriately.
|
||||
**
|
||||
** Here is a schematic of the generated code assuming that X is the
|
||||
** co-routine entry-point register reg[pDest->iSDParm], that EOF is the
|
||||
** completed flag reg[pDest->iSDParm+1], and R and S are the range of
|
||||
** registers that hold the result set, reg[pDest->iSdst] through
|
||||
** reg[pDest->iSdst+pDest->nSdst-1]:
|
||||
**
|
||||
** X <- A
|
||||
** EOF <- 0
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
** loop rows in the SELECT
|
||||
** load results into registers R..S
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** halt-error
|
||||
** B:
|
||||
**
|
||||
** To use this subroutine, the caller generates code as follows:
|
||||
**
|
||||
** [ Co-routine generated by this subroutine, shown above ]
|
||||
** S: yield X
|
||||
** if EOF goto E
|
||||
** if skip this row, goto C
|
||||
** if terminate loop, goto E
|
||||
** deal with this row
|
||||
** C: goto S
|
||||
** E:
|
||||
*/
|
||||
int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int regEof; /* Register holding co-routine completion flag */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int j1; /* Jump instruction */
|
||||
int rc; /* Result code */
|
||||
Vdbe *v; /* VDBE under construction */
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
regEof = ++pParse->nMem;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
addrTop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, addrTop+2, regYield); /* X <- A */
|
||||
VdbeComment((v, "Co-routine entry point"));
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
|
||||
VdbeComment((v, "Co-routine completion flag"));
|
||||
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;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
|
||||
VdbeComment((v, "End of coroutine"));
|
||||
sqlite3VdbeJumpHere(v, j1); /* label B: */
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Forward declaration */
|
||||
static int xferOptimization(
|
||||
Parse *pParse, /* Parser context */
|
||||
@ -568,51 +659,12 @@ void sqlite3Insert(
|
||||
** 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, j1;
|
||||
|
||||
regEof = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
|
||||
VdbeComment((v, "SELECT eof flag"));
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, ++pParse->nMem);
|
||||
addrSelect = sqlite3VdbeCurrentAddr(v)+2;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, addrSelect-1, dest.iSDParm);
|
||||
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);
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( rc || NEVER(pParse->nErr) || db->mallocFailed ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); /* yield X */
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
|
||||
VdbeComment((v, "End of SELECT coroutine"));
|
||||
sqlite3VdbeJumpHere(v, j1); /* label B: */
|
||||
/* Data is coming from a SELECT. Generate a co-routine to run that
|
||||
** SELECT. */
|
||||
int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
|
||||
if( rc ) goto insert_cleanup;
|
||||
|
||||
regEof = dest.iSDParm + 1;
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( pSelect->pEList );
|
||||
nColumn = pSelect->pEList->nExpr;
|
||||
|
@ -2780,6 +2780,7 @@ void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
# define sqlite3AutoincrementBegin(X)
|
||||
# define sqlite3AutoincrementEnd(X)
|
||||
#endif
|
||||
int sqlite3CodeCoroutine(Parse*, Select*, SelectDest*);
|
||||
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
||||
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
||||
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
|
||||
|
Loading…
x
Reference in New Issue
Block a user