From: drh Date: Fri, 7 Feb 2014 13:20:31 +0000 (+0000) Subject: Add the OP_Undef and OP_IsUndef opcodes. With these, use the first register X-Git-Tag: version-3.8.4~97^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a5750cfe01b8fb83cf7382fc04b288c0b649b023;p=thirdparty%2Fsqlite.git Add the OP_Undef and OP_IsUndef opcodes. With these, use the first register in the result register range as the flag to indicate EOF on an INSERT from a SELECT, rather than allocating a separate boolean register for that task. FossilOrigin-Name: 6fb7448550f28a3c93053e125faeaf11de1011d0 --- diff --git a/manifest b/manifest index 5537506c47..9feb2fda5b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\scomment\supdates.\s\sNo\schanges\sto\scode. -D 2014-02-07T03:28:02.783 +C Add\sthe\sOP_Undef\sand\sOP_IsUndef\sopcodes.\s\sWith\sthese,\suse\sthe\sfirst\sregister\nin\sthe\sresult\sregister\srange\sas\sthe\sflag\sto\sindicate\sEOF\son\san\sINSERT\sfrom\na\sSELECT,\srather\sthan\sallocating\sa\sseparate\sboolean\sregister\sfor\sthat\stask. +D 2014-02-07T13:20:31.855 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -183,7 +183,7 @@ F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486 F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c a4450f0c46a9f221622e6551ab0953b03c4f8ee8 +F src/insert.c fa98632fbf46e01c7b4d2130558c74b42947f50d F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b @@ -280,13 +280,13 @@ F src/update.c a7df6fffce6bfedc578fda6136dd33e34a63f8ee F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c 15ac2627f548f5481d0d7e6c4eb67be673027695 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c 575189caf33bc3f2b9557f420e9b815afcd5ace8 +F src/vdbe.c 8697f15ad86604c5a8d598b1566e1594a7956469 F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26 -F src/vdbeInt.h 42db251e9f863401ff847b90d5fe1614c89a6a56 +F src/vdbeInt.h bd6d5e70fe7c80f6aa4c56c34589762b9e933929 F src/vdbeapi.c ce4e68ea4842cc6081046f533d088dcf01d247ad -F src/vdbeaux.c a3327afa8cfcc5bb3d38f2b2a599bac5fb63c6be +F src/vdbeaux.c 3fd95b226330e1d50aedb40d750effe726ebb3fb F src/vdbeblob.c 9542e116c1db5ed813977581d506c176e117c0ec -F src/vdbemem.c 23cdc14ed43e0aafa57bd72b9bf3d5b1641afa91 +F src/vdbemem.c c0bcc02d6816ab4218ac0f94b63c8ee78a0f739f F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd @@ -1152,7 +1152,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 1122b410de68a3c79b4c719a3a4cc4dc6a5bb39d -R ba81bea358565b1489c187d643f4773f -U mistachkin -Z fafd555fb9fada47058f4a33fbcaaf41 +P be24fbc22106e508975e316abe0471edd3833291 +R 7163c03b39a8cc1205867ee33d31d20c +U drh +Z 84c60c97897782670b677e52594a24b3 diff --git a/manifest.uuid b/manifest.uuid index affff2d9c4..a1ffd679c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -be24fbc22106e508975e316abe0471edd3833291 \ No newline at end of file +6fb7448550f28a3c93053e125faeaf11de1011d0 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index a2366360c7..edf277876f 100644 --- a/src/insert.c +++ b/src/insert.c @@ -349,17 +349,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){ ** 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. ** +** At EOF the first result register will be marked as "undefined" so that +** the caller can know when to stop reading results. +** ** This routine handles all of the register allocation and fills in the ** pDest structure appropriately. ** @@ -370,7 +366,6 @@ void sqlite3AutoincrementEnd(Parse *pParse){ ** reg[pDest->iSdst+pDest->nSdst-1]: ** ** X <- A -** EOF <- 0 ** goto B ** A: setup for the SELECT ** loop rows in the SELECT @@ -378,7 +373,7 @@ void sqlite3AutoincrementEnd(Parse *pParse){ ** yield X ** end loop ** cleanup after the SELECT -** EOF <- 1 +** R <- undefined (signals EOF) ** yield X ** halt-error ** B: @@ -387,7 +382,7 @@ void sqlite3AutoincrementEnd(Parse *pParse){ ** ** [ Co-routine generated by this subroutine, shown above ] ** S: yield X -** if EOF goto E +** if R==undefined goto E ** if skip this row, goto C ** if terminate loop, goto E ** deal with this row @@ -396,28 +391,24 @@ void sqlite3AutoincrementEnd(Parse *pParse){ */ 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 */ + sqlite3VdbeAddOp2(v, OP_Integer, addrTop+1, 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 */ + sqlite3VdbeAddOp1(v, OP_Undef, pDest->iSdst); /* Signal EOF */ + 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: */ @@ -488,7 +479,6 @@ static int xferOptimization( ** and the SELECT clause does not read from at any time. ** The generated code follows this template: ** -** EOF <- 0 ** X <- A ** goto B ** A: setup for the SELECT @@ -497,12 +487,12 @@ static int xferOptimization( ** yield X ** end loop ** cleanup after the SELECT -** EOF <- 1 +** R <- undefined (signals EOF) ** yield X ** goto A ** B: open write cursor to
and its indices ** C: yield X -** if EOF goto D +** if R=undefined goto D ** insert the select result into
from R..R+n ** goto C ** D: cleanup @@ -513,7 +503,6 @@ static int xferOptimization( ** 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 @@ -522,12 +511,12 @@ static int xferOptimization( ** yield X ** end loop ** cleanup after the SELECT -** EOF <- 1 +** R <- undefined (signals EOF) ** yield X ** halt-error ** B: open temp table ** L: yield X -** if EOF goto M +** if R=undefined goto M ** insert row from R..R+n into temp table ** goto L ** M: open write cursor to
and its indices @@ -576,7 +565,6 @@ void sqlite3Insert( int regIns; /* Block of regs holding rowid+data being inserted */ int regRowid; /* registers holding insert rowid */ int regData; /* register holding first column to insert */ - int regEof = 0; /* Register recording end of SELECT data */ int *aRegIdx = 0; /* One register allocated to each index */ #ifndef SQLITE_OMIT_TRIGGER @@ -689,7 +677,6 @@ void sqlite3Insert( 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; @@ -715,7 +702,7 @@ void sqlite3Insert( ** ** B: open temp table ** L: yield X - ** if EOF goto M + ** if R=undefined goto M ** insert row from R..R+n into temp table ** goto L ** M: ... @@ -730,7 +717,7 @@ void sqlite3Insert( regTempRowid = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); - addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof); + addrIf = sqlite3VdbeAddOp1(v, OP_IsUndef, regFromSelect); sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec); sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid); sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid); @@ -860,13 +847,13 @@ void sqlite3Insert( ** following pseudocode (template 3): ** ** C: yield X - ** if EOF goto D + ** if R=undefined goto D ** insert the select result into
from R..R+n ** goto C ** D: ... */ addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); - addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof); + addrInsTop = sqlite3VdbeAddOp1(v, OP_IsUndef, dest.iSdst); } /* Allocate registers for holding the rowid of the new row, diff --git a/src/vdbe.c b/src/vdbe.c index 5816c4a797..ab025ac48d 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -393,7 +393,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ ** Print the value of a register for tracing purposes: */ static void memTracePrint(Mem *p){ - if( p->flags & MEM_Invalid ){ + if( p->flags & MEM_Undefined ){ printf(" undefined"); }else if( p->flags & MEM_Null ){ printf(" NULL"); @@ -702,7 +702,6 @@ check_for_interrupt: } /* Opcode: Gosub P1 P2 * * * -** Synopsis: r[P1]=pc; pc=P2 ** ** Write the current address onto register P1 ** and then jump to address P2. @@ -720,7 +719,6 @@ case OP_Gosub: { /* jump */ } /* Opcode: Return P1 * * * * -** Synopsis: pc=r[P1]+1 ** ** Jump to the next instruction after the address in register P1. */ @@ -732,7 +730,6 @@ case OP_Return: { /* in1 */ } /* Opcode: Yield P1 * * * * -** Synopsis: swap(pc,r[P1]) ** ** Swap the program counter with the value in register P1. */ @@ -974,7 +971,7 @@ case OP_Null: { /* out2-prerelease */ } -/* Opcode: Blob P1 P2 * P4 +/* Opcode: Blob P1 P2 * P4 * ** Synopsis: r[P2]=P4 (len=P1) ** ** P4 points to a blob of data P1 bytes long. Store this @@ -988,6 +985,21 @@ case OP_Blob: { /* out2-prerelease */ break; } +/* Opcode: Undef P1 * * * * +** Synopsis: r[P1]=undef +** +** Mark register P1 as undefined. +*/ +case OP_Undef: { + assert( pOp->p1>0 ); + assert( pOp->p1<=(p->nMem-p->nCursor) ); + pOut = &aMem[pOp->p1]; + memAboutToChange(p, pOut); + VdbeMemRelease(pOut); + pOut->flags = MEM_Undefined; + break; +} + /* Opcode: Variable P1 P2 * P4 * ** Synopsis: r[P2]=parameter(P1,P4) ** @@ -2142,6 +2154,19 @@ case OP_IfNot: { /* jump, in1 */ break; } +/* Opcode: IsUndef P1 P2 * * * +** Synopsis: if r[P1]==undefined goto P2 +** +** Jump to P2 if the value in register P1 is undefined +*/ +case OP_IsUndef: { /* jump */ + pIn1 = &aMem[pOp->p1]; + if( (pIn1->flags & MEM_Undefined)!=0 ){ + pc = pOp->p2 - 1; + } + break; +} + /* Opcode: IsNull P1 P2 * * * ** Synopsis: if r[P1]==NULL goto P2 ** @@ -5191,7 +5216,7 @@ case OP_Program: { /* jump */ pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ - pMem->flags = MEM_Invalid; + pMem->flags = MEM_Undefined; pMem->db = db; } }else{ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index c4fa26cc05..4da24b2374 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -198,7 +198,7 @@ struct Mem { #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_RowSet 0x0020 /* Value is a RowSet object */ #define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ -#define MEM_Invalid 0x0080 /* Value is undefined */ +#define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_TypeMask 0x01ff /* Mask of type bits */ @@ -230,7 +230,7 @@ struct Mem { ** is for use inside assert() statements only. */ #ifdef SQLITE_DEBUG -#define memIsValid(M) ((M)->flags & MEM_Invalid)==0 +#define memIsValid(M) ((M)->flags & MEM_Undefined)==0 #endif /* diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 69611622af..59b766a79c 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1234,7 +1234,7 @@ static void releaseMemArray(Mem *p, int N){ p->zMalloc = 0; } - p->flags = MEM_Invalid; + p->flags = MEM_Undefined; } db->mallocFailed = malloc_failed; } @@ -1702,7 +1702,7 @@ void sqlite3VdbeMakeReady( p->aMem--; /* aMem[] goes from 1..nMem */ p->nMem = nMem; /* not from 0..nMem-1 */ for(n=1; n<=nMem; n++){ - p->aMem[n].flags = MEM_Invalid; + p->aMem[n].flags = MEM_Undefined; p->aMem[n].db = db; } } @@ -1814,7 +1814,7 @@ static void Cleanup(Vdbe *p){ int i; if( p->apCsr ) for(i=0; inCursor; i++) assert( p->apCsr[i]==0 ); if( p->aMem ){ - for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid ); + for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); } #endif diff --git a/src/vdbemem.c b/src/vdbemem.c index 9a621d1f73..982a44537d 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -587,7 +587,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ Mem *pX; for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){ if( pX->pScopyFrom==pMem ){ - pX->flags |= MEM_Invalid; + pX->flags |= MEM_Undefined; pX->pScopyFrom = 0; } }