diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/auth.c | 2 | ||||
-rw-r--r-- | src/btree.c | 8 | ||||
-rw-r--r-- | src/select.c | 13 | ||||
-rw-r--r-- | src/sqliteInt.h | 11 | ||||
-rw-r--r-- | src/vdbe.c | 156 | ||||
-rw-r--r-- | src/vdbeInt.h | 16 | ||||
-rw-r--r-- | src/vdbeaux.c | 3 |
7 files changed, 88 insertions, 121 deletions
diff --git a/src/auth.c b/src/auth.c index 4e5bd164f..ec3514257 100644 --- a/src/auth.c +++ b/src/auth.c @@ -128,7 +128,7 @@ void sqlite3AuthRead( pTab = pParse->pTriggerTab; }else{ assert( pTabList ); - for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){ + for(iSrc=0; ALWAYS(iSrc<pTabList->nSrc); iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ pTab = pTabList->a[iSrc].pTab; break; diff --git a/src/btree.c b/src/btree.c index 903b782bc..dde289752 100644 --- a/src/btree.c +++ b/src/btree.c @@ -6420,8 +6420,10 @@ static int balance(BtCursor *pCur){ ** a positive value if pCur points at an etry that is larger than ** (pKey, nKey)). ** -** If the seekResult parameter is 0, then cursor pCur may point to any -** entry or to no entry at all. In this case this function has to seek +** If the seekResult parameter is non-zero, then the caller guarantees that +** cursor pCur is pointing at the existing copy of a row that is to be +** overwritten. If the seekResult parameter is 0, then cursor pCur may +** point to any entry or to no entry at all and so this function has to seek ** the cursor before the new key can be inserted. */ int sqlite3BtreeInsert( @@ -6433,7 +6435,7 @@ int sqlite3BtreeInsert( int seekResult /* Result of prior MovetoUnpacked() call */ ){ int rc; - int loc = seekResult; + int loc = seekResult; /* -1: before desired location +1: after */ int szNew; int idx; MemPage *pPage; diff --git a/src/select.c b/src/select.c index ecdc63187..21bc2be23 100644 --- a/src/select.c +++ b/src/select.c @@ -766,14 +766,16 @@ static void generateSortTail( int regRowid; iTab = pOrderBy->iECursor; + regRow = sqlite3GetTempReg(pParse); if( eDest==SRT_Output || eDest==SRT_Coroutine ){ pseudoTab = pParse->nTab++; - sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, eDest==SRT_Output, nColumn); + sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn); + regRowid = 0; + }else{ + regRowid = sqlite3GetTempReg(pParse); } addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); codeOffset(v, p, addrContinue); - regRow = sqlite3GetTempReg(pParse); - regRowid = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow); switch( eDest ){ case SRT_Table: @@ -805,11 +807,12 @@ static void generateSortTail( assert( eDest==SRT_Output || eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); testcase( eDest==SRT_Coroutine ); - sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, pseudoTab, regRow, regRowid); for(i=0; i<nColumn; i++){ assert( regRow!=pDest->iMem+i ); sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iMem+i); + if( i==0 ){ + sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); + } } if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7c610060b..6cfe702e3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2161,11 +2161,12 @@ struct AuthContext { /* ** Bitfield flags for P5 value in OP_Insert and OP_Delete */ -#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */ -#define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */ -#define OPFLAG_ISUPDATE 4 /* This OP_Insert is an sql UPDATE */ -#define OPFLAG_APPEND 8 /* This is likely to be an append */ -#define OPFLAG_USESEEKRESULT 16 /* Try to avoid a seek in BtreeInsert() */ +#define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */ +#define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */ +#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ +#define OPFLAG_APPEND 0x08 /* This is likely to be an append */ +#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ +#define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */ /* * Each trigger present in the database schema is stored as an instance of diff --git a/src/vdbe.c b/src/vdbe.c index d3fd3050e..b16880270 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -189,7 +189,7 @@ static VdbeCursor *allocateCursor( int iCur, /* Index of the new VdbeCursor */ int nField, /* Number of fields in the table or index */ int iDb, /* When database the cursor belongs to, or -1 */ - int isBtreeCursor /* True for B-Tree vs. pseudo-table or vtab */ + int isBtreeCursor /* True for B-Tree. False for pseudo-table or vtab */ ){ /* Find the memory cell that will be used to store the blob of memory ** required for this VdbeCursor structure. It is convenient to use a @@ -1975,29 +1975,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ break; } -/* Opcode: SetNumColumns * P2 * * * -** -** This opcode sets the number of columns for the cursor opened by the -** following instruction to P2. -** -** An OP_SetNumColumns is only useful if it occurs immediately before -** one of the following opcodes: -** -** OpenRead -** OpenWrite -** OpenPseudo -** -** If the OP_Column opcode is to be executed on a cursor, then -** this opcode must be present immediately before the opcode that -** opens the cursor. -*/ -#if 0 -case OP_SetNumColumns: { - break; -} -#endif - -/* Opcode: Column P1 P2 P3 P4 * +/* Opcode: Column P1 P2 P3 P4 P5 ** ** Interpret the data that cursor P1 points to as a structure built using ** the MakeRecord instruction. (See the MakeRecord opcode for additional @@ -2010,6 +1988,11 @@ case OP_SetNumColumns: { ** If the column contains fewer than P2 fields, then extract a NULL. Or, ** if the P4 argument is a P4_MEM use the value of the P4 argument as ** the result. +** +** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor, +** then the cache of the cursor is reset prior to extracting the column. +** The first OP_Column against a pseudo-table after the value of the content +** register has changed should have this bit set. */ case OP_Column: { u32 payloadSize; /* Number of bytes in the record */ @@ -2033,6 +2016,7 @@ case OP_Column: { u64 offset64; /* 64-bit offset. 64 bits needed to catch overflow */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ + Mem *pReg; /* PseudoTable input register */ p1 = pOp->p1; @@ -2086,11 +2070,12 @@ case OP_Column: { rc = sqlite3BtreeDataSize(pCrsr, &payloadSize); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ } - }else if( pC->pseudoTable ){ - /* The record is the sole entry of a pseudo-table */ - payloadSize = pC->nData; - zRec = pC->pData; - pC->cacheStatus = CACHE_STALE; + }else if( pC->pseudoTableReg>0 ){ + pReg = &p->aMem[pC->pseudoTableReg]; + assert( pReg->flags & MEM_Blob ); + payloadSize = pReg->n; + zRec = pReg->z; + pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr; assert( payloadSize==0 || zRec!=0 ); }else{ /* Consider the row to be NULL */ @@ -3067,22 +3052,14 @@ case OP_OpenEphemeral: { /* Opcode: OpenPseudo P1 P2 P3 * * ** ** Open a new cursor that points to a fake table that contains a single -** row of data. Any attempt to write a second row of data causes the -** first row to be deleted. All data is deleted when the cursor is -** closed. +** row of data. The content of that one row in the content of memory +** register P2. In other words, cursor P1 becomes an alias for the +** MEM_Blob content contained in register P2. ** -** A pseudo-table created by this opcode is useful for holding the -** NEW or OLD tables in a trigger. Also used to hold the a single +** A pseudo-table created by this opcode is used to hold the a single ** row output from the sorter so that the row can be decomposed into -** individual columns using the OP_Column opcode. -** -** When OP_Insert is executed to insert a row in to the pseudo table, -** the pseudo-table cursor may or may not make it's own copy of the -** original row data. If P2 is 0, then the pseudo-table will copy the -** original row data. Otherwise, a pointer to the original memory cell -** is stored. In this case, the vdbe program must ensure that the -** memory cell containing the row data is not overwritten until the -** pseudo table is closed (or a new row is inserted into it). +** individual columns using the OP_Column opcode. The OP_Column opcode +** is the only cursor opcode that works with a pseudo-table. ** ** P3 is the number of fields in the records that will be stored by ** the pseudo-table. @@ -3094,8 +3071,7 @@ case OP_OpenPseudo: { pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; - pCx->pseudoTable = 1; - pCx->ephemPseudoTable = (u8)pOp->p2; + pCx->pseudoTableReg = pOp->p2; pCx->isTable = 1; pCx->isIndex = 0; break; @@ -3180,6 +3156,7 @@ case OP_SeekGt: { /* jump, in3 */ assert( pOp->p2!=0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); + assert( pC->pseudoTableReg==0 ); if( pC->pCursor!=0 ){ oc = pOp->opcode; pC->nullRow = 0; @@ -3293,7 +3270,6 @@ case OP_SeekGt: { /* jump, in3 */ ** for read access returns SQLITE_EMPTY. In this case always ** take the jump (since there are no records in the table). */ - assert( pC->pseudoTable==0 ); pc = pOp->p2 - 1; } break; @@ -3504,6 +3480,7 @@ case OP_NotExists: { /* jump, in3 */ pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->isTable ); + assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; if( pCrsr!=0 ){ res = 0; @@ -3523,8 +3500,6 @@ case OP_NotExists: { /* jump, in3 */ /* This happens when an attempt to open a read cursor on the ** sqlite_master table returns SQLITE_EMPTY. */ - assert( !pC->pseudoTable ); - assert( pC->isTable ); pc = pOp->p2 - 1; assert( pC->rowidIsValid==0 ); pC->seekResult = 0; @@ -3685,15 +3660,28 @@ case OP_NewRowid: { /* out2-prerelease */ ** ** Write an entry into the table of cursor P1. A new entry is ** created if it doesn't already exist or the data for an existing -** entry is overwritten. The data is the value stored register +** entry is overwritten. The data is the value MEM_Blob stored in register ** number P2. The key is stored in register P3. The key must -** be an integer. +** be a MEM_Int. ** ** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** +** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of +** the last seek operation (OP_NotExists) was a success, then this +** operation will not attempt to find the appropriate row before doing +** the insert but will instead overwrite the row that the cursor is +** currently pointing to. Presumably, the prior OP_NotExists opcode +** has already positioned the cursor correctly. This is an optimization +** that boosts performance by avoiding redundant seeks. +** +** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an +** UPDATE operation. Otherwise (if the flag is clear) then this opcode +** is part of an INSERT operation. The difference is only important to +** the update hook. +** ** Parameter P4 may point to a string containing the table-name, or ** may be NULL. If it is not NULL, then the update-hook ** (sqlite3.xUpdateCallback) is invoked following a successful insert. @@ -3708,22 +3696,23 @@ case OP_NewRowid: { /* out2-prerelease */ ** for indices is OP_IdxInsert. */ case OP_Insert: { - Mem *pData; - Mem *pKey; - i64 iKey; /* The integer ROWID or key for the record to be inserted */ - VdbeCursor *pC; - int nZero; - int seekResult; - const char *zDb; - const char *zTbl; - int op; + Mem *pData; /* MEM cell holding data for the record to be inserted */ + Mem *pKey; /* MEM cell holding key for the record */ + i64 iKey; /* The integer ROWID or key for the record to be inserted */ + VdbeCursor *pC; /* Cursor to table into which insert is written */ + int nZero; /* Number of zero-bytes to append */ + int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ + const char *zDb; /* database name - used by the update hook */ + const char *zTbl; /* Table name - used by the opdate hook */ + int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ pData = &p->aMem[pOp->p2]; pKey = &p->aMem[pOp->p3]; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); - assert( pC->pCursor!=0 || pC->pseudoTable ); + assert( pC->pCursor!=0 ); + assert( pC->pseudoTableReg==0 ); assert( pKey->flags & MEM_Int ); assert( pC->isTable ); REGISTER_TRACE(pOp->p2, pData); @@ -3738,41 +3727,17 @@ case OP_Insert: { }else{ assert( pData->flags & (MEM_Blob|MEM_Str) ); } - if( pC->pseudoTable ){ - if( !pC->ephemPseudoTable ){ - sqlite3DbFree(db, pC->pData); - } - pC->iKey = iKey; - pC->nData = pData->n; - if( pC->ephemPseudoTable || pData->z==pData->zMalloc ){ - pC->pData = pData->z; - if( !pC->ephemPseudoTable ){ - pData->flags &= ~MEM_Dyn; - pData->flags |= MEM_Ephem; - pData->zMalloc = 0; - } - }else{ - pC->pData = sqlite3Malloc( pC->nData+2 ); - if( !pC->pData ) goto no_mem; - memcpy(pC->pData, pData->z, pC->nData); - pC->pData[pC->nData] = 0; - pC->pData[pC->nData+1] = 0; - } - pC->nullRow = 0; + seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); + if( pData->flags & MEM_Zero ){ + nZero = pData->u.nZero; }else{ - seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); - if( pData->flags & MEM_Zero ){ - nZero = pData->u.nZero; - }else{ - nZero = 0; - } - sqlite3BtreeSetCachedRowid(pC->pCursor, 0); - rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, - pData->z, pData->n, nZero, - pOp->p5 & OPFLAG_APPEND, seekResult - ); + nZero = 0; } - + sqlite3BtreeSetCachedRowid(pC->pCursor, 0); + rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, + pData->z, pData->n, nZero, + pOp->p5 & OPFLAG_APPEND, seekResult + ); pC->rowidIsValid = 0; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; @@ -3905,7 +3870,7 @@ case OP_RowData: { assert( pC->isIndex || pOp->opcode==OP_RowData ); assert( pC!=0 ); assert( pC->nullRow==0 ); - assert( pC->pseudoTable==0 ); + assert( pC->pseudoTableReg==0 ); assert( pC->pCursor!=0 ); pCrsr = pC->pCursor; assert( sqlite3BtreeCursorIsValid(pCrsr) ); @@ -3967,13 +3932,12 @@ case OP_Rowid: { /* out2-prerelease */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); + assert( pC->pseudoTableReg==0 ); if( pC->nullRow ){ /* Do nothing so that reg[P2] remains NULL */ break; }else if( pC->deferredMoveto ){ v = pC->movetoTarget; - }else if( pC->pseudoTable ){ - v = pC->iKey; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( pC->pVtabCursor ){ pVtab = pC->pVtabCursor->pVtab; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 40aab1a39..ecf8dcd54 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -56,16 +56,12 @@ struct VdbeCursor { Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ - Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */ - Bool ephemPseudoTable; Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isTable; /* True if a table requiring integer keys */ Bool isIndex; /* True if an index containing keys only - no data */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ Btree *pBt; /* Separate file holding temporary table */ - int nData; /* Number of bytes in pData */ - char *pData; /* Data for a NEW or OLD pseudo-table */ - i64 iKey; /* Key for the NEW or OLD pseudo-table row */ + int pseudoTableReg; /* Register holding pseudotable content. */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ int nField; /* Number of fields in the header */ i64 seqCount; /* Sequence counter */ @@ -77,11 +73,15 @@ struct VdbeCursor { int seekResult; /* Cached information about the header for the data record that the - ** cursor is currently pointing to. Only valid if cacheValid is true. + ** cursor is currently pointing to. Only valid if cacheStatus matches + ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of + ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that + ** the cache is out of date. + ** ** aRow might point to (ephemeral) data for the current row, or it might ** be NULL. */ - int cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ + u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ int payloadSize; /* Total number of bytes in the record */ u32 *aType; /* Type values for all entries in the record */ u32 *aOffset; /* Cached offsets to the start of each columns data */ @@ -296,7 +296,7 @@ struct Vdbe { u32 magic; /* Magic number for sanity checking */ int nMem; /* Number of memory locations currently allocated */ Mem *aMem; /* The memory locations */ - int cacheCtr; /* VdbeCursor row cache generation counter */ + u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ char *zErrMsg; /* Error message written here */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index a3975647d..35ae1e355 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1365,9 +1365,6 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ p->inVtabMethod = 0; } #endif - if( !pCx->ephemPseudoTable ){ - sqlite3DbFree(p->db, pCx->pData); - } } /* |