mirror of
https://github.com/sqlite/sqlite.git
synced 2025-09-11 08:30:57 +03:00
Merge the latest trunk changes (especially "PRAGMA busy_timeout" and the
ORDER BY query planner optimizations) into the sessions branch. FossilOrigin-Name: 6ca8eae1f89d19ee23cbc3a869d85b57d29b4a7d
This commit is contained in:
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;
|
||||
|
Reference in New Issue
Block a user