mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Merge all recent enhancements from trunk.
FossilOrigin-Name: f3f9200115caf4b356f90ec97c351d1afbcb9bf6
This commit is contained in:
230
src/vdbe.c
230
src/vdbe.c
@@ -481,6 +481,7 @@ static void memTracePrint(Mem *p){
|
||||
sqlite3VdbeMemPrettyPrint(p, zBuf);
|
||||
printf(" %s", zBuf);
|
||||
}
|
||||
if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
|
||||
}
|
||||
static void registerTrace(int iReg, Mem *p){
|
||||
printf("REG[%d] = ", iReg);
|
||||
@@ -561,6 +562,9 @@ int sqlite3VdbeExec(
|
||||
Op *pOp = aOp; /* Current operation */
|
||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
Op *pOrigOp; /* Value of pOp at the top of the loop */
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */
|
||||
#endif
|
||||
int rc = SQLITE_OK; /* Value to return */
|
||||
sqlite3 *db = p->db; /* The database */
|
||||
@@ -2077,11 +2081,14 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
** The permutation is only valid until the next OP_Compare that has
|
||||
** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
|
||||
** occur immediately prior to the OP_Compare.
|
||||
**
|
||||
** The first integer in the P4 integer array is the length of the array
|
||||
** and does not become part of the permutation.
|
||||
*/
|
||||
case OP_Permutation: {
|
||||
assert( pOp->p4type==P4_INTARRAY );
|
||||
assert( pOp->p4.ai );
|
||||
aPermute = pOp->p4.ai;
|
||||
aPermute = pOp->p4.ai + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2386,12 +2393,16 @@ case OP_Column: {
|
||||
u32 t; /* A type code from the record header */
|
||||
Mem *pReg; /* PseudoTable input register */
|
||||
|
||||
pC = p->apCsr[pOp->p1];
|
||||
p2 = pOp->p2;
|
||||
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
|
||||
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( p2<pC->nField );
|
||||
aOffset = pC->aOffset;
|
||||
@@ -2400,8 +2411,6 @@ case OP_Column: {
|
||||
assert( pC->eCurType!=CURTYPE_SORTER );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pC->cacheStatus!=p->cacheCtr ){
|
||||
if( pC->nullRow ){
|
||||
@@ -3009,28 +3018,27 @@ case OP_Savepoint: {
|
||||
case OP_AutoCommit: {
|
||||
int desiredAutoCommit;
|
||||
int iRollback;
|
||||
int turnOnAC;
|
||||
|
||||
desiredAutoCommit = pOp->p1;
|
||||
iRollback = pOp->p2;
|
||||
turnOnAC = desiredAutoCommit && !db->autoCommit;
|
||||
assert( desiredAutoCommit==1 || desiredAutoCommit==0 );
|
||||
assert( desiredAutoCommit==1 || iRollback==0 );
|
||||
assert( db->nVdbeActive>0 ); /* At least this one VM is active */
|
||||
assert( p->bIsReader );
|
||||
|
||||
if( turnOnAC && !iRollback && db->nVdbeWrite>0 ){
|
||||
/* If this instruction implements a COMMIT and other VMs are writing
|
||||
** return an error indicating that the other VMs must complete first.
|
||||
*/
|
||||
sqlite3VdbeError(p, "cannot commit transaction - "
|
||||
"SQL statements in progress");
|
||||
rc = SQLITE_BUSY;
|
||||
}else if( desiredAutoCommit!=db->autoCommit ){
|
||||
if( desiredAutoCommit!=db->autoCommit ){
|
||||
if( iRollback ){
|
||||
assert( desiredAutoCommit==1 );
|
||||
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
|
||||
db->autoCommit = 1;
|
||||
}else if( desiredAutoCommit && db->nVdbeWrite>0 ){
|
||||
/* If this instruction implements a COMMIT and other VMs are writing
|
||||
** return an error indicating that the other VMs must complete first.
|
||||
*/
|
||||
sqlite3VdbeError(p, "cannot commit transaction - "
|
||||
"SQL statements in progress");
|
||||
rc = SQLITE_BUSY;
|
||||
break;
|
||||
}else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
|
||||
goto vdbe_return;
|
||||
}else{
|
||||
@@ -3215,15 +3223,15 @@ case OP_ReadCookie: { /* out2 */
|
||||
|
||||
/* Opcode: SetCookie P1 P2 P3 * *
|
||||
**
|
||||
** Write the content of register P3 (interpreted as an integer)
|
||||
** into cookie number P2 of database P1. P2==1 is the schema version.
|
||||
** P2==2 is the database format. P2==3 is the recommended pager cache
|
||||
** Write the integer value P3 into cookie number P2 of database P1.
|
||||
** P2==1 is the schema version. P2==2 is the database format.
|
||||
** P2==3 is the recommended pager cache
|
||||
** size, and so forth. P1==0 is the main database file and P1==1 is the
|
||||
** database file used to store temporary tables.
|
||||
**
|
||||
** A transaction must be started before executing this opcode.
|
||||
*/
|
||||
case OP_SetCookie: { /* in3 */
|
||||
case OP_SetCookie: {
|
||||
Db *pDb;
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
@@ -3232,17 +3240,15 @@ case OP_SetCookie: { /* in3 */
|
||||
pDb = &db->aDb[pOp->p1];
|
||||
assert( pDb->pBt!=0 );
|
||||
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
sqlite3VdbeMemIntegerify(pIn3);
|
||||
/* See note about index shifting on OP_ReadCookie */
|
||||
rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, (int)pIn3->u.i);
|
||||
rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
|
||||
if( pOp->p2==BTREE_SCHEMA_VERSION ){
|
||||
/* When the schema cookie changes, record the new cookie internally */
|
||||
pDb->pSchema->schema_cookie = (int)pIn3->u.i;
|
||||
pDb->pSchema->schema_cookie = pOp->p3;
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}else if( pOp->p2==BTREE_FILE_FORMAT ){
|
||||
/* Record changes in the file format */
|
||||
pDb->pSchema->file_format = (u8)pIn3->u.i;
|
||||
pDb->pSchema->file_format = pOp->p3;
|
||||
}
|
||||
if( pOp->p1==1 ){
|
||||
/* Invalidate all prepared statements whenever the TEMP database
|
||||
@@ -3402,6 +3408,9 @@ case OP_OpenWrite:
|
||||
pCur->nullRow = 1;
|
||||
pCur->isOrdered = 1;
|
||||
pCur->pgnoRoot = p2;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pCur->wrFlag = wrFlag;
|
||||
#endif
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor);
|
||||
pCur->pKeyInfo = pKeyInfo;
|
||||
/* Set the VdbeCursor.isTable variable. Previous versions of
|
||||
@@ -3855,32 +3864,6 @@ seek_not_found:
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Seek P1 P2 * * *
|
||||
** Synopsis: intkey=r[P2]
|
||||
**
|
||||
** P1 is an open table cursor and P2 is a rowid integer. Arrange
|
||||
** for P1 to move so that it points to the rowid given by P2.
|
||||
**
|
||||
** This is actually a deferred seek. Nothing actually happens until
|
||||
** the cursor is used to read a record. That way, if no reads
|
||||
** occur, no unnecessary I/O happens.
|
||||
*/
|
||||
case OP_Seek: { /* in2 */
|
||||
VdbeCursor *pC;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable );
|
||||
pC->nullRow = 0;
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
|
||||
pC->deferredMoveto = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: Found P1 P2 P3 P4 *
|
||||
@@ -4366,14 +4349,22 @@ case OP_InsertInt: {
|
||||
**
|
||||
** Delete the record at which the P1 cursor is currently pointing.
|
||||
**
|
||||
** If the P5 parameter is non-zero, the cursor will be left pointing at
|
||||
** either the next or the previous record in the table. If it is left
|
||||
** pointing at the next record, then the next Next instruction will be a
|
||||
** no-op. As a result, in this case it is OK to delete a record from within a
|
||||
** Next loop. If P5 is zero, then the cursor is left in an undefined state.
|
||||
** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then
|
||||
** the cursor will be left pointing at either the next or the previous
|
||||
** record in the table. If it is left pointing at the next record, then
|
||||
** the next Next instruction will be a no-op. As a result, in this case
|
||||
** it is ok to delete a record from within a Next loop. If
|
||||
** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be
|
||||
** left in an undefined state.
|
||||
**
|
||||
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
|
||||
** incremented (otherwise not).
|
||||
** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this
|
||||
** delete one of several associated with deleting a table row and all its
|
||||
** associated index entries. Exactly one of those deletes is the "primary"
|
||||
** delete. The others are all on OPFLAG_FORDELETE cursors or else are
|
||||
** marked with the AUXDELETE flag.
|
||||
**
|
||||
** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
|
||||
** change count is incremented (otherwise not).
|
||||
**
|
||||
** P1 must not be pseudo-table. It has to be a real table with
|
||||
** multiple rows.
|
||||
@@ -4442,6 +4433,25 @@ case OP_Delete: {
|
||||
|
||||
if( opflags & OPFLAG_ISNOOP ) break;
|
||||
|
||||
/* Only flags that can be set are SAVEPOISTION and AUXDELETE */
|
||||
assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 );
|
||||
assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
|
||||
assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE );
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->pFrame==0 ){
|
||||
if( pC->isEphemeral==0
|
||||
&& (pOp->p5 & OPFLAG_AUXDELETE)==0
|
||||
&& (pC->wrFlag & OPFLAG_FORDELETE)==0
|
||||
){
|
||||
nExtraDelete++;
|
||||
}
|
||||
if( pOp->p2 & OPFLAG_NCHANGE ){
|
||||
nExtraDelete--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
|
||||
@@ -4989,18 +4999,34 @@ case OP_IdxDelete: {
|
||||
r.nField = (u16)pOp->p3;
|
||||
r.default_rc = 0;
|
||||
r.aMem = &aMem[pOp->p2];
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
||||
#endif
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
|
||||
if( rc==SQLITE_OK && res==0 ){
|
||||
rc = sqlite3BtreeDelete(pCrsr, 0);
|
||||
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
|
||||
}
|
||||
assert( pC->deferredMoveto==0 );
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Seek P1 * P3 P4 *
|
||||
** Synopsis: Move P3 to P1.rowid
|
||||
**
|
||||
** P1 is an open index cursor and P3 is a cursor on the corresponding
|
||||
** table. This opcode does a deferred seek of the P3 table cursor
|
||||
** to the row that corresponds to the current row of P1.
|
||||
**
|
||||
** This is a deferred seek. Nothing actually happens until
|
||||
** the cursor is used to read a record. That way, if no reads
|
||||
** occur, no unnecessary I/O happens.
|
||||
**
|
||||
** P4 may be an array of integers (type P4_INTARRAY) containing
|
||||
** one entry for each column in the P3 table. If array entry a[i]
|
||||
** is non-zero, then reading column (a[i]-1) from cursor P3 is
|
||||
** equivalent to performing the deferred seek and then reading column i
|
||||
** from P1. This information is stored in P3 and used to redirect
|
||||
** reads against P3 over to P1, thus possibly avoiding the need to
|
||||
** seek and read cursor P3.
|
||||
*/
|
||||
/* Opcode: IdxRowid P1 P2 * * *
|
||||
** Synopsis: r[P2]=rowid
|
||||
**
|
||||
@@ -5010,37 +5036,57 @@ case OP_IdxDelete: {
|
||||
**
|
||||
** See also: Rowid, MakeRecord.
|
||||
*/
|
||||
case OP_Seek:
|
||||
case OP_IdxRowid: { /* out2 */
|
||||
BtCursor *pCrsr;
|
||||
VdbeCursor *pC;
|
||||
i64 rowid;
|
||||
VdbeCursor *pC; /* The P1 index cursor */
|
||||
VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */
|
||||
i64 rowid; /* Rowid that P1 current points to */
|
||||
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr!=0 );
|
||||
pOut->flags = MEM_Null;
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable==0 );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
|
||||
|
||||
/* The IdxRowid and Seek opcodes are combined because of the commonality
|
||||
** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
|
||||
rc = sqlite3VdbeCursorRestore(pC);
|
||||
|
||||
/* sqlite3VbeCursorRestore() can only fail if the record has been deleted
|
||||
** out from under the cursor. That will never happend for an IdxRowid
|
||||
** opcode, hence the NEVER() arround the check of the return value.
|
||||
*/
|
||||
rc = sqlite3VdbeCursorRestore(pC);
|
||||
** out from under the cursor. That will never happens for an IdxRowid
|
||||
** or Seek opcode */
|
||||
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
|
||||
|
||||
if( !pC->nullRow ){
|
||||
rowid = 0; /* Not needed. Only used to silence a warning. */
|
||||
rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
|
||||
rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
pOut->u.i = rowid;
|
||||
pOut->flags = MEM_Int;
|
||||
if( pOp->opcode==OP_Seek ){
|
||||
assert( pOp->p3>=0 && pOp->p3<p->nCursor );
|
||||
pTabCur = p->apCsr[pOp->p3];
|
||||
assert( pTabCur!=0 );
|
||||
assert( pTabCur->eCurType==CURTYPE_BTREE );
|
||||
assert( pTabCur->uc.pCursor!=0 );
|
||||
assert( pTabCur->isTable );
|
||||
pTabCur->nullRow = 0;
|
||||
pTabCur->movetoTarget = rowid;
|
||||
pTabCur->deferredMoveto = 1;
|
||||
assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
|
||||
pTabCur->aAltMap = pOp->p4.ai;
|
||||
pTabCur->pAltCursor = pC;
|
||||
}else{
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = rowid;
|
||||
pOut->flags = MEM_Int;
|
||||
}
|
||||
}else{
|
||||
assert( pOp->opcode==OP_IdxRowid );
|
||||
sqlite3VdbeMemSetNull(&aMem[pOp->p2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5817,20 +5863,31 @@ case OP_IfPos: { /* jump, in1 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SetIfNotPos P1 P2 P3 * *
|
||||
** Synopsis: if r[P1]<=0 then r[P2]=P3
|
||||
/* Opcode: OffsetLimit P1 P2 P3 * *
|
||||
** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)
|
||||
**
|
||||
** Register P1 must contain an integer.
|
||||
** If the value of register P1 is not positive (if it is less than 1) then
|
||||
** set the value of register P2 to be the integer P3.
|
||||
** This opcode performs a commonly used computation associated with
|
||||
** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3]
|
||||
** holds the offset counter. The opcode computes the combined value
|
||||
** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2]
|
||||
** value computed is the total number of rows that will need to be
|
||||
** visited in order to complete the query.
|
||||
**
|
||||
** If r[P3] is zero or negative, that means there is no OFFSET
|
||||
** and r[P2] is set to be the value of the LIMIT, r[P1].
|
||||
**
|
||||
** if r[P1] is zero or negative, that means there is no LIMIT
|
||||
** and r[P2] is set to -1.
|
||||
**
|
||||
** Otherwise, r[P2] is set to the sum of r[P1] and r[P3].
|
||||
*/
|
||||
case OP_SetIfNotPos: { /* in1, in2 */
|
||||
case OP_OffsetLimit: { /* in1, out2, in3 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags&MEM_Int );
|
||||
if( pIn1->u.i<=0 ){
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = pOp->p3;
|
||||
}
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
assert( pIn1->flags & MEM_Int );
|
||||
assert( pIn3->flags & MEM_Int );
|
||||
pOut->u.i = pIn1->u.i<=0 ? -1 : pIn1->u.i+(pIn3->u.i>0?pIn3->u.i:0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6802,6 +6859,9 @@ vdbe_return:
|
||||
testcase( nVmStep>0 );
|
||||
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
|
||||
sqlite3VdbeLeave(p);
|
||||
assert( rc!=SQLITE_OK || nExtraDelete==0
|
||||
|| sqlite3_strlike("DELETE%",p->zSql,0)!=0
|
||||
);
|
||||
return rc;
|
||||
|
||||
/* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH
|
||||
|
Reference in New Issue
Block a user