Index: third_party/sqlite/src/src/vdbe.c |
diff --git a/third_party/sqlite/src/src/vdbe.c b/third_party/sqlite/src/src/vdbe.c |
index 5376b08a00ef9d9f2d27e0d54627fcbe64af20ff..366c7a01661b2d48e986d903d412981e69df33f5 100644 |
--- a/third_party/sqlite/src/src/vdbe.c |
+++ b/third_party/sqlite/src/src/vdbe.c |
@@ -9,33 +9,8 @@ |
** May you share freely, never taking more than you give. |
** |
************************************************************************* |
-** The code in this file implements execution method of the |
-** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c") |
-** handles housekeeping details such as creating and deleting |
-** VDBE instances. This file is solely interested in executing |
-** the VDBE program. |
-** |
-** In the external interface, an "sqlite3_stmt*" is an opaque pointer |
-** to a VDBE. |
-** |
-** The SQL parser generates a program which is then executed by |
-** the VDBE to do the work of the SQL statement. VDBE programs are |
-** similar in form to assembly language. The program consists of |
-** a linear sequence of operations. Each operation has an opcode |
-** and 5 operands. Operands P1, P2, and P3 are integers. Operand P4 |
-** is a null-terminated string. Operand P5 is an unsigned character. |
-** Few opcodes use all 5 operands. |
-** |
-** Computation results are stored on a set of registers numbered beginning |
-** with 1 and going up to Vdbe.nMem. Each register can store |
-** either an integer, a null-terminated string, a floating point |
-** number, or the SQL "NULL" value. An implicit conversion from one |
-** type to the other occurs as necessary. |
-** |
-** Most of the code in this file is taken up by the sqlite3VdbeExec() |
-** function which does the work of interpreting a VDBE program. |
-** But other routines are also provided to help in building up |
-** a program instruction by instruction. |
+** The code in this file implements the function that runs the |
+** bytecode of a prepared statement. |
** |
** Various scripts scan this source file in order to generate HTML |
** documentation, headers files, or other derived files. The formatting |
@@ -49,10 +24,14 @@ |
/* |
** Invoke this macro on memory cells just prior to changing the |
** value of the cell. This macro verifies that shallow copies are |
-** not misused. |
+** not misused. A shallow copy of a string or blob just copies a |
+** pointer to the string or blob, not the content. If the original |
+** is changed while the copy is still in use, the string or blob might |
+** be changed out from under the copy. This macro verifies that nothing |
+** like that ever happens. |
*/ |
#ifdef SQLITE_DEBUG |
-# define memAboutToChange(P,M) sqlite3VdbeMemPrepareToChange(P,M) |
+# define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M) |
#else |
# define memAboutToChange(P,M) |
#endif |
@@ -70,8 +49,8 @@ int sqlite3_search_count = 0; |
/* |
** When this global variable is positive, it gets decremented once before |
-** each instruction in the VDBE. When reaches zero, the u1.isInterrupted |
-** field of the sqlite3 structure is set in order to simulate and interrupt. |
+** each instruction in the VDBE. When it reaches zero, the u1.isInterrupted |
+** field of the sqlite3 structure is set in order to simulate an interrupt. |
** |
** This facility is used for testing purposes only. It does not function |
** in an ordinary build. |
@@ -108,7 +87,7 @@ static void updateMaxBlobsize(Mem *p){ |
#endif |
/* |
-** The next global variable is incremented each type the OP_Found opcode |
+** The next global variable is incremented each time the OP_Found opcode |
** is executed. This is used to test whether or not the foreign key |
** operation implemented using OP_FkIsZero is working. This variable |
** has no function other than to help verify the correct operation of the |
@@ -129,11 +108,45 @@ int sqlite3_found_count = 0; |
#endif |
/* |
+** Invoke the VDBE coverage callback, if that callback is defined. This |
+** feature is used for test suite validation only and does not appear an |
+** production builds. |
+** |
+** M is an integer, 2 or 3, that indices how many different ways the |
+** branch can go. It is usually 2. "I" is the direction the branch |
+** goes. 0 means falls through. 1 means branch is taken. 2 means the |
+** second alternative branch is taken. |
+** |
+** iSrcLine is the source code line (from the __LINE__ macro) that |
+** generated the VDBE instruction. This instrumentation assumes that all |
+** source code is in a single file (the amalgamation). Special values 1 |
+** and 2 for the iSrcLine parameter mean that this particular branch is |
+** always taken or never taken, respectively. |
+*/ |
+#if !defined(SQLITE_VDBE_COVERAGE) |
+# define VdbeBranchTaken(I,M) |
+#else |
+# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M) |
+ static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){ |
+ if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){ |
+ M = iSrcLine; |
+ /* Assert the truth of VdbeCoverageAlwaysTaken() and |
+ ** VdbeCoverageNeverTaken() */ |
+ assert( (M & I)==I ); |
+ }else{ |
+ if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ |
+ sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, |
+ iSrcLine,I,M); |
+ } |
+ } |
+#endif |
+ |
+/* |
** Convert the given register into a string if it isn't one |
** already. Return non-zero if a malloc() fails. |
*/ |
#define Stringify(P, enc) \ |
- if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc)) \ |
+ if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \ |
{ goto no_mem; } |
/* |
@@ -145,41 +158,14 @@ int sqlite3_found_count = 0; |
** |
** This routine converts an ephemeral string into a dynamically allocated |
** string that the register itself controls. In other words, it |
-** converts an MEM_Ephem string into an MEM_Dyn string. |
+** converts an MEM_Ephem string into a string with P.z==P.zMalloc. |
*/ |
#define Deephemeralize(P) \ |
if( ((P)->flags&MEM_Ephem)!=0 \ |
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} |
-/* |
-** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) |
-** P if required. |
-*/ |
-#define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) |
- |
-/* |
-** Argument pMem points at a register that will be passed to a |
-** user-defined function or returned to the user as the result of a query. |
-** This routine sets the pMem->type variable used by the sqlite3_value_*() |
-** routines. |
-*/ |
-void sqlite3VdbeMemStoreType(Mem *pMem){ |
- int flags = pMem->flags; |
- if( flags & MEM_Null ){ |
- pMem->type = SQLITE_NULL; |
- } |
- else if( flags & MEM_Int ){ |
- pMem->type = SQLITE_INTEGER; |
- } |
- else if( flags & MEM_Real ){ |
- pMem->type = SQLITE_FLOAT; |
- } |
- else if( flags & MEM_Str ){ |
- pMem->type = SQLITE_TEXT; |
- }else{ |
- pMem->type = SQLITE_BLOB; |
- } |
-} |
+/* Return true if the cursor was opened using the OP_OpenSorter opcode. */ |
+#define isSorter(x) ((x)->pSorter!=0) |
/* |
** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL |
@@ -189,7 +175,7 @@ static VdbeCursor *allocateCursor( |
Vdbe *p, /* The virtual machine */ |
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 iDb, /* Database the cursor belongs to, or -1 */ |
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 |
@@ -215,26 +201,23 @@ static VdbeCursor *allocateCursor( |
int nByte; |
VdbeCursor *pCx = 0; |
nByte = |
- ROUND8(sizeof(VdbeCursor)) + |
- (isBtreeCursor?sqlite3BtreeCursorSize():0) + |
- 2*nField*sizeof(u32); |
+ ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + |
+ (isBtreeCursor?sqlite3BtreeCursorSize():0); |
assert( iCur<p->nCursor ); |
if( p->apCsr[iCur] ){ |
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); |
p->apCsr[iCur] = 0; |
} |
- if( SQLITE_OK==sqlite3VdbeMemGrow(pMem, nByte, 0) ){ |
+ if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ |
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; |
memset(pCx, 0, sizeof(VdbeCursor)); |
pCx->iDb = iDb; |
pCx->nField = nField; |
- if( nField ){ |
- pCx->aType = (u32 *)&pMem->z[ROUND8(sizeof(VdbeCursor))]; |
- } |
+ pCx->aOffset = &pCx->aType[nField]; |
if( isBtreeCursor ){ |
pCx->pCursor = (BtCursor*) |
- &pMem->z[ROUND8(sizeof(VdbeCursor))+2*nField*sizeof(u32)]; |
+ &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; |
sqlite3BtreeCursorZero(pCx->pCursor); |
} |
} |
@@ -246,21 +229,29 @@ static VdbeCursor *allocateCursor( |
** do so without loss of information. In other words, if the string |
** looks like a number, convert it into a number. If it does not |
** look like a number, leave it alone. |
-*/ |
-static void applyNumericAffinity(Mem *pRec){ |
- if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){ |
- double rValue; |
- i64 iValue; |
- u8 enc = pRec->enc; |
- if( (pRec->flags&MEM_Str)==0 ) return; |
- if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; |
- if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ |
- pRec->u.i = iValue; |
- pRec->flags |= MEM_Int; |
- }else{ |
- pRec->r = rValue; |
- pRec->flags |= MEM_Real; |
- } |
+** |
+** If the bTryForInt flag is true, then extra effort is made to give |
+** an integer representation. Strings that look like floating point |
+** values but which have no fractional component (example: '48.00') |
+** will have a MEM_Int representation when bTryForInt is true. |
+** |
+** If bTryForInt is false, then if the input string contains a decimal |
+** point or exponential notation, the result is only MEM_Real, even |
+** if there is an exact integer representation of the quantity. |
+*/ |
+static void applyNumericAffinity(Mem *pRec, int bTryForInt){ |
+ double rValue; |
+ i64 iValue; |
+ u8 enc = pRec->enc; |
+ assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str ); |
+ if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; |
+ if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ |
+ pRec->u.i = iValue; |
+ pRec->flags |= MEM_Int; |
+ }else{ |
+ pRec->u.r = rValue; |
+ pRec->flags |= MEM_Real; |
+ if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); |
} |
} |
@@ -287,21 +278,23 @@ static void applyAffinity( |
char affinity, /* The affinity to be applied */ |
u8 enc /* Use this text encoding */ |
){ |
- if( affinity==SQLITE_AFF_TEXT ){ |
+ if( affinity>=SQLITE_AFF_NUMERIC ){ |
+ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL |
+ || affinity==SQLITE_AFF_NUMERIC ); |
+ if( (pRec->flags & MEM_Int)==0 ){ |
+ if( (pRec->flags & MEM_Real)==0 ){ |
+ if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); |
+ }else{ |
+ sqlite3VdbeIntegerAffinity(pRec); |
+ } |
+ } |
+ }else if( affinity==SQLITE_AFF_TEXT ){ |
/* Only attempt the conversion to TEXT if there is an integer or real |
** representation (blob and NULL do not get converted) but no string |
** representation. |
*/ |
if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){ |
- sqlite3VdbeMemStringify(pRec, enc); |
- } |
- pRec->flags &= ~(MEM_Real|MEM_Int); |
- }else if( affinity!=SQLITE_AFF_NONE ){ |
- assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL |
- || affinity==SQLITE_AFF_NUMERIC ); |
- applyNumericAffinity(pRec); |
- if( pRec->flags & MEM_Real ){ |
- sqlite3VdbeIntegerAffinity(pRec); |
+ sqlite3VdbeMemStringify(pRec, enc, 1); |
} |
} |
} |
@@ -313,12 +306,13 @@ static void applyAffinity( |
** loss of information and return the revised type of the argument. |
*/ |
int sqlite3_value_numeric_type(sqlite3_value *pVal){ |
- Mem *pMem = (Mem*)pVal; |
- if( pMem->type==SQLITE_TEXT ){ |
- applyNumericAffinity(pMem); |
- sqlite3VdbeMemStoreType(pMem); |
+ int eType = sqlite3_value_type(pVal); |
+ if( eType==SQLITE_TEXT ){ |
+ Mem *pMem = (Mem*)pVal; |
+ applyNumericAffinity(pMem, 0); |
+ eType = sqlite3_value_type(pVal); |
} |
- return pMem->type; |
+ return eType; |
} |
/* |
@@ -333,6 +327,41 @@ void sqlite3ValueApplyAffinity( |
applyAffinity((Mem *)pVal, affinity, enc); |
} |
+/* |
+** pMem currently only holds a string type (or maybe a BLOB that we can |
+** interpret as a string if we want to). Compute its corresponding |
+** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields |
+** accordingly. |
+*/ |
+static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ |
+ assert( (pMem->flags & (MEM_Int|MEM_Real))==0 ); |
+ assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); |
+ if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ |
+ return 0; |
+ } |
+ if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ |
+ return MEM_Int; |
+ } |
+ return MEM_Real; |
+} |
+ |
+/* |
+** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or |
+** none. |
+** |
+** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. |
+** But it does set pMem->u.r and pMem->u.i appropriately. |
+*/ |
+static u16 numericType(Mem *pMem){ |
+ if( pMem->flags & (MEM_Int|MEM_Real) ){ |
+ return pMem->flags & (MEM_Int|MEM_Real); |
+ } |
+ if( pMem->flags & (MEM_Str|MEM_Blob) ){ |
+ return computeNumericType(pMem); |
+ } |
+ return 0; |
+} |
+ |
#ifdef SQLITE_DEBUG |
/* |
** Write a nice string representation of the contents of cell pMem |
@@ -420,35 +449,36 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ |
/* |
** Print the value of a register for tracing purposes: |
*/ |
-static void memTracePrint(FILE *out, Mem *p){ |
- if( p->flags & MEM_Null ){ |
- fprintf(out, " NULL"); |
+static void memTracePrint(Mem *p){ |
+ if( p->flags & MEM_Undefined ){ |
+ printf(" undefined"); |
+ }else if( p->flags & MEM_Null ){ |
+ printf(" NULL"); |
}else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ |
- fprintf(out, " si:%lld", p->u.i); |
+ printf(" si:%lld", p->u.i); |
}else if( p->flags & MEM_Int ){ |
- fprintf(out, " i:%lld", p->u.i); |
+ printf(" i:%lld", p->u.i); |
#ifndef SQLITE_OMIT_FLOATING_POINT |
}else if( p->flags & MEM_Real ){ |
- fprintf(out, " r:%g", p->r); |
+ printf(" r:%g", p->u.r); |
#endif |
}else if( p->flags & MEM_RowSet ){ |
- fprintf(out, " (rowset)"); |
+ printf(" (rowset)"); |
}else{ |
char zBuf[200]; |
sqlite3VdbeMemPrettyPrint(p, zBuf); |
- fprintf(out, " "); |
- fprintf(out, "%s", zBuf); |
+ printf(" %s", zBuf); |
} |
} |
-static void registerTrace(FILE *out, int iReg, Mem *p){ |
- fprintf(out, "REG[%d] = ", iReg); |
- memTracePrint(out, p); |
- fprintf(out, "\n"); |
+static void registerTrace(int iReg, Mem *p){ |
+ printf("REG[%d] = ", iReg); |
+ memTracePrint(p); |
+ printf("\n"); |
} |
#endif |
#ifdef SQLITE_DEBUG |
-# define REGISTER_TRACE(R,M) if(p->trace)registerTrace(p->trace,R,M) |
+# define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M) |
#else |
# define REGISTER_TRACE(R,M) |
#endif |
@@ -464,20 +494,6 @@ static void registerTrace(FILE *out, int iReg, Mem *p){ |
#endif |
-/* |
-** The CHECK_FOR_INTERRUPT macro defined here looks to see if the |
-** sqlite3_interrupt() routine has been called. If it has been, then |
-** processing of the VDBE program is interrupted. |
-** |
-** This macro added to every instruction that does a jump in order to |
-** implement a loop. This test used to be on every single instruction, |
-** but that meant we more testing that we needed. By only testing the |
-** flag on jump instructions, we get a (small) speed improvement. |
-*/ |
-#define CHECK_FOR_INTERRUPT \ |
- if( db->u1.isInterrupted ) goto abort_due_to_interrupt; |
- |
- |
#ifndef NDEBUG |
/* |
** This function is only called from within an assert() expression. It |
@@ -498,50 +514,10 @@ static int checkSavepointCount(sqlite3 *db){ |
} |
#endif |
-/* |
-** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored |
-** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored |
-** in memory obtained from sqlite3DbMalloc). |
-*/ |
-static void importVtabErrMsg(Vdbe *p, sqlite3_vtab *pVtab){ |
- sqlite3 *db = p->db; |
- sqlite3DbFree(db, p->zErrMsg); |
- p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); |
- sqlite3_free(pVtab->zErrMsg); |
- pVtab->zErrMsg = 0; |
-} |
- |
/* |
-** Execute as much of a VDBE program as we can then return. |
-** |
-** sqlite3VdbeMakeReady() must be called before this routine in order to |
-** close the program with a final OP_Halt and to set up the callbacks |
-** and the error message pointer. |
-** |
-** Whenever a row or result data is available, this routine will either |
-** invoke the result callback (if there is one) or return with |
-** SQLITE_ROW. |
-** |
-** If an attempt is made to open a locked database, then this routine |
-** will either invoke the busy callback (if there is one) or it will |
-** return SQLITE_BUSY. |
-** |
-** If an error occurs, an error message is written to memory obtained |
-** from sqlite3_malloc() and p->zErrMsg is made to point to that memory. |
-** The error code is stored in p->rc and this routine returns SQLITE_ERROR. |
-** |
-** If the callback ever returns non-zero, then the program exits |
-** immediately. There will be no error message but the p->rc field is |
-** set to SQLITE_ABORT and this routine will return SQLITE_ERROR. |
-** |
-** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this |
-** routine to return SQLITE_ERROR. |
-** |
-** Other fatal errors return SQLITE_ERROR. |
-** |
-** After this routine has finished, sqlite3VdbeFinalize() should be |
-** used to clean up the mess that was left behind. |
+** Execute as much of a VDBE program as we can. |
+** This is the core of sqlite3_step(). |
*/ |
int sqlite3VdbeExec( |
Vdbe *p /* The VDBE */ |
@@ -553,20 +529,20 @@ int sqlite3VdbeExec( |
sqlite3 *db = p->db; /* The database */ |
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ |
u8 encoding = ENC(db); /* The database encoding */ |
+ int iCompare = 0; /* Result of last OP_Compare operation */ |
+ unsigned nVmStep = 0; /* Number of virtual machine steps */ |
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
- int checkProgress; /* True if progress callbacks are enabled */ |
- int nProgressOps = 0; /* Opcodes executed since progress callback. */ |
+ unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */ |
#endif |
Mem *aMem = p->aMem; /* Copy of p->aMem */ |
Mem *pIn1 = 0; /* 1st input operand */ |
Mem *pIn2 = 0; /* 2nd input operand */ |
Mem *pIn3 = 0; /* 3rd input operand */ |
Mem *pOut = 0; /* Output operand */ |
- int iCompare = 0; /* Result of last OP_Compare operation */ |
int *aPermute = 0; /* Permutation of columns for OP_Compare */ |
+ i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */ |
#ifdef VDBE_PROFILE |
u64 start; /* CPU clock count at start of opcode */ |
- int origPc; /* Program counter at start of opcode */ |
#endif |
/*** INSERT STACK UNION HERE ***/ |
@@ -578,24 +554,49 @@ int sqlite3VdbeExec( |
goto no_mem; |
} |
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY ); |
+ assert( p->bIsReader || p->readOnly!=0 ); |
p->rc = SQLITE_OK; |
+ p->iCurrentTime = 0; |
assert( p->explain==0 ); |
p->pResultSet = 0; |
db->busyHandler.nBusy = 0; |
- CHECK_FOR_INTERRUPT; |
+ if( db->u1.isInterrupted ) goto abort_due_to_interrupt; |
sqlite3VdbeIOTraceSql(p); |
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
- checkProgress = db->xProgress!=0; |
+ if( db->xProgress ){ |
+ assert( 0 < db->nProgressOps ); |
+ nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; |
+ if( nProgressLimit==0 ){ |
+ nProgressLimit = db->nProgressOps; |
+ }else{ |
+ nProgressLimit %= (unsigned)db->nProgressOps; |
+ } |
+ } |
#endif |
#ifdef SQLITE_DEBUG |
sqlite3BeginBenignMalloc(); |
- if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){ |
+ if( p->pc==0 |
+ && (p->db->flags & (SQLITE_VdbeListing|SQLITE_VdbeEQP|SQLITE_VdbeTrace))!=0 |
+ ){ |
int i; |
- printf("VDBE Program Listing:\n"); |
+ int once = 1; |
sqlite3VdbePrintSql(p); |
- for(i=0; i<p->nOp; i++){ |
- sqlite3VdbePrintOp(stdout, i, &aOp[i]); |
+ if( p->db->flags & SQLITE_VdbeListing ){ |
+ printf("VDBE Program Listing:\n"); |
+ for(i=0; i<p->nOp; i++){ |
+ sqlite3VdbePrintOp(stdout, i, &aOp[i]); |
+ } |
+ } |
+ if( p->db->flags & SQLITE_VdbeEQP ){ |
+ for(i=0; i<p->nOp; i++){ |
+ if( aOp[i].opcode==OP_Explain ){ |
+ if( once ) printf("VDBE Query Plan:\n"); |
+ printf("%s\n", aOp[i].p4.z); |
+ once = 0; |
+ } |
+ } |
} |
+ if( p->db->flags & SQLITE_VdbeTrace ) printf("VDBE Trace:\n"); |
} |
sqlite3EndBenignMalloc(); |
#endif |
@@ -603,20 +604,16 @@ int sqlite3VdbeExec( |
assert( pc>=0 && pc<p->nOp ); |
if( db->mallocFailed ) goto no_mem; |
#ifdef VDBE_PROFILE |
- origPc = pc; |
start = sqlite3Hwtime(); |
#endif |
+ nVmStep++; |
pOp = &aOp[pc]; |
/* Only allow tracing if SQLITE_DEBUG is defined. |
*/ |
#ifdef SQLITE_DEBUG |
- if( p->trace ){ |
- if( pc==0 ){ |
- printf("VDBE Execution Trace:\n"); |
- sqlite3VdbePrintSql(p); |
- } |
- sqlite3VdbePrintOp(p->trace, pc, pOp); |
+ if( db->flags & SQLITE_VdbeTrace ){ |
+ sqlite3VdbePrintOp(stdout, pc, pOp); |
} |
#endif |
@@ -633,28 +630,7 @@ int sqlite3VdbeExec( |
} |
#endif |
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
- /* Call the progress callback if it is configured and the required number |
- ** of VDBE ops have been executed (either since this invocation of |
- ** sqlite3VdbeExec() or since last time the progress callback was called). |
- ** If the progress callback returns non-zero, exit the virtual machine with |
- ** a return code SQLITE_ABORT. |
- */ |
- if( checkProgress ){ |
- if( db->nProgressOps==nProgressOps ){ |
- int prc; |
- prc = db->xProgress(db->pProgressArg); |
- if( prc!=0 ){ |
- rc = SQLITE_INTERRUPT; |
- goto vdbe_error_halt; |
- } |
- nProgressOps = 0; |
- } |
- nProgressOps++; |
- } |
-#endif |
- |
- /* On any opcode with the "out2-prerelase" tag, free any |
+ /* On any opcode with the "out2-prerelease" tag, free any |
** external allocations out of mem[p2] and set mem[p2] to be |
** an undefined integer. Opcodes will either fill in the integer |
** value or convert mem[p2] to a different type. |
@@ -662,10 +638,10 @@ int sqlite3VdbeExec( |
assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] ); |
if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){ |
assert( pOp->p2>0 ); |
- assert( pOp->p2<=p->nMem ); |
+ assert( pOp->p2<=(p->nMem-p->nCursor) ); |
pOut = &aMem[pOp->p2]; |
memAboutToChange(p, pOut); |
- sqlite3VdbeMemReleaseExternal(pOut); |
+ if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); |
pOut->flags = MEM_Int; |
} |
@@ -673,30 +649,33 @@ int sqlite3VdbeExec( |
#ifdef SQLITE_DEBUG |
if( (pOp->opflags & OPFLG_IN1)!=0 ){ |
assert( pOp->p1>0 ); |
- assert( pOp->p1<=p->nMem ); |
+ assert( pOp->p1<=(p->nMem-p->nCursor) ); |
assert( memIsValid(&aMem[pOp->p1]) ); |
+ assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); |
REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); |
} |
if( (pOp->opflags & OPFLG_IN2)!=0 ){ |
assert( pOp->p2>0 ); |
- assert( pOp->p2<=p->nMem ); |
+ assert( pOp->p2<=(p->nMem-p->nCursor) ); |
assert( memIsValid(&aMem[pOp->p2]) ); |
+ assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); |
REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); |
} |
if( (pOp->opflags & OPFLG_IN3)!=0 ){ |
assert( pOp->p3>0 ); |
- assert( pOp->p3<=p->nMem ); |
+ assert( pOp->p3<=(p->nMem-p->nCursor) ); |
assert( memIsValid(&aMem[pOp->p3]) ); |
+ assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); |
REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); |
} |
if( (pOp->opflags & OPFLG_OUT2)!=0 ){ |
assert( pOp->p2>0 ); |
- assert( pOp->p2<=p->nMem ); |
+ assert( pOp->p2<=(p->nMem-p->nCursor) ); |
memAboutToChange(p, &aMem[pOp->p2]); |
} |
if( (pOp->opflags & OPFLG_OUT3)!=0 ){ |
assert( pOp->p3>0 ); |
- assert( pOp->p3<=p->nMem ); |
+ assert( pOp->p3<=(p->nMem-p->nCursor) ); |
memAboutToChange(p, &aMem[pOp->p3]); |
} |
#endif |
@@ -744,10 +723,44 @@ int sqlite3VdbeExec( |
** The next instruction executed will be |
** the one at index P2 from the beginning of |
** the program. |
+** |
+** The P1 parameter is not actually used by this opcode. However, it |
+** is sometimes set to 1 instead of 0 as a hint to the command-line shell |
+** that this Goto is the bottom of a loop and that the lines from P2 down |
+** to the current line should be indented for EXPLAIN output. |
*/ |
case OP_Goto: { /* jump */ |
- CHECK_FOR_INTERRUPT; |
pc = pOp->p2 - 1; |
+ |
+ /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, |
+ ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon |
+ ** completion. Check to see if sqlite3_interrupt() has been called |
+ ** or if the progress callback needs to be invoked. |
+ ** |
+ ** This code uses unstructured "goto" statements and does not look clean. |
+ ** But that is not due to sloppy coding habits. The code is written this |
+ ** way for performance, to avoid having to run the interrupt and progress |
+ ** checks on every opcode. This helps sqlite3_step() to run about 1.5% |
+ ** faster according to "valgrind --tool=cachegrind" */ |
+check_for_interrupt: |
+ if( db->u1.isInterrupted ) goto abort_due_to_interrupt; |
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
+ /* Call the progress callback if it is configured and the required number |
+ ** of VDBE ops have been executed (either since this invocation of |
+ ** sqlite3VdbeExec() or since last time the progress callback was called). |
+ ** If the progress callback returns non-zero, exit the virtual machine with |
+ ** a return code SQLITE_ABORT. |
+ */ |
+ if( db->xProgress!=0 && nVmStep>=nProgressLimit ){ |
+ assert( db->nProgressOps!=0 ); |
+ nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps); |
+ if( db->xProgress(db->pProgressArg) ){ |
+ rc = SQLITE_INTERRUPT; |
+ goto vdbe_error_halt; |
+ } |
+ } |
+#endif |
+ |
break; |
} |
@@ -756,9 +769,10 @@ case OP_Goto: { /* jump */ |
** Write the current address onto register P1 |
** and then jump to address P2. |
*/ |
-case OP_Gosub: { /* jump, in1 */ |
+case OP_Gosub: { /* jump */ |
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); |
pIn1 = &aMem[pOp->p1]; |
- assert( (pIn1->flags & MEM_Dyn)==0 ); |
+ assert( VdbeMemDynamic(pIn1)==0 ); |
memAboutToChange(p, pIn1); |
pIn1->flags = MEM_Int; |
pIn1->u.i = pc; |
@@ -769,23 +783,78 @@ case OP_Gosub: { /* jump, in1 */ |
/* Opcode: Return P1 * * * * |
** |
-** Jump to the next instruction after the address in register P1. |
+** Jump to the next instruction after the address in register P1. After |
+** the jump, register P1 becomes undefined. |
*/ |
case OP_Return: { /* in1 */ |
pIn1 = &aMem[pOp->p1]; |
- assert( pIn1->flags & MEM_Int ); |
+ assert( pIn1->flags==MEM_Int ); |
pc = (int)pIn1->u.i; |
+ pIn1->flags = MEM_Undefined; |
+ break; |
+} |
+ |
+/* Opcode: InitCoroutine P1 P2 P3 * * |
+** |
+** Set up register P1 so that it will Yield to the coroutine |
+** located at address P3. |
+** |
+** If P2!=0 then the coroutine implementation immediately follows |
+** this opcode. So jump over the coroutine implementation to |
+** address P2. |
+** |
+** See also: EndCoroutine |
+*/ |
+case OP_InitCoroutine: { /* jump */ |
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); |
+ assert( pOp->p2>=0 && pOp->p2<p->nOp ); |
+ assert( pOp->p3>=0 && pOp->p3<p->nOp ); |
+ pOut = &aMem[pOp->p1]; |
+ assert( !VdbeMemDynamic(pOut) ); |
+ pOut->u.i = pOp->p3 - 1; |
+ pOut->flags = MEM_Int; |
+ if( pOp->p2 ) pc = pOp->p2 - 1; |
+ break; |
+} |
+ |
+/* Opcode: EndCoroutine P1 * * * * |
+** |
+** The instruction at the address in register P1 is a Yield. |
+** Jump to the P2 parameter of that Yield. |
+** After the jump, register P1 becomes undefined. |
+** |
+** See also: InitCoroutine |
+*/ |
+case OP_EndCoroutine: { /* in1 */ |
+ VdbeOp *pCaller; |
+ pIn1 = &aMem[pOp->p1]; |
+ assert( pIn1->flags==MEM_Int ); |
+ assert( pIn1->u.i>=0 && pIn1->u.i<p->nOp ); |
+ pCaller = &aOp[pIn1->u.i]; |
+ assert( pCaller->opcode==OP_Yield ); |
+ assert( pCaller->p2>=0 && pCaller->p2<p->nOp ); |
+ pc = pCaller->p2 - 1; |
+ pIn1->flags = MEM_Undefined; |
break; |
} |
-/* Opcode: Yield P1 * * * * |
+/* Opcode: Yield P1 P2 * * * |
** |
-** Swap the program counter with the value in register P1. |
+** Swap the program counter with the value in register P1. This |
+** has the effect of yielding to a coroutine. |
+** |
+** If the coroutine that is launched by this instruction ends with |
+** Yield or Return then continue to the next instruction. But if |
+** the coroutine launched by this instruction ends with |
+** EndCoroutine, then jump to P2 rather than continuing with the |
+** next instruction. |
+** |
+** See also: InitCoroutine |
*/ |
-case OP_Yield: { /* in1 */ |
+case OP_Yield: { /* in1, jump */ |
int pcDest; |
pIn1 = &aMem[pOp->p1]; |
- assert( (pIn1->flags & MEM_Dyn)==0 ); |
+ assert( VdbeMemDynamic(pIn1)==0 ); |
pIn1->flags = MEM_Int; |
pcDest = (int)pIn1->u.i; |
pIn1->u.i = pc; |
@@ -794,11 +863,13 @@ case OP_Yield: { /* in1 */ |
break; |
} |
-/* Opcode: HaltIfNull P1 P2 P3 P4 * |
+/* Opcode: HaltIfNull P1 P2 P3 P4 P5 |
+** Synopsis: if r[P3]=null halt |
** |
-** Check the value in register P3. If is is NULL then Halt using |
+** Check the value in register P3. If it is NULL then Halt using |
** parameter P1, P2, and P4 as if this were a Halt instruction. If the |
** value in register P3 is not NULL, then this routine is a no-op. |
+** The P5 parameter should be 1. |
*/ |
case OP_HaltIfNull: { /* in3 */ |
pIn3 = &aMem[pOp->p3]; |
@@ -806,7 +877,7 @@ case OP_HaltIfNull: { /* in3 */ |
/* Fall through into OP_Halt */ |
} |
-/* Opcode: Halt P1 P2 * P4 * |
+/* Opcode: Halt P1 P2 * P4 P5 |
** |
** Exit immediately. All open cursors, etc are closed |
** automatically. |
@@ -821,11 +892,25 @@ case OP_HaltIfNull: { /* in3 */ |
** |
** If P4 is not null then it is an error message string. |
** |
+** P5 is a value between 0 and 4, inclusive, that modifies the P4 string. |
+** |
+** 0: (no change) |
+** 1: NOT NULL contraint failed: P4 |
+** 2: UNIQUE constraint failed: P4 |
+** 3: CHECK constraint failed: P4 |
+** 4: FOREIGN KEY constraint failed: P4 |
+** |
+** If P5 is not zero and P4 is NULL, then everything after the ":" is |
+** omitted. |
+** |
** There is an implied "Halt 0 0 0" instruction inserted at the very end of |
** every program. So a jump past the last instruction of the program |
** is the same as executing Halt. |
*/ |
case OP_Halt: { |
+ const char *zType; |
+ const char *zLogFmt; |
+ |
if( pOp->p1==SQLITE_OK && p->pFrame ){ |
/* Halt the sub-program. Return control to the parent frame. */ |
VdbeFrame *pFrame = p->pFrame; |
@@ -833,6 +918,7 @@ case OP_Halt: { |
p->nFrame--; |
sqlite3VdbeSetChanges(db, p->nChange); |
pc = sqlite3VdbeFrameRestore(pFrame); |
+ lastRowid = db->lastRowid; |
if( pOp->p2==OE_Ignore ){ |
/* Instruction pc is the OP_Program that invoked the sub-program |
** currently being halted. If the p2 instruction of this OP_Halt |
@@ -845,32 +931,48 @@ case OP_Halt: { |
aMem = p->aMem; |
break; |
} |
- |
p->rc = pOp->p1; |
p->errorAction = (u8)pOp->p2; |
p->pc = pc; |
- if( pOp->p4.z ){ |
- assert( p->rc!=SQLITE_OK ); |
- sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z); |
- testcase( sqlite3GlobalConfig.xLog!=0 ); |
- sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pc, p->zSql, pOp->p4.z); |
- }else if( p->rc ){ |
- testcase( sqlite3GlobalConfig.xLog!=0 ); |
- sqlite3_log(pOp->p1, "constraint failed at %d in [%s]", pc, p->zSql); |
+ if( p->rc ){ |
+ if( pOp->p5 ){ |
+ static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", |
+ "FOREIGN KEY" }; |
+ assert( pOp->p5>=1 && pOp->p5<=4 ); |
+ testcase( pOp->p5==1 ); |
+ testcase( pOp->p5==2 ); |
+ testcase( pOp->p5==3 ); |
+ testcase( pOp->p5==4 ); |
+ zType = azType[pOp->p5-1]; |
+ }else{ |
+ zType = 0; |
+ } |
+ assert( zType!=0 || pOp->p4.z!=0 ); |
+ zLogFmt = "abort at %d in [%s]: %s"; |
+ if( zType && pOp->p4.z ){ |
+ sqlite3SetString(&p->zErrMsg, db, "%s constraint failed: %s", |
+ zType, pOp->p4.z); |
+ }else if( pOp->p4.z ){ |
+ sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z); |
+ }else{ |
+ sqlite3SetString(&p->zErrMsg, db, "%s constraint failed", zType); |
+ } |
+ sqlite3_log(pOp->p1, zLogFmt, pc, p->zSql, p->zErrMsg); |
} |
rc = sqlite3VdbeHalt(p); |
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); |
if( rc==SQLITE_BUSY ){ |
p->rc = rc = SQLITE_BUSY; |
}else{ |
- assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ); |
- assert( rc==SQLITE_OK || db->nDeferredCons>0 ); |
+ assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ); |
+ assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 ); |
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; |
} |
goto vdbe_return; |
} |
/* Opcode: Integer P1 P2 * * * |
+** Synopsis: r[P2]=P1 |
** |
** The 32-bit integer value P1 is written into register P2. |
*/ |
@@ -880,6 +982,7 @@ case OP_Integer: { /* out2-prerelease */ |
} |
/* Opcode: Int64 * P2 * P4 * |
+** Synopsis: r[P2]=P4 |
** |
** P4 is a pointer to a 64-bit integer value. |
** Write that value into register P2. |
@@ -892,6 +995,7 @@ case OP_Int64: { /* out2-prerelease */ |
#ifndef SQLITE_OMIT_FLOATING_POINT |
/* Opcode: Real * P2 * P4 * |
+** Synopsis: r[P2]=P4 |
** |
** P4 is a pointer to a 64-bit floating point value. |
** Write that value into register P2. |
@@ -899,15 +1003,18 @@ case OP_Int64: { /* out2-prerelease */ |
case OP_Real: { /* same as TK_FLOAT, out2-prerelease */ |
pOut->flags = MEM_Real; |
assert( !sqlite3IsNaN(*pOp->p4.pReal) ); |
- pOut->r = *pOp->p4.pReal; |
+ pOut->u.r = *pOp->p4.pReal; |
break; |
} |
#endif |
/* Opcode: String8 * P2 * P4 * |
+** Synopsis: r[P2]='P4' |
** |
** P4 points to a nul terminated UTF-8 string. This opcode is transformed |
-** into an OP_String before it is executed for the first time. |
+** into a String before it is executed for the first time. During |
+** this transformation, the length of string P4 is computed and stored |
+** as the P1 parameter. |
*/ |
case OP_String8: { /* same as TK_STRING, out2-prerelease */ |
assert( pOp->p4.z!=0 ); |
@@ -919,11 +1026,10 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */ |
rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); |
if( rc==SQLITE_TOOBIG ) goto too_big; |
if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; |
- assert( pOut->zMalloc==pOut->z ); |
- assert( pOut->flags & MEM_Dyn ); |
- pOut->zMalloc = 0; |
+ assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); |
+ assert( VdbeMemDynamic(pOut)==0 ); |
+ pOut->szMalloc = 0; |
pOut->flags |= MEM_Static; |
- pOut->flags &= ~MEM_Dyn; |
if( pOp->p4type==P4_DYNAMIC ){ |
sqlite3DbFree(db, pOp->p4.z); |
} |
@@ -939,6 +1045,7 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */ |
} |
/* Opcode: String P1 P2 * P4 * |
+** Synopsis: r[P2]='P4' (len=P1) |
** |
** The string value P4 of length P1 (bytes) is stored in register P2. |
*/ |
@@ -952,17 +1059,51 @@ case OP_String: { /* out2-prerelease */ |
break; |
} |
-/* Opcode: Null * P2 * * * |
+/* Opcode: Null P1 P2 P3 * * |
+** Synopsis: r[P2..P3]=NULL |
** |
-** Write a NULL into register P2. |
+** Write a NULL into registers P2. If P3 greater than P2, then also write |
+** NULL into register P3 and every register in between P2 and P3. If P3 |
+** is less than P2 (typically P3 is zero) then only register P2 is |
+** set to NULL. |
+** |
+** If the P1 value is non-zero, then also set the MEM_Cleared flag so that |
+** NULL values will not compare equal even if SQLITE_NULLEQ is set on |
+** OP_Ne or OP_Eq. |
*/ |
case OP_Null: { /* out2-prerelease */ |
- pOut->flags = MEM_Null; |
+ int cnt; |
+ u16 nullFlag; |
+ cnt = pOp->p3-pOp->p2; |
+ assert( pOp->p3<=(p->nMem-p->nCursor) ); |
+ pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; |
+ while( cnt>0 ){ |
+ pOut++; |
+ memAboutToChange(p, pOut); |
+ sqlite3VdbeMemSetNull(pOut); |
+ pOut->flags = nullFlag; |
+ cnt--; |
+ } |
break; |
} |
+/* Opcode: SoftNull P1 * * * * |
+** Synopsis: r[P1]=NULL |
+** |
+** Set register P1 to have the value NULL as seen by the OP_MakeRecord |
+** instruction, but do not free any string or blob memory associated with |
+** the register, so that if the value was a string or blob that was |
+** previously copied using OP_SCopy, the copies will continue to be valid. |
+*/ |
+case OP_SoftNull: { |
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); |
+ pOut = &aMem[pOp->p1]; |
+ pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined; |
+ break; |
+} |
-/* 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 |
** blob in register P2. |
@@ -976,16 +1117,18 @@ case OP_Blob: { /* out2-prerelease */ |
} |
/* Opcode: Variable P1 P2 * P4 * |
+** Synopsis: r[P2]=parameter(P1,P4) |
** |
** Transfer the values of bound parameter P1 into register P2 |
** |
-** If the parameter is named, then its name appears in P4 and P3==1. |
+** If the parameter is named, then its name appears in P4. |
** The P4 value is used by sqlite3_bind_parameter_name(). |
*/ |
case OP_Variable: { /* out2-prerelease */ |
Mem *pVar; /* Value being transferred */ |
assert( pOp->p1>0 && pOp->p1<=p->nVar ); |
+ assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] ); |
pVar = &p->aVar[pOp->p1 - 1]; |
if( sqlite3VdbeMemTooBig(pVar) ){ |
goto too_big; |
@@ -996,14 +1139,15 @@ case OP_Variable: { /* out2-prerelease */ |
} |
/* Opcode: Move P1 P2 P3 * * |
+** Synopsis: r[P2@P3]=r[P1@P3] |
** |
-** Move the values in register P1..P1+P3-1 over into |
-** registers P2..P2+P3-1. Registers P1..P1+P1-1 are |
+** Move the P3 values in register P1..P1+P3-1 over into |
+** registers P2..P2+P3-1. Registers P1..P1+P3-1 are |
** left holding a NULL. It is an error for register ranges |
-** P1..P1+P3-1 and P2..P2+P3-1 to overlap. |
+** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error |
+** for P3 to be less than 1. |
*/ |
case OP_Move: { |
- char *zMalloc; /* Holding variable for allocated memory */ |
int n; /* Number of registers left to copy */ |
int p1; /* Register to copy from */ |
int p2; /* Register to copy to */ |
@@ -1016,40 +1160,55 @@ case OP_Move: { |
pIn1 = &aMem[p1]; |
pOut = &aMem[p2]; |
- while( n-- ){ |
- assert( pOut<=&aMem[p->nMem] ); |
- assert( pIn1<=&aMem[p->nMem] ); |
+ do{ |
+ assert( pOut<=&aMem[(p->nMem-p->nCursor)] ); |
+ assert( pIn1<=&aMem[(p->nMem-p->nCursor)] ); |
assert( memIsValid(pIn1) ); |
memAboutToChange(p, pOut); |
- zMalloc = pOut->zMalloc; |
- pOut->zMalloc = 0; |
sqlite3VdbeMemMove(pOut, pIn1); |
- pIn1->zMalloc = zMalloc; |
+#ifdef SQLITE_DEBUG |
+ if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){ |
+ pOut->pScopyFrom += p1 - pOp->p2; |
+ } |
+#endif |
REGISTER_TRACE(p2++, pOut); |
pIn1++; |
pOut++; |
- } |
+ }while( --n ); |
break; |
} |
-/* Opcode: Copy P1 P2 * * * |
+/* Opcode: Copy P1 P2 P3 * * |
+** Synopsis: r[P2@P3+1]=r[P1@P3+1] |
** |
-** Make a copy of register P1 into register P2. |
+** Make a copy of registers P1..P1+P3 into registers P2..P2+P3. |
** |
** This instruction makes a deep copy of the value. A duplicate |
** is made of any string or blob constant. See also OP_SCopy. |
*/ |
-case OP_Copy: { /* in1, out2 */ |
+case OP_Copy: { |
+ int n; |
+ |
+ n = pOp->p3; |
pIn1 = &aMem[pOp->p1]; |
pOut = &aMem[pOp->p2]; |
assert( pOut!=pIn1 ); |
- sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); |
- Deephemeralize(pOut); |
- REGISTER_TRACE(pOp->p2, pOut); |
+ while( 1 ){ |
+ sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); |
+ Deephemeralize(pOut); |
+#ifdef SQLITE_DEBUG |
+ pOut->pScopyFrom = 0; |
+#endif |
+ REGISTER_TRACE(pOp->p2+pOp->p3-n, pOut); |
+ if( (n--)==0 ) break; |
+ pOut++; |
+ pIn1++; |
+ } |
break; |
} |
/* Opcode: SCopy P1 P2 * * * |
+** Synopsis: r[P2]=r[P1] |
** |
** Make a shallow copy of register P1 into register P2. |
** |
@@ -1061,7 +1220,7 @@ case OP_Copy: { /* in1, out2 */ |
** during the lifetime of the copy. Use OP_Copy to make a complete |
** copy. |
*/ |
-case OP_SCopy: { /* in1, out2 */ |
+case OP_SCopy: { /* out2 */ |
pIn1 = &aMem[pOp->p1]; |
pOut = &aMem[pOp->p2]; |
assert( pOut!=pIn1 ); |
@@ -1069,24 +1228,36 @@ case OP_SCopy: { /* in1, out2 */ |
#ifdef SQLITE_DEBUG |
if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1; |
#endif |
- REGISTER_TRACE(pOp->p2, pOut); |
break; |
} |
/* Opcode: ResultRow P1 P2 * * * |
+** Synopsis: output=r[P1@P2] |
** |
** The registers P1 through P1+P2-1 contain a single row of |
** results. This opcode causes the sqlite3_step() call to terminate |
** with an SQLITE_ROW return code and it sets up the sqlite3_stmt |
-** structure to provide access to the top P1 values as the result |
-** row. |
+** structure to provide access to the r(P1)..r(P1+P2-1) values as |
+** the result row. |
*/ |
case OP_ResultRow: { |
Mem *pMem; |
int i; |
assert( p->nResColumn==pOp->p2 ); |
assert( pOp->p1>0 ); |
- assert( pOp->p1+pOp->p2<=p->nMem+1 ); |
+ assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 ); |
+ |
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
+ /* Run the progress counter just before returning. |
+ */ |
+ if( db->xProgress!=0 |
+ && nVmStep>=nProgressLimit |
+ && db->xProgress(db->pProgressArg)!=0 |
+ ){ |
+ rc = SQLITE_INTERRUPT; |
+ goto vdbe_error_halt; |
+ } |
+#endif |
/* If this statement has violated immediate foreign key constraints, do |
** not return the number of rows modified. And do not RELEASE the statement |
@@ -1123,7 +1294,7 @@ case OP_ResultRow: { |
/* Make sure the results of the current row are \000 terminated |
** and have an assigned type. The results are de-ephemeralized as |
- ** as side effect. |
+ ** a side effect. |
*/ |
pMem = p->pResultSet = &aMem[pOp->p1]; |
for(i=0; i<pOp->p2; i++){ |
@@ -1132,7 +1303,6 @@ case OP_ResultRow: { |
assert( (pMem[i].flags & MEM_Ephem)==0 |
|| (pMem[i].flags & (MEM_Str|MEM_Blob))==0 ); |
sqlite3VdbeMemNulTerminate(&pMem[i]); |
- sqlite3VdbeMemStoreType(&pMem[i]); |
REGISTER_TRACE(pOp->p1+i, &pMem[i]); |
} |
if( db->mallocFailed ) goto no_mem; |
@@ -1145,6 +1315,7 @@ case OP_ResultRow: { |
} |
/* Opcode: Concat P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P2]+r[P1] |
** |
** Add the text in register P1 onto the end of the text in |
** register P2 and store the result in register P3. |
@@ -1174,15 +1345,15 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ |
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
goto too_big; |
} |
- MemSetTypeFlag(pOut, MEM_Str); |
if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ |
goto no_mem; |
} |
+ MemSetTypeFlag(pOut, MEM_Str); |
if( pOut!=pIn2 ){ |
memcpy(pOut->z, pIn2->z, pIn2->n); |
} |
memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); |
- pOut->z[nByte] = 0; |
+ pOut->z[nByte]=0; |
pOut->z[nByte+1] = 0; |
pOut->flags |= MEM_Term; |
pOut->n = (int)nByte; |
@@ -1192,12 +1363,14 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ |
} |
/* Opcode: Add P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P1]+r[P2] |
** |
** Add the value in register P1 to the value in register P2 |
** and store the result in register P3. |
** If either input is NULL, the result is NULL. |
*/ |
/* Opcode: Multiply P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P1]*r[P2] |
** |
** |
** Multiply the value in register P1 by the value in register P2 |
@@ -1205,12 +1378,14 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ |
** If either input is NULL, the result is NULL. |
*/ |
/* Opcode: Subtract P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P2]-r[P1] |
** |
** Subtract the value in register P1 from the value in register P2 |
** and store the result in register P3. |
** If either input is NULL, the result is NULL. |
*/ |
/* Opcode: Divide P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P2]/r[P1] |
** |
** Divide the value in register P1 by the value in register P2 |
** and store the result in register P3 (P3=P2/P1). If the value in |
@@ -1218,10 +1393,11 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ |
** NULL, the result is NULL. |
*/ |
/* Opcode: Remainder P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P2]%r[P1] |
** |
-** Compute the remainder after integer division of the value in |
-** register P1 by the value in register P2 and store the result in P3. |
-** If the value in register P2 is zero the result is NULL. |
+** Compute the remainder after integer register P2 is divided by |
+** register P1 and store the result in register P3. |
+** If the value in register P1 is zero the result is NULL. |
** If either operand is NULL, the result is NULL. |
*/ |
case OP_Add: /* same as TK_PLUS, in1, in2, out3 */ |
@@ -1229,22 +1405,26 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ |
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ |
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ |
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ |
- int flags; /* Combined MEM_* flags from both inputs */ |
+ char bIntint; /* Started out as two integer operands */ |
+ u16 flags; /* Combined MEM_* flags from both inputs */ |
+ u16 type1; /* Numeric type of left operand */ |
+ u16 type2; /* Numeric type of right operand */ |
i64 iA; /* Integer value of left operand */ |
i64 iB; /* Integer value of right operand */ |
double rA; /* Real value of left operand */ |
double rB; /* Real value of right operand */ |
pIn1 = &aMem[pOp->p1]; |
- applyNumericAffinity(pIn1); |
+ type1 = numericType(pIn1); |
pIn2 = &aMem[pOp->p2]; |
- applyNumericAffinity(pIn2); |
+ type2 = numericType(pIn2); |
pOut = &aMem[pOp->p3]; |
flags = pIn1->flags | pIn2->flags; |
if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; |
- if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){ |
+ if( (type1 & type2 & MEM_Int)!=0 ){ |
iA = pIn1->u.i; |
iB = pIn2->u.i; |
+ bIntint = 1; |
switch( pOp->opcode ){ |
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; |
case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break; |
@@ -1265,6 +1445,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ |
pOut->u.i = iB; |
MemSetTypeFlag(pOut, MEM_Int); |
}else{ |
+ bIntint = 0; |
fp_math: |
rA = sqlite3VdbeRealValue(pIn1); |
rB = sqlite3VdbeRealValue(pIn2); |
@@ -1294,9 +1475,9 @@ fp_math: |
if( sqlite3IsNaN(rB) ){ |
goto arithmetic_result_is_null; |
} |
- pOut->r = rB; |
+ pOut->u.r = rB; |
MemSetTypeFlag(pOut, MEM_Real); |
- if( (flags & MEM_Real)==0 ){ |
+ if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ |
sqlite3VdbeIntegerAffinity(pOut); |
} |
#endif |
@@ -1308,23 +1489,31 @@ arithmetic_result_is_null: |
break; |
} |
-/* Opcode: CollSeq * * P4 |
+/* Opcode: CollSeq P1 * * P4 |
** |
** P4 is a pointer to a CollSeq struct. If the next call to a user function |
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will |
** be returned. This is used by the built-in min(), max() and nullif() |
** functions. |
** |
+** If P1 is not zero, then it is a register that a subsequent min() or |
+** max() aggregate will set to 1 if the current row is not the minimum or |
+** maximum. The P1 register is initialized to 0 by this instruction. |
+** |
** The interface used by the implementation of the aforementioned functions |
** to retrieve the collation sequence set by this opcode is not available |
** publicly, only to user functions defined in func.c. |
*/ |
case OP_CollSeq: { |
assert( pOp->p4type==P4_COLLSEQ ); |
+ if( pOp->p1 ){ |
+ sqlite3VdbeMemSetInt64(&aMem[pOp->p1], 0); |
+ } |
break; |
} |
/* Opcode: Function P1 P2 P3 P4 P5 |
+** Synopsis: r[P3]=func(r[P2@P5]) |
** |
** Invoke a user function (P4 is a pointer to a Function structure that |
** defines the function) with P5 arguments taken from register P2 and |
@@ -1350,108 +1539,66 @@ case OP_Function: { |
n = pOp->p5; |
apVal = p->apArg; |
assert( apVal || n==0 ); |
- assert( pOp->p3>0 && pOp->p3<=p->nMem ); |
- pOut = &aMem[pOp->p3]; |
- memAboutToChange(p, pOut); |
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); |
+ ctx.pOut = &aMem[pOp->p3]; |
+ memAboutToChange(p, ctx.pOut); |
- assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) ); |
+ assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) ); |
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n ); |
pArg = &aMem[pOp->p2]; |
for(i=0; i<n; i++, pArg++){ |
assert( memIsValid(pArg) ); |
apVal[i] = pArg; |
Deephemeralize(pArg); |
- sqlite3VdbeMemStoreType(pArg); |
REGISTER_TRACE(pOp->p2+i, pArg); |
} |
- assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC ); |
- if( pOp->p4type==P4_FUNCDEF ){ |
- ctx.pFunc = pOp->p4.pFunc; |
- ctx.pVdbeFunc = 0; |
- }else{ |
- ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc; |
- ctx.pFunc = ctx.pVdbeFunc->pFunc; |
- } |
- |
- ctx.s.flags = MEM_Null; |
- ctx.s.db = db; |
- ctx.s.xDel = 0; |
- ctx.s.zMalloc = 0; |
- |
- /* The output cell may already have a buffer allocated. Move |
- ** the pointer to ctx.s so in case the user-function can use |
- ** the already allocated buffer instead of allocating a new one. |
- */ |
- sqlite3VdbeMemMove(&ctx.s, pOut); |
- MemSetTypeFlag(&ctx.s, MEM_Null); |
- |
- ctx.isError = 0; |
- if( ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){ |
- assert( pOp>aOp ); |
- assert( pOp[-1].p4type==P4_COLLSEQ ); |
- assert( pOp[-1].opcode==OP_CollSeq ); |
- ctx.pColl = pOp[-1].p4.pColl; |
- } |
+ assert( pOp->p4type==P4_FUNCDEF ); |
+ ctx.pFunc = pOp->p4.pFunc; |
+ ctx.iOp = pc; |
+ ctx.pVdbe = p; |
+ MemSetTypeFlag(ctx.pOut, MEM_Null); |
+ ctx.fErrorOrAux = 0; |
+ db->lastRowid = lastRowid; |
(*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */ |
- if( db->mallocFailed ){ |
- /* Even though a malloc() has failed, the implementation of the |
- ** user function may have called an sqlite3_result_XXX() function |
- ** to return a value. The following call releases any resources |
- ** associated with such a value. |
- */ |
- sqlite3VdbeMemRelease(&ctx.s); |
- goto no_mem; |
- } |
- |
- /* If any auxiliary data functions have been called by this user function, |
- ** immediately call the destructor for any non-static values. |
- */ |
- if( ctx.pVdbeFunc ){ |
- sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1); |
- pOp->p4.pVdbeFunc = ctx.pVdbeFunc; |
- pOp->p4type = P4_VDBEFUNC; |
- } |
+ lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */ |
/* If the function returned an error, throw an exception */ |
- if( ctx.isError ){ |
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s)); |
- rc = ctx.isError; |
+ if( ctx.fErrorOrAux ){ |
+ if( ctx.isError ){ |
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut)); |
+ rc = ctx.isError; |
+ } |
+ sqlite3VdbeDeleteAuxData(p, pc, pOp->p1); |
} |
/* Copy the result of the function into register P3 */ |
- sqlite3VdbeChangeEncoding(&ctx.s, encoding); |
- sqlite3VdbeMemMove(pOut, &ctx.s); |
- if( sqlite3VdbeMemTooBig(pOut) ){ |
+ sqlite3VdbeChangeEncoding(ctx.pOut, encoding); |
+ if( sqlite3VdbeMemTooBig(ctx.pOut) ){ |
goto too_big; |
} |
-#if 0 |
- /* The app-defined function has done something that as caused this |
- ** statement to expire. (Perhaps the function called sqlite3_exec() |
- ** with a CREATE TABLE statement.) |
- */ |
- if( p->expired ) rc = SQLITE_ABORT; |
-#endif |
- |
- REGISTER_TRACE(pOp->p3, pOut); |
- UPDATE_MAX_BLOBSIZE(pOut); |
+ REGISTER_TRACE(pOp->p3, ctx.pOut); |
+ UPDATE_MAX_BLOBSIZE(ctx.pOut); |
break; |
} |
/* Opcode: BitAnd P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P1]&r[P2] |
** |
** Take the bit-wise AND of the values in register P1 and P2 and |
** store the result in register P3. |
** If either input is NULL, the result is NULL. |
*/ |
/* Opcode: BitOr P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P1]|r[P2] |
** |
** Take the bit-wise OR of the values in register P1 and P2 and |
** store the result in register P3. |
** If either input is NULL, the result is NULL. |
*/ |
/* Opcode: ShiftLeft P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P2]<<r[P1] |
** |
** Shift the integer value in register P2 to the left by the |
** number of bits specified by the integer in register P1. |
@@ -1459,6 +1606,7 @@ case OP_Function: { |
** If either input is NULL, the result is NULL. |
*/ |
/* Opcode: ShiftRight P1 P2 P3 * * |
+** Synopsis: r[P3]=r[P2]>>r[P1] |
** |
** Shift the integer value in register P2 to the right by the |
** number of bits specified by the integer in register P1. |
@@ -1518,6 +1666,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ |
} |
/* Opcode: AddImm P1 P2 * * * |
+** Synopsis: r[P1]=r[P1]+P2 |
** |
** Add the constant P2 to the value in register P1. |
** The result is always an integer. |
@@ -1541,17 +1690,20 @@ case OP_AddImm: { /* in1 */ |
*/ |
case OP_MustBeInt: { /* jump, in1 */ |
pIn1 = &aMem[pOp->p1]; |
- applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); |
if( (pIn1->flags & MEM_Int)==0 ){ |
- if( pOp->p2==0 ){ |
- rc = SQLITE_MISMATCH; |
- goto abort_due_to_error; |
- }else{ |
- pc = pOp->p2 - 1; |
+ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); |
+ VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); |
+ if( (pIn1->flags & MEM_Int)==0 ){ |
+ if( pOp->p2==0 ){ |
+ rc = SQLITE_MISMATCH; |
+ goto abort_due_to_error; |
+ }else{ |
+ pc = pOp->p2 - 1; |
+ break; |
+ } |
} |
- }else{ |
- MemSetTypeFlag(pIn1, MEM_Int); |
} |
+ MemSetTypeFlag(pIn1, MEM_Int); |
break; |
} |
@@ -1575,107 +1727,39 @@ case OP_RealAffinity: { /* in1 */ |
#endif |
#ifndef SQLITE_OMIT_CAST |
-/* Opcode: ToText P1 * * * * |
+/* Opcode: Cast P1 P2 * * * |
+** Synopsis: affinity(r[P1]) |
** |
-** Force the value in register P1 to be text. |
-** If the value is numeric, convert it to a string using the |
-** equivalent of printf(). Blob values are unchanged and |
-** are afterwards simply interpreted as text. |
+** Force the value in register P1 to be the type defined by P2. |
+** |
+** <ul> |
+** <li value="97"> TEXT |
+** <li value="98"> BLOB |
+** <li value="99"> NUMERIC |
+** <li value="100"> INTEGER |
+** <li value="101"> REAL |
+** </ul> |
** |
** A NULL value is not changed by this routine. It remains NULL. |
*/ |
-case OP_ToText: { /* same as TK_TO_TEXT, in1 */ |
+case OP_Cast: { /* in1 */ |
+ assert( pOp->p2>=SQLITE_AFF_NONE && pOp->p2<=SQLITE_AFF_REAL ); |
+ testcase( pOp->p2==SQLITE_AFF_TEXT ); |
+ testcase( pOp->p2==SQLITE_AFF_NONE ); |
+ testcase( pOp->p2==SQLITE_AFF_NUMERIC ); |
+ testcase( pOp->p2==SQLITE_AFF_INTEGER ); |
+ testcase( pOp->p2==SQLITE_AFF_REAL ); |
pIn1 = &aMem[pOp->p1]; |
memAboutToChange(p, pIn1); |
- if( pIn1->flags & MEM_Null ) break; |
- assert( MEM_Str==(MEM_Blob>>3) ); |
- pIn1->flags |= (pIn1->flags&MEM_Blob)>>3; |
- applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); |
rc = ExpandBlob(pIn1); |
- assert( pIn1->flags & MEM_Str || db->mallocFailed ); |
- pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); |
- UPDATE_MAX_BLOBSIZE(pIn1); |
- break; |
-} |
- |
-/* Opcode: ToBlob P1 * * * * |
-** |
-** Force the value in register P1 to be a BLOB. |
-** If the value is numeric, convert it to a string first. |
-** Strings are simply reinterpreted as blobs with no change |
-** to the underlying data. |
-** |
-** A NULL value is not changed by this routine. It remains NULL. |
-*/ |
-case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ |
- pIn1 = &aMem[pOp->p1]; |
- if( pIn1->flags & MEM_Null ) break; |
- if( (pIn1->flags & MEM_Blob)==0 ){ |
- applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); |
- assert( pIn1->flags & MEM_Str || db->mallocFailed ); |
- MemSetTypeFlag(pIn1, MEM_Blob); |
- }else{ |
- pIn1->flags &= ~(MEM_TypeMask&~MEM_Blob); |
- } |
+ sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); |
UPDATE_MAX_BLOBSIZE(pIn1); |
break; |
} |
- |
-/* Opcode: ToNumeric P1 * * * * |
-** |
-** Force the value in register P1 to be numeric (either an |
-** integer or a floating-point number.) |
-** If the value is text or blob, try to convert it to an using the |
-** equivalent of atoi() or atof() and store 0 if no such conversion |
-** is possible. |
-** |
-** A NULL value is not changed by this routine. It remains NULL. |
-*/ |
-case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */ |
- pIn1 = &aMem[pOp->p1]; |
- sqlite3VdbeMemNumerify(pIn1); |
- break; |
-} |
#endif /* SQLITE_OMIT_CAST */ |
-/* Opcode: ToInt P1 * * * * |
-** |
-** Force the value in register P1 to be an integer. If |
-** The value is currently a real number, drop its fractional part. |
-** If the value is text or blob, try to convert it to an integer using the |
-** equivalent of atoi() and store 0 if no such conversion is possible. |
-** |
-** A NULL value is not changed by this routine. It remains NULL. |
-*/ |
-case OP_ToInt: { /* same as TK_TO_INT, in1 */ |
- pIn1 = &aMem[pOp->p1]; |
- if( (pIn1->flags & MEM_Null)==0 ){ |
- sqlite3VdbeMemIntegerify(pIn1); |
- } |
- break; |
-} |
- |
-#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) |
-/* Opcode: ToReal P1 * * * * |
-** |
-** Force the value in register P1 to be a floating point number. |
-** If The value is currently an integer, convert it. |
-** If the value is text or blob, try to convert it to an integer using the |
-** equivalent of atoi() and store 0.0 if no such conversion is possible. |
-** |
-** A NULL value is not changed by this routine. It remains NULL. |
-*/ |
-case OP_ToReal: { /* same as TK_TO_REAL, in1 */ |
- pIn1 = &aMem[pOp->p1]; |
- memAboutToChange(p, pIn1); |
- if( (pIn1->flags & MEM_Null)==0 ){ |
- sqlite3VdbeMemRealify(pIn1); |
- } |
- break; |
-} |
-#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */ |
- |
/* Opcode: Lt P1 P2 P3 P4 P5 |
+** Synopsis: if r[P1]<r[P3] goto P2 |
** |
** Compare the values in register P1 and P3. If reg(P3)<reg(P1) then |
** jump to address P2. |
@@ -1704,8 +1788,13 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */ |
** |
** If the SQLITE_STOREP2 bit of P5 is set, then do not jump. Instead, |
** store a boolean result (either 0, or 1, or NULL) in register P2. |
+** |
+** If the SQLITE_NULLEQ bit is set in P5, then NULL values are considered |
+** equal to one another, provided that they do not have their MEM_Cleared |
+** bit set. |
*/ |
/* Opcode: Ne P1 P2 P3 P4 P5 |
+** Synopsis: if r[P1]!=r[P3] goto P2 |
** |
** This works just like the Lt opcode except that the jump is taken if |
** the operands in registers P1 and P3 are not equal. See the Lt opcode for |
@@ -1714,10 +1803,11 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */ |
** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either |
** true or false and is never NULL. If both operands are NULL then the result |
** of comparison is false. If either operand is NULL then the result is true. |
-** If neither operand is NULL the the result is the same as it would be if |
+** If neither operand is NULL the result is the same as it would be if |
** the SQLITE_NULLEQ flag were omitted from P5. |
*/ |
/* Opcode: Eq P1 P2 P3 P4 P5 |
+** Synopsis: if r[P1]==r[P3] goto P2 |
** |
** This works just like the Lt opcode except that the jump is taken if |
** the operands in registers P1 and P3 are equal. |
@@ -1726,22 +1816,25 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */ |
** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either |
** true or false and is never NULL. If both operands are NULL then the result |
** of comparison is true. If either operand is NULL then the result is false. |
-** If neither operand is NULL the the result is the same as it would be if |
+** If neither operand is NULL the result is the same as it would be if |
** the SQLITE_NULLEQ flag were omitted from P5. |
*/ |
/* Opcode: Le P1 P2 P3 P4 P5 |
+** Synopsis: if r[P1]<=r[P3] goto P2 |
** |
** This works just like the Lt opcode except that the jump is taken if |
** the content of register P3 is less than or equal to the content of |
** register P1. See the Lt opcode for additional information. |
*/ |
/* Opcode: Gt P1 P2 P3 P4 P5 |
+** Synopsis: if r[P1]>r[P3] goto P2 |
** |
** This works just like the Lt opcode except that the jump is taken if |
** the content of register P3 is greater than the content of |
** register P1. See the Lt opcode for additional information. |
*/ |
/* Opcode: Ge P1 P2 P3 P4 P5 |
+** Synopsis: if r[P1]>=r[P3] goto P2 |
** |
** This works just like the Lt opcode except that the jump is taken if |
** the content of register P3 is greater than or equal to the content of |
@@ -1762,7 +1855,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ |
pIn3 = &aMem[pOp->p3]; |
flags1 = pIn1->flags; |
flags3 = pIn3->flags; |
- if( (pIn1->flags | pIn3->flags)&MEM_Null ){ |
+ if( (flags1 | flags3)&MEM_Null ){ |
/* One or both operands are NULL */ |
if( pOp->p5 & SQLITE_NULLEQ ){ |
/* If SQLITE_NULLEQ is set (which will only happen if the operator is |
@@ -1770,7 +1863,16 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ |
** or not both operands are null. |
*/ |
assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); |
- res = (pIn1->flags & pIn3->flags & MEM_Null)==0; |
+ assert( (flags1 & MEM_Cleared)==0 ); |
+ assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 ); |
+ if( (flags1&MEM_Null)!=0 |
+ && (flags3&MEM_Null)!=0 |
+ && (flags3&MEM_Cleared)==0 |
+ ){ |
+ res = 0; /* Results are equal */ |
+ }else{ |
+ res = 1; /* Results are not equal */ |
+ } |
}else{ |
/* SQLITE_NULLEQ is clear and at least one operand is NULL, |
** then the result is always NULL. |
@@ -1780,23 +1882,46 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ |
pOut = &aMem[pOp->p2]; |
MemSetTypeFlag(pOut, MEM_Null); |
REGISTER_TRACE(pOp->p2, pOut); |
- }else if( pOp->p5 & SQLITE_JUMPIFNULL ){ |
- pc = pOp->p2-1; |
+ }else{ |
+ VdbeBranchTaken(2,3); |
+ if( pOp->p5 & SQLITE_JUMPIFNULL ){ |
+ pc = pOp->p2-1; |
+ } |
} |
break; |
} |
}else{ |
/* Neither operand is NULL. Do a comparison. */ |
affinity = pOp->p5 & SQLITE_AFF_MASK; |
- if( affinity ){ |
- applyAffinity(pIn1, affinity, encoding); |
- applyAffinity(pIn3, affinity, encoding); |
- if( db->mallocFailed ) goto no_mem; |
+ if( affinity>=SQLITE_AFF_NUMERIC ){ |
+ if( (pIn1->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ |
+ applyNumericAffinity(pIn1,0); |
+ } |
+ if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ |
+ applyNumericAffinity(pIn3,0); |
+ } |
+ }else if( affinity==SQLITE_AFF_TEXT ){ |
+ if( (pIn1->flags & MEM_Str)==0 && (pIn1->flags & (MEM_Int|MEM_Real))!=0 ){ |
+ testcase( pIn1->flags & MEM_Int ); |
+ testcase( pIn1->flags & MEM_Real ); |
+ sqlite3VdbeMemStringify(pIn1, encoding, 1); |
+ } |
+ if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){ |
+ testcase( pIn3->flags & MEM_Int ); |
+ testcase( pIn3->flags & MEM_Real ); |
+ sqlite3VdbeMemStringify(pIn3, encoding, 1); |
+ } |
} |
- |
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); |
- ExpandBlob(pIn1); |
- ExpandBlob(pIn3); |
+ if( pIn1->flags & MEM_Zero ){ |
+ sqlite3VdbeMemExpandBlob(pIn1); |
+ flags1 &= ~MEM_Zero; |
+ } |
+ if( pIn3->flags & MEM_Zero ){ |
+ sqlite3VdbeMemExpandBlob(pIn3); |
+ flags3 &= ~MEM_Zero; |
+ } |
+ if( db->mallocFailed ) goto no_mem; |
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); |
} |
switch( pOp->opcode ){ |
@@ -1814,13 +1939,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ |
MemSetTypeFlag(pOut, MEM_Int); |
pOut->u.i = res; |
REGISTER_TRACE(pOp->p2, pOut); |
- }else if( res ){ |
- pc = pOp->p2-1; |
+ }else{ |
+ VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); |
+ if( res ){ |
+ pc = pOp->p2-1; |
+ } |
} |
- |
/* Undo any changes made by applyAffinity() to the input registers. */ |
- pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (flags1&MEM_TypeMask); |
- pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (flags3&MEM_TypeMask); |
+ pIn1->flags = flags1; |
+ pIn3->flags = flags3; |
break; |
} |
@@ -1829,9 +1956,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ |
** Set the permutation used by the OP_Compare operator to be the array |
** of integers in P4. |
** |
-** The permutation is only valid until the next OP_Permutation, OP_Compare, |
-** OP_Halt, or OP_ResultRow. Typically the OP_Permutation should occur |
-** immediately prior to the OP_Compare. |
+** 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. |
*/ |
case OP_Permutation: { |
assert( pOp->p4type==P4_INTARRAY ); |
@@ -1840,12 +1967,18 @@ case OP_Permutation: { |
break; |
} |
-/* Opcode: Compare P1 P2 P3 P4 * |
+/* Opcode: Compare P1 P2 P3 P4 P5 |
+** Synopsis: r[P1@P3] <-> r[P2@P3] |
** |
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this |
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of |
** the comparison for use by the next OP_Jump instruct. |
** |
+** If P5 has the OPFLAG_PERMUTE bit set, then the order of comparison is |
+** determined by the most recent OP_Permutation operator. If the |
+** OPFLAG_PERMUTE bit is clear, then register are compared in sequential |
+** order. |
+** |
** P4 is a KeyInfo structure that defines collating sequences and sort |
** orders for the comparison. The permutation applies to registers |
** only. The KeyInfo elements are used sequentially. |
@@ -1864,6 +1997,7 @@ case OP_Compare: { |
CollSeq *pColl; /* Collating sequence to use on this term */ |
int bRev; /* True for DESCENDING sort order */ |
+ if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0; |
n = pOp->p3; |
pKeyInfo = pOp->p4.pKeyInfo; |
assert( n>0 ); |
@@ -1874,11 +2008,11 @@ case OP_Compare: { |
if( aPermute ){ |
int k, mx = 0; |
for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k]; |
- assert( p1>0 && p1+mx<=p->nMem+1 ); |
- assert( p2>0 && p2+mx<=p->nMem+1 ); |
+ assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 ); |
+ assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 ); |
}else{ |
- assert( p1>0 && p1+n<=p->nMem+1 ); |
- assert( p2>0 && p2+n<=p->nMem+1 ); |
+ assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 ); |
+ assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 ); |
} |
#endif /* SQLITE_DEBUG */ |
for(i=0; i<n; i++){ |
@@ -1908,16 +2042,17 @@ case OP_Compare: { |
*/ |
case OP_Jump: { /* jump */ |
if( iCompare<0 ){ |
- pc = pOp->p1 - 1; |
+ pc = pOp->p1 - 1; VdbeBranchTaken(0,3); |
}else if( iCompare==0 ){ |
- pc = pOp->p2 - 1; |
+ pc = pOp->p2 - 1; VdbeBranchTaken(1,3); |
}else{ |
- pc = pOp->p3 - 1; |
+ pc = pOp->p3 - 1; VdbeBranchTaken(2,3); |
} |
break; |
} |
/* Opcode: And P1 P2 P3 * * |
+** Synopsis: r[P3]=(r[P1] && r[P2]) |
** |
** Take the logical AND of the values in registers P1 and P2 and |
** write the result into register P3. |
@@ -1927,6 +2062,7 @@ case OP_Jump: { /* jump */ |
** a NULL output. |
*/ |
/* Opcode: Or P1 P2 P3 * * |
+** Synopsis: r[P3]=(r[P1] || r[P2]) |
** |
** Take the logical OR of the values in register P1 and P2 and |
** store the answer in register P3. |
@@ -1970,6 +2106,7 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ |
} |
/* Opcode: Not P1 P2 * * * |
+** Synopsis: r[P2]= !r[P1] |
** |
** Interpret the value in register P1 as a boolean value. Store the |
** boolean complement in register P2. If the value in register P1 is |
@@ -1978,15 +2115,16 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ |
case OP_Not: { /* same as TK_NOT, in1, out2 */ |
pIn1 = &aMem[pOp->p1]; |
pOut = &aMem[pOp->p2]; |
- if( pIn1->flags & MEM_Null ){ |
- sqlite3VdbeMemSetNull(pOut); |
- }else{ |
- sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeIntValue(pIn1)); |
+ sqlite3VdbeMemSetNull(pOut); |
+ if( (pIn1->flags & MEM_Null)==0 ){ |
+ pOut->flags = MEM_Int; |
+ pOut->u.i = !sqlite3VdbeIntValue(pIn1); |
} |
break; |
} |
/* Opcode: BitNot P1 P2 * * * |
+** Synopsis: r[P1]= ~r[P1] |
** |
** Interpret the content of register P1 as an integer. Store the |
** ones-complement of the P1 value into register P2. If P1 holds |
@@ -1995,25 +2133,47 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */ |
case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ |
pIn1 = &aMem[pOp->p1]; |
pOut = &aMem[pOp->p2]; |
- if( pIn1->flags & MEM_Null ){ |
- sqlite3VdbeMemSetNull(pOut); |
+ sqlite3VdbeMemSetNull(pOut); |
+ if( (pIn1->flags & MEM_Null)==0 ){ |
+ pOut->flags = MEM_Int; |
+ pOut->u.i = ~sqlite3VdbeIntValue(pIn1); |
+ } |
+ break; |
+} |
+ |
+/* Opcode: Once P1 P2 * * * |
+** |
+** Check the "once" flag number P1. If it is set, jump to instruction P2. |
+** Otherwise, set the flag and fall through to the next instruction. |
+** In other words, this opcode causes all following opcodes up through P2 |
+** (but not including P2) to run just once and to be skipped on subsequent |
+** times through the loop. |
+** |
+** All "once" flags are initially cleared whenever a prepared statement |
+** first begins to run. |
+*/ |
+case OP_Once: { /* jump */ |
+ assert( pOp->p1<p->nOnceFlag ); |
+ VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2); |
+ if( p->aOnceFlag[pOp->p1] ){ |
+ pc = pOp->p2-1; |
}else{ |
- sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1)); |
+ p->aOnceFlag[pOp->p1] = 1; |
} |
break; |
} |
/* Opcode: If P1 P2 P3 * * |
** |
-** Jump to P2 if the value in register P1 is true. The value is |
+** Jump to P2 if the value in register P1 is true. The value |
** is considered true if it is numeric and non-zero. If the value |
-** in P1 is NULL then take the jump if P3 is true. |
+** in P1 is NULL then take the jump if and only if P3 is non-zero. |
*/ |
/* Opcode: IfNot P1 P2 P3 * * |
** |
-** Jump to P2 if the value in register P1 is False. The value is |
-** is considered true if it has a numeric value of zero. If the value |
-** in P1 is NULL then take the jump if P3 is true. |
+** Jump to P2 if the value in register P1 is False. The value |
+** is considered false if it has a numeric value of zero. If the value |
+** in P1 is NULL then take the jump if and only if P3 is non-zero. |
*/ |
case OP_If: /* jump, in1 */ |
case OP_IfNot: { /* jump, in1 */ |
@@ -2029,6 +2189,7 @@ case OP_IfNot: { /* jump, in1 */ |
#endif |
if( pOp->opcode==OP_IfNot ) c = !c; |
} |
+ VdbeBranchTaken(c!=0, 2); |
if( c ){ |
pc = pOp->p2-1; |
} |
@@ -2036,11 +2197,13 @@ case OP_IfNot: { /* jump, in1 */ |
} |
/* Opcode: IsNull P1 P2 * * * |
+** Synopsis: if r[P1]==NULL goto P2 |
** |
** Jump to P2 if the value in register P1 is NULL. |
*/ |
case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ |
pIn1 = &aMem[pOp->p1]; |
+ VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2); |
if( (pIn1->flags & MEM_Null)!=0 ){ |
pc = pOp->p2 - 1; |
} |
@@ -2048,11 +2211,13 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ |
} |
/* Opcode: NotNull P1 P2 * * * |
+** Synopsis: if r[P1]!=NULL goto P2 |
** |
** Jump to P2 if the value in register P1 is not NULL. |
*/ |
case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ |
pIn1 = &aMem[pOp->p1]; |
+ VdbeBranchTaken( (pIn1->flags & MEM_Null)==0, 2); |
if( (pIn1->flags & MEM_Null)==0 ){ |
pc = pOp->p2 - 1; |
} |
@@ -2060,6 +2225,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ |
} |
/* Opcode: Column P1 P2 P3 P4 P5 |
+** Synopsis: r[P3]=PX |
** |
** Interpret the data that cursor P1 points to as a structure built using |
** the MakeRecord instruction. (See the MakeRecord opcode for additional |
@@ -2077,149 +2243,96 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ |
** 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. |
+** |
+** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when |
+** the result is guaranteed to only be used as the argument of a length() |
+** or typeof() function, respectively. The loading of large blobs can be |
+** skipped for length() and all content loading can be skipped for typeof(). |
*/ |
case OP_Column: { |
- u32 payloadSize; /* Number of bytes in the record */ |
i64 payloadSize64; /* Number of bytes in the record */ |
- int p1; /* P1 value of the opcode */ |
int p2; /* column number to retrieve */ |
VdbeCursor *pC; /* The VDBE cursor */ |
- char *zRec; /* Pointer to complete record-data */ |
BtCursor *pCrsr; /* The BTree cursor */ |
- u32 *aType; /* aType[i] holds the numeric type of the i-th column */ |
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ |
- int nField; /* number of fields in the record */ |
int len; /* The length of the serialized data for the column */ |
int i; /* Loop counter */ |
- char *zData; /* Part of the record being decoded */ |
Mem *pDest; /* Where to write the extracted value */ |
Mem sMem; /* For storing the record being decoded */ |
- u8 *zIdx; /* Index into header */ |
- u8 *zEndHdr; /* Pointer to first byte after the header */ |
+ const u8 *zData; /* Part of the record being decoded */ |
+ const u8 *zHdr; /* Next unparsed byte of the header */ |
+ const u8 *zEndHdr; /* Pointer to first byte after the header */ |
u32 offset; /* Offset into the data */ |
u32 szField; /* Number of bytes in the content of a field */ |
- int szHdr; /* Size of the header size field at start of record */ |
- int avail; /* Number of bytes of available data */ |
+ u32 avail; /* Number of bytes of available data */ |
+ u32 t; /* A type code from the record header */ |
+ u16 fx; /* pDest->flags value */ |
Mem *pReg; /* PseudoTable input register */ |
- |
- p1 = pOp->p1; |
p2 = pOp->p2; |
- pC = 0; |
- memset(&sMem, 0, sizeof(sMem)); |
- assert( p1<p->nCursor ); |
- assert( pOp->p3>0 && pOp->p3<=p->nMem ); |
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); |
pDest = &aMem[pOp->p3]; |
memAboutToChange(p, pDest); |
- MemSetTypeFlag(pDest, MEM_Null); |
- zRec = 0; |
- |
- /* This block sets the variable payloadSize to be the total number of |
- ** bytes in the record. |
- ** |
- ** zRec is set to be the complete text of the record if it is available. |
- ** The complete record text is always available for pseudo-tables |
- ** If the record is stored in a cursor, the complete record text |
- ** might be available in the pC->aRow cache. Or it might not be. |
- ** If the data is unavailable, zRec is set to NULL. |
- ** |
- ** We also compute the number of columns in the record. For cursors, |
- ** the number of columns is stored in the VdbeCursor.nField element. |
- */ |
- pC = p->apCsr[p1]; |
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
+ pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
+ assert( p2<pC->nField ); |
+ aOffset = pC->aOffset; |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
- assert( pC->pVtabCursor==0 ); |
+ assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */ |
#endif |
pCrsr = pC->pCursor; |
- if( pCrsr!=0 ){ |
- /* The record is stored in a B-Tree */ |
- rc = sqlite3VdbeCursorMoveto(pC); |
- if( rc ) goto abort_due_to_error; |
- if( pC->nullRow ){ |
- payloadSize = 0; |
- }else if( pC->cacheStatus==p->cacheCtr ){ |
- payloadSize = pC->payloadSize; |
- zRec = (char*)pC->aRow; |
- }else if( pC->isIndex ){ |
- assert( sqlite3BtreeCursorIsValid(pCrsr) ); |
- rc = sqlite3BtreeKeySize(pCrsr, &payloadSize64); |
- assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ |
- /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the |
- ** payload size, so it is impossible for payloadSize64 to be |
- ** larger than 32 bits. */ |
- assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 ); |
- payloadSize = (u32)payloadSize64; |
- }else{ |
- assert( sqlite3BtreeCursorIsValid(pCrsr) ); |
- rc = sqlite3BtreeDataSize(pCrsr, &payloadSize); |
- assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ |
- } |
- }else if( pC->pseudoTableReg>0 ){ |
- pReg = &aMem[pC->pseudoTableReg]; |
- assert( pReg->flags & MEM_Blob ); |
- assert( memIsValid(pReg) ); |
- 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 */ |
- payloadSize = 0; |
- } |
- |
- /* If payloadSize is 0, then just store a NULL */ |
- if( payloadSize==0 ){ |
- assert( pDest->flags&MEM_Null ); |
- goto op_column_out; |
- } |
- assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 ); |
- if( payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
- goto too_big; |
- } |
- |
- nField = pC->nField; |
- assert( p2<nField ); |
- |
- /* Read and parse the table header. Store the results of the parse |
- ** into the record header cache fields of the cursor. |
- */ |
- aType = pC->aType; |
- if( pC->cacheStatus==p->cacheCtr ){ |
- aOffset = pC->aOffset; |
- }else{ |
- assert(aType); |
- avail = 0; |
- pC->aOffset = aOffset = &aType[nField]; |
- pC->payloadSize = payloadSize; |
- pC->cacheStatus = p->cacheCtr; |
+ assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */ |
+ assert( pCrsr!=0 || pC->nullRow ); /* pC->nullRow on PseudoTables */ |
- /* Figure out how many bytes are in the header */ |
- if( zRec ){ |
- zData = zRec; |
+ /* 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 ){ |
+ if( pCrsr==0 ){ |
+ assert( pC->pseudoTableReg>0 ); |
+ pReg = &aMem[pC->pseudoTableReg]; |
+ assert( pReg->flags & MEM_Blob ); |
+ assert( memIsValid(pReg) ); |
+ pC->payloadSize = pC->szRow = avail = pReg->n; |
+ pC->aRow = (u8*)pReg->z; |
+ }else{ |
+ sqlite3VdbeMemSetNull(pDest); |
+ goto op_column_out; |
+ } |
}else{ |
- if( pC->isIndex ){ |
- zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail); |
+ assert( pCrsr ); |
+ if( pC->isTable==0 ){ |
+ assert( sqlite3BtreeCursorIsValid(pCrsr) ); |
+ VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64); |
+ assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ |
+ /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the |
+ ** payload size, so it is impossible for payloadSize64 to be |
+ ** larger than 32 bits. */ |
+ assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 ); |
+ pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail); |
+ pC->payloadSize = (u32)payloadSize64; |
}else{ |
- zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail); |
+ assert( sqlite3BtreeCursorIsValid(pCrsr) ); |
+ VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize); |
+ assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ |
+ pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail); |
} |
- /* If KeyFetch()/DataFetch() managed to get the entire payload, |
- ** save the payload in the pC->aRow cache. That will save us from |
- ** having to make additional calls to fetch the content portion of |
- ** the record. |
- */ |
- assert( avail>=0 ); |
- if( payloadSize <= (u32)avail ){ |
- zRec = zData; |
- pC->aRow = (u8*)zData; |
+ assert( avail<=65536 ); /* Maximum page size is 64KiB */ |
+ if( pC->payloadSize <= (u32)avail ){ |
+ pC->szRow = pC->payloadSize; |
}else{ |
- pC->aRow = 0; |
+ pC->szRow = avail; |
+ } |
+ if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
+ goto too_big; |
} |
} |
- /* The following assert is true in all cases accept when |
- ** the database file has been corrupted externally. |
- ** assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */ |
- szHdr = getVarint32((u8*)zData, offset); |
+ pC->cacheStatus = p->cacheCtr; |
+ pC->iHdrOffset = getVarint32(pC->aRow, offset); |
+ pC->nHdrParsed = 0; |
+ aOffset[0] = offset; |
/* Make sure a corrupt database has not given us an oversize header. |
** Do this now to avoid an oversize memory allocation. |
@@ -2230,140 +2343,174 @@ case OP_Column: { |
** 3-byte type for each of the maximum of 32768 columns plus three |
** extra bytes for the header length itself. 32768*3 + 3 = 98307. |
*/ |
- if( offset > 98307 ){ |
+ if( offset > 98307 || offset > pC->payloadSize ){ |
rc = SQLITE_CORRUPT_BKPT; |
- goto op_column_out; |
+ goto op_column_error; |
} |
- /* Compute in len the number of bytes of data we need to read in order |
- ** to get nField type values. offset is an upper bound on this. But |
- ** nField might be significantly less than the true number of columns |
- ** in the table, and in that case, 5*nField+3 might be smaller than offset. |
- ** We want to minimize len in order to limit the size of the memory |
- ** allocation, especially if a corrupt database file has caused offset |
- ** to be oversized. Offset is limited to 98307 above. But 98307 might |
- ** still exceed Robson memory allocation limits on some configurations. |
- ** On systems that cannot tolerate large memory allocations, nField*5+3 |
- ** will likely be much smaller since nField will likely be less than |
- ** 20 or so. This insures that Robson memory allocation limits are |
- ** not exceeded even for corrupt database files. |
- */ |
- len = nField*5 + 3; |
- if( len > (int)offset ) len = (int)offset; |
- |
- /* The KeyFetch() or DataFetch() above are fast and will get the entire |
- ** record header in most cases. But they will fail to get the complete |
- ** record header if the record header does not fit on a single page |
- ** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to |
- ** acquire the complete header text. |
- */ |
- if( !zRec && avail<len ){ |
- sMem.flags = 0; |
- sMem.db = 0; |
- rc = sqlite3VdbeMemFromBtree(pCrsr, 0, len, pC->isIndex, &sMem); |
- if( rc!=SQLITE_OK ){ |
- goto op_column_out; |
- } |
- zData = sMem.z; |
+ if( avail<offset ){ |
+ /* pC->aRow does not have to hold the entire row, but it does at least |
+ ** need to cover the header of the record. If pC->aRow does not contain |
+ ** the complete header, then set it to zero, forcing the header to be |
+ ** dynamically allocated. */ |
+ pC->aRow = 0; |
+ pC->szRow = 0; |
} |
- zEndHdr = (u8 *)&zData[len]; |
- zIdx = (u8 *)&zData[szHdr]; |
- /* Scan the header and use it to fill in the aType[] and aOffset[] |
- ** arrays. aType[i] will contain the type integer for the i-th |
- ** column and aOffset[i] will contain the offset from the beginning |
- ** of the record to the start of the data for the i-th column |
+ /* The following goto is an optimization. It can be omitted and |
+ ** everything will still work. But OP_Column is measurably faster |
+ ** by skipping the subsequent conditional, which is always true. |
*/ |
- for(i=0; i<nField; i++){ |
- if( zIdx<zEndHdr ){ |
- aOffset[i] = offset; |
- zIdx += getVarint32(zIdx, aType[i]); |
- szField = sqlite3VdbeSerialTypeLen(aType[i]); |
+ assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ |
+ goto op_column_read_header; |
+ } |
+ |
+ /* Make sure at least the first p2+1 entries of the header have been |
+ ** parsed and valid information is in aOffset[] and pC->aType[]. |
+ */ |
+ if( pC->nHdrParsed<=p2 ){ |
+ /* If there is more header available for parsing in the record, try |
+ ** to extract additional fields up through the p2+1-th field |
+ */ |
+ op_column_read_header: |
+ if( pC->iHdrOffset<aOffset[0] ){ |
+ /* Make sure zData points to enough of the record to cover the header. */ |
+ if( pC->aRow==0 ){ |
+ memset(&sMem, 0, sizeof(sMem)); |
+ rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], |
+ !pC->isTable, &sMem); |
+ if( rc!=SQLITE_OK ){ |
+ goto op_column_error; |
+ } |
+ zData = (u8*)sMem.z; |
+ }else{ |
+ zData = pC->aRow; |
+ } |
+ |
+ /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ |
+ i = pC->nHdrParsed; |
+ offset = aOffset[i]; |
+ zHdr = zData + pC->iHdrOffset; |
+ zEndHdr = zData + aOffset[0]; |
+ assert( i<=p2 && zHdr<zEndHdr ); |
+ do{ |
+ if( zHdr[0]<0x80 ){ |
+ t = zHdr[0]; |
+ zHdr++; |
+ }else{ |
+ zHdr += sqlite3GetVarint32(zHdr, &t); |
+ } |
+ pC->aType[i] = t; |
+ szField = sqlite3VdbeSerialTypeLen(t); |
offset += szField; |
if( offset<szField ){ /* True if offset overflows */ |
- zIdx = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */ |
+ zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */ |
break; |
} |
- }else{ |
- /* If i is less that nField, then there are less fields in this |
- ** record than SetNumColumns indicated there are columns in the |
- ** table. Set the offset for any extra columns not present in |
- ** the record to 0. This tells code below to store a NULL |
- ** instead of deserializing a value from the record. |
- */ |
- aOffset[i] = 0; |
+ i++; |
+ aOffset[i] = offset; |
+ }while( i<=p2 && zHdr<zEndHdr ); |
+ pC->nHdrParsed = i; |
+ pC->iHdrOffset = (u32)(zHdr - zData); |
+ if( pC->aRow==0 ){ |
+ sqlite3VdbeMemRelease(&sMem); |
+ sMem.flags = MEM_Null; |
+ } |
+ |
+ /* The record is corrupt if any of the following are true: |
+ ** (1) the bytes of the header extend past the declared header size |
+ ** (zHdr>zEndHdr) |
+ ** (2) the entire header was used but not all data was used |
+ ** (zHdr==zEndHdr && offset!=pC->payloadSize) |
+ ** (3) the end of the data extends beyond the end of the record. |
+ ** (offset > pC->payloadSize) |
+ */ |
+ if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize)) |
+ || (offset > pC->payloadSize) |
+ ){ |
+ rc = SQLITE_CORRUPT_BKPT; |
+ goto op_column_error; |
} |
} |
- sqlite3VdbeMemRelease(&sMem); |
- sMem.flags = MEM_Null; |
- |
- /* If we have read more header data than was contained in the header, |
- ** or if the end of the last field appears to be past the end of the |
- ** record, or if the end of the last field appears to be before the end |
- ** of the record (when all fields present), then we must be dealing |
- ** with a corrupt database. |
+ |
+ /* If after trying to extra new entries from the header, nHdrParsed is |
+ ** still not up to p2, that means that the record has fewer than p2 |
+ ** columns. So the result will be either the default value or a NULL. |
*/ |
- if( (zIdx > zEndHdr) || (offset > payloadSize) |
- || (zIdx==zEndHdr && offset!=payloadSize) ){ |
- rc = SQLITE_CORRUPT_BKPT; |
+ if( pC->nHdrParsed<=p2 ){ |
+ if( pOp->p4type==P4_MEM ){ |
+ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); |
+ }else{ |
+ sqlite3VdbeMemSetNull(pDest); |
+ } |
goto op_column_out; |
} |
} |
- /* Get the column information. If aOffset[p2] is non-zero, then |
- ** deserialize the value from the record. If aOffset[p2] is zero, |
- ** then there are not enough fields in the record to satisfy the |
- ** request. In this case, set the value NULL or to P4 if P4 is |
- ** a pointer to a Mem object. |
+ /* Extract the content for the p2+1-th column. Control can only |
+ ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are |
+ ** all valid. |
*/ |
- if( aOffset[p2] ){ |
- assert( rc==SQLITE_OK ); |
- if( zRec ){ |
- sqlite3VdbeMemReleaseExternal(pDest); |
- sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest); |
+ assert( p2<pC->nHdrParsed ); |
+ assert( rc==SQLITE_OK ); |
+ assert( sqlite3VdbeCheckMemInvariants(pDest) ); |
+ if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); |
+ t = pC->aType[p2]; |
+ if( pC->szRow>=aOffset[p2+1] ){ |
+ /* This is the common case where the desired content fits on the original |
+ ** page - where the content is not on an overflow page */ |
+ sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest); |
+ }else{ |
+ /* This branch happens only when content is on overflow pages */ |
+ if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 |
+ && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) |
+ || (len = sqlite3VdbeSerialTypeLen(t))==0 |
+ ){ |
+ /* Content is irrelevant for |
+ ** 1. the typeof() function, |
+ ** 2. the length(X) function if X is a blob, and |
+ ** 3. if the content length is zero. |
+ ** So we might as well use bogus content rather than reading |
+ ** content from disk. NULL will work for the value for strings |
+ ** and blobs and whatever is in the payloadSize64 variable |
+ ** will work for everything else. */ |
+ sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest); |
}else{ |
- len = sqlite3VdbeSerialTypeLen(aType[p2]); |
- sqlite3VdbeMemMove(&sMem, pDest); |
- rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex, &sMem); |
+ rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable, |
+ pDest); |
if( rc!=SQLITE_OK ){ |
- goto op_column_out; |
+ goto op_column_error; |
} |
- zData = sMem.z; |
- sqlite3VdbeSerialGet((u8*)zData, aType[p2], pDest); |
- } |
- pDest->enc = encoding; |
- }else{ |
- if( pOp->p4type==P4_MEM ){ |
- sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); |
- }else{ |
- assert( pDest->flags&MEM_Null ); |
+ sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); |
+ pDest->flags &= ~MEM_Ephem; |
} |
} |
- |
- /* If we dynamically allocated space to hold the data (in the |
- ** sqlite3VdbeMemFromBtree() call above) then transfer control of that |
- ** dynamically allocated space over to the pDest structure. |
- ** This prevents a memory copy. |
- */ |
- if( sMem.zMalloc ){ |
- assert( sMem.z==sMem.zMalloc ); |
- assert( !(pDest->flags & MEM_Dyn) ); |
- assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z ); |
- pDest->flags &= ~(MEM_Ephem|MEM_Static); |
- pDest->flags |= MEM_Term; |
- pDest->z = sMem.z; |
- pDest->zMalloc = sMem.zMalloc; |
- } |
- |
- rc = sqlite3VdbeMemMakeWriteable(pDest); |
+ pDest->enc = encoding; |
op_column_out: |
+ /* If the column value is an ephemeral string, go ahead and persist |
+ ** that string in case the cursor moves before the column value is |
+ ** used. The following code does the equivalent of Deephemeralize() |
+ ** but does it faster. */ |
+ if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){ |
+ fx = pDest->flags & (MEM_Str|MEM_Blob); |
+ assert( fx!=0 ); |
+ zData = (const u8*)pDest->z; |
+ len = pDest->n; |
+ if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem; |
+ memcpy(pDest->z, zData, len); |
+ pDest->z[len] = 0; |
+ pDest->z[len+1] = 0; |
+ pDest->flags = fx|MEM_Term; |
+ } |
+op_column_error: |
UPDATE_MAX_BLOBSIZE(pDest); |
REGISTER_TRACE(pOp->p3, pDest); |
break; |
} |
/* Opcode: Affinity P1 P2 * P4 * |
+** Synopsis: affinity(r[P1@P2]) |
** |
** Apply affinities to a range of P2 registers starting with P1. |
** |
@@ -2380,9 +2527,8 @@ case OP_Affinity: { |
assert( zAffinity[pOp->p2]==0 ); |
pIn1 = &aMem[pOp->p1]; |
while( (cAff = *(zAffinity++))!=0 ){ |
- assert( pIn1 <= &p->aMem[p->nMem] ); |
+ assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] ); |
assert( memIsValid(pIn1) ); |
- ExpandBlob(pIn1); |
applyAffinity(pIn1, cAff, encoding); |
pIn1++; |
} |
@@ -2390,6 +2536,7 @@ case OP_Affinity: { |
} |
/* Opcode: MakeRecord P1 P2 P3 P4 * |
+** Synopsis: r[P3]=mkrec(r[P1@P2]) |
** |
** Convert P2 registers beginning with P1 into the [record format] |
** use as a data record in a database table or as a key |
@@ -2418,7 +2565,8 @@ case OP_MakeRecord: { |
int nField; /* Number of fields in the record */ |
char *zAffinity; /* The affinity string for the record */ |
int file_format; /* File format to use for encoding */ |
- int i; /* Space used in zNewRecord[] */ |
+ int i; /* Space used in zNewRecord[] header */ |
+ int j; /* Space used in zNewRecord[] content */ |
int len; /* Length of a field */ |
/* Assuming the record contains N fields, the record format looks |
@@ -2429,7 +2577,7 @@ case OP_MakeRecord: { |
** ------------------------------------------------------------------------ |
** |
** Data(0) is taken from register P1. Data(1) comes from register P1+1 |
- ** and so froth. |
+ ** and so forth. |
** |
** Each type field is a varint representing the serial type of the |
** corresponding data element (see sqlite3VdbeSerialType()). The |
@@ -2441,7 +2589,7 @@ case OP_MakeRecord: { |
nZero = 0; /* Number of zero bytes at the end of the record */ |
nField = pOp->p1; |
zAffinity = pOp->p4.z; |
- assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem+1 ); |
+ assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 ); |
pData0 = &aMem[nField]; |
nField = pOp->p2; |
pLast = &pData0[nField-1]; |
@@ -2452,36 +2600,52 @@ case OP_MakeRecord: { |
pOut = &aMem[pOp->p3]; |
memAboutToChange(p, pOut); |
+ /* Apply the requested affinity to all inputs |
+ */ |
+ assert( pData0<=pLast ); |
+ if( zAffinity ){ |
+ pRec = pData0; |
+ do{ |
+ applyAffinity(pRec++, *(zAffinity++), encoding); |
+ assert( zAffinity[0]==0 || pRec<=pLast ); |
+ }while( zAffinity[0] ); |
+ } |
+ |
/* Loop through the elements that will make up the record to figure |
** out how much space is required for the new record. |
*/ |
- for(pRec=pData0; pRec<=pLast; pRec++){ |
+ pRec = pLast; |
+ do{ |
assert( memIsValid(pRec) ); |
- if( zAffinity ){ |
- applyAffinity(pRec, zAffinity[pRec-pData0], encoding); |
- } |
- if( pRec->flags&MEM_Zero && pRec->n>0 ){ |
- sqlite3VdbeMemExpandBlob(pRec); |
- } |
- serial_type = sqlite3VdbeSerialType(pRec, file_format); |
+ pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format); |
len = sqlite3VdbeSerialTypeLen(serial_type); |
- nData += len; |
- nHdr += sqlite3VarintLen(serial_type); |
if( pRec->flags & MEM_Zero ){ |
- /* Only pure zero-filled BLOBs can be input to this Opcode. |
- ** We do not allow blobs with a prefix and a zero-filled tail. */ |
- nZero += pRec->u.nZero; |
- }else if( len ){ |
- nZero = 0; |
+ if( nData ){ |
+ sqlite3VdbeMemExpandBlob(pRec); |
+ }else{ |
+ nZero += pRec->u.nZero; |
+ len -= pRec->u.nZero; |
+ } |
} |
- } |
+ nData += len; |
+ testcase( serial_type==127 ); |
+ testcase( serial_type==128 ); |
+ nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type); |
+ }while( (--pRec)>=pData0 ); |
/* Add the initial header varint and total the size */ |
- nHdr += nVarint = sqlite3VarintLen(nHdr); |
- if( nVarint<sqlite3VarintLen(nHdr) ){ |
- nHdr++; |
+ testcase( nHdr==126 ); |
+ testcase( nHdr==127 ); |
+ if( nHdr<=126 ){ |
+ /* The common case */ |
+ nHdr += 1; |
+ }else{ |
+ /* Rare case of a really large header */ |
+ nVarint = sqlite3VarintLen(nHdr); |
+ nHdr += nVarint; |
+ if( nVarint<sqlite3VarintLen(nHdr) ) nHdr++; |
} |
- nByte = nHdr+nData-nZero; |
+ nByte = nHdr+nData; |
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
goto too_big; |
} |
@@ -2489,28 +2653,29 @@ case OP_MakeRecord: { |
/* Make sure the output register has a buffer large enough to store |
** the new record. The output register (pOp->p3) is not allowed to |
** be one of the input registers (because the following call to |
- ** sqlite3VdbeMemGrow() could clobber the value before it is used). |
+ ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). |
*/ |
- if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){ |
+ if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ |
goto no_mem; |
} |
zNewRecord = (u8 *)pOut->z; |
/* Write the record */ |
i = putVarint32(zNewRecord, nHdr); |
- for(pRec=pData0; pRec<=pLast; pRec++){ |
- serial_type = sqlite3VdbeSerialType(pRec, file_format); |
- i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ |
- } |
- for(pRec=pData0; pRec<=pLast; pRec++){ /* serial data */ |
- i += sqlite3VdbeSerialPut(&zNewRecord[i], (int)(nByte-i), pRec,file_format); |
- } |
- assert( i==nByte ); |
- |
- assert( pOp->p3>0 && pOp->p3<=p->nMem ); |
+ j = nHdr; |
+ assert( pData0<=pLast ); |
+ pRec = pData0; |
+ do{ |
+ serial_type = pRec->uTemp; |
+ i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ |
+ j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ |
+ }while( (++pRec)<=pLast ); |
+ assert( i==nHdr ); |
+ assert( j==nByte ); |
+ |
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); |
pOut->n = (int)nByte; |
- pOut->flags = MEM_Blob | MEM_Dyn; |
- pOut->xDel = 0; |
+ pOut->flags = MEM_Blob; |
if( nZero ){ |
pOut->u.nZero = nZero; |
pOut->flags |= MEM_Zero; |
@@ -2522,6 +2687,7 @@ case OP_MakeRecord: { |
} |
/* Opcode: Count P1 P2 * * * |
+** Synopsis: r[P2]=count() |
** |
** Store the number of entries (an integer value) in the table or index |
** opened by cursor P1 in register P2 |
@@ -2532,11 +2698,9 @@ case OP_Count: { /* out2-prerelease */ |
BtCursor *pCrsr; |
pCrsr = p->apCsr[pOp->p1]->pCursor; |
- if( pCrsr ){ |
- rc = sqlite3BtreeCount(pCrsr, &nEntry); |
- }else{ |
- nEntry = 0; |
- } |
+ assert( pCrsr ); |
+ nEntry = 0; /* Not needed. Only used to silence a warning. */ |
+ rc = sqlite3BtreeCount(pCrsr, &nEntry); |
pOut->u.i = nEntry; |
break; |
} |
@@ -2568,9 +2732,10 @@ case OP_Savepoint: { |
assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK ); |
assert( db->pSavepoint || db->isTransactionSavepoint==0 ); |
assert( checkSavepointCount(db) ); |
+ assert( p->bIsReader ); |
if( p1==SAVEPOINT_BEGIN ){ |
- if( db->writeVdbeCnt>0 ){ |
+ if( db->nVdbeWrite>0 ){ |
/* A new savepoint cannot be created if there are active write |
** statements (i.e. open read/write incremental blob handles). |
*/ |
@@ -2580,6 +2745,17 @@ case OP_Savepoint: { |
}else{ |
nName = sqlite3Strlen30(zName); |
+#ifndef SQLITE_OMIT_VIRTUALTABLE |
+ /* This call is Ok even if this savepoint is actually a transaction |
+ ** savepoint (and therefore should not prompt xSavepoint()) callbacks. |
+ ** If this is a transaction savepoint being opened, it is guaranteed |
+ ** that the db->aVTrans[] array is empty. */ |
+ assert( db->autoCommit==0 || db->nVTrans==0 ); |
+ rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, |
+ db->nStatement+db->nSavepoint); |
+ if( rc!=SQLITE_OK ) goto abort_due_to_error; |
+#endif |
+ |
/* Create a new savepoint structure. */ |
pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1); |
if( pNew ){ |
@@ -2599,6 +2775,7 @@ case OP_Savepoint: { |
pNew->pNext = db->pSavepoint; |
db->pSavepoint = pNew; |
pNew->nDeferredCons = db->nDeferredCons; |
+ pNew->nDeferredImmCons = db->nDeferredImmCons; |
} |
} |
}else{ |
@@ -2616,16 +2793,12 @@ case OP_Savepoint: { |
if( !pSavepoint ){ |
sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", zName); |
rc = SQLITE_ERROR; |
- }else if( |
- db->writeVdbeCnt>0 || (p1==SAVEPOINT_ROLLBACK && db->activeVdbeCnt>1) |
- ){ |
+ }else if( db->nVdbeWrite>0 && p1==SAVEPOINT_RELEASE ){ |
/* It is not possible to release (commit) a savepoint if there are |
- ** active write statements. It is not possible to rollback a savepoint |
- ** if there are any active statements at all. |
+ ** active write statements. |
*/ |
sqlite3SetString(&p->zErrMsg, db, |
- "cannot %s savepoint - SQL statements in progress", |
- (p1==SAVEPOINT_ROLLBACK ? "rollback": "release") |
+ "cannot release savepoint - SQL statements in progress" |
); |
rc = SQLITE_BUSY; |
}else{ |
@@ -2649,16 +2822,28 @@ case OP_Savepoint: { |
db->isTransactionSavepoint = 0; |
rc = p->rc; |
}else{ |
+ int isSchemaChange; |
iSavepoint = db->nSavepoint - iSavepoint - 1; |
+ if( p1==SAVEPOINT_ROLLBACK ){ |
+ isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; |
+ for(ii=0; ii<db->nDb; ii++){ |
+ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, |
+ SQLITE_ABORT_ROLLBACK, |
+ isSchemaChange==0); |
+ if( rc!=SQLITE_OK ) goto abort_due_to_error; |
+ } |
+ }else{ |
+ isSchemaChange = 0; |
+ } |
for(ii=0; ii<db->nDb; ii++){ |
rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); |
if( rc!=SQLITE_OK ){ |
goto abort_due_to_error; |
} |
} |
- if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ |
+ if( isSchemaChange ){ |
sqlite3ExpirePreparedStatements(db); |
- sqlite3ResetInternalSchema(db, -1); |
+ sqlite3ResetAllSchemasOfConnection(db); |
db->flags = (db->flags | SQLITE_InternChanges); |
} |
} |
@@ -2685,6 +2870,12 @@ case OP_Savepoint: { |
} |
}else{ |
db->nDeferredCons = pSavepoint->nDeferredCons; |
+ db->nDeferredImmCons = pSavepoint->nDeferredImmCons; |
+ } |
+ |
+ if( !isTransaction ){ |
+ rc = sqlite3VtabSavepoint(db, p1, iSavepoint); |
+ if( rc!=SQLITE_OK ) goto abort_due_to_error; |
} |
} |
} |
@@ -2711,9 +2902,11 @@ case OP_AutoCommit: { |
turnOnAC = desiredAutoCommit && !db->autoCommit; |
assert( desiredAutoCommit==1 || desiredAutoCommit==0 ); |
assert( desiredAutoCommit==1 || iRollback==0 ); |
- assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */ |
+ assert( db->nVdbeActive>0 ); /* At least this one VM is active */ |
+ assert( p->bIsReader ); |
- if( turnOnAC && iRollback && db->activeVdbeCnt>1 ){ |
+#if 0 |
+ if( turnOnAC && iRollback && db->nVdbeActive>1 ){ |
/* If this instruction implements a ROLLBACK and other VMs are |
** still running, and a transaction is active, return an error indicating |
** that the other VMs must complete first. |
@@ -2721,7 +2914,9 @@ case OP_AutoCommit: { |
sqlite3SetString(&p->zErrMsg, db, "cannot rollback transaction - " |
"SQL statements in progress"); |
rc = SQLITE_BUSY; |
- }else if( turnOnAC && !iRollback && db->writeVdbeCnt>0 ){ |
+ }else |
+#endif |
+ 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. |
*/ |
@@ -2731,7 +2926,7 @@ case OP_AutoCommit: { |
}else if( desiredAutoCommit!=db->autoCommit ){ |
if( iRollback ){ |
assert( desiredAutoCommit==1 ); |
- sqlite3RollbackAll(db); |
+ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); |
db->autoCommit = 1; |
}else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ |
goto vdbe_return; |
@@ -2763,42 +2958,53 @@ case OP_AutoCommit: { |
break; |
} |
-/* Opcode: Transaction P1 P2 * * * |
+/* Opcode: Transaction P1 P2 P3 P4 P5 |
** |
-** Begin a transaction. The transaction ends when a Commit or Rollback |
-** opcode is encountered. Depending on the ON CONFLICT setting, the |
-** transaction might also be rolled back if an error is encountered. |
+** Begin a transaction on database P1 if a transaction is not already |
+** active. |
+** If P2 is non-zero, then a write-transaction is started, or if a |
+** read-transaction is already active, it is upgraded to a write-transaction. |
+** If P2 is zero, then a read-transaction is started. |
** |
** P1 is the index of the database file on which the transaction is |
** started. Index 0 is the main database file and index 1 is the |
** file used for temporary tables. Indices of 2 or more are used for |
** attached databases. |
** |
-** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is |
-** obtained on the database file when a write-transaction is started. No |
-** other process can start another write transaction while this transaction is |
-** underway. Starting a write transaction also creates a rollback journal. A |
-** write transaction must be started before any changes can be made to the |
-** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained |
-** on the file. |
-** |
** If a write-transaction is started and the Vdbe.usesStmtJournal flag is |
** true (this flag is set if the Vdbe may modify more than one row and may |
** throw an ABORT exception), a statement transaction may also be opened. |
** More specifically, a statement transaction is opened iff the database |
** connection is currently not in autocommit mode, or if there are other |
-** active statements. A statement transaction allows the affects of this |
+** active statements. A statement transaction allows the changes made by this |
** VDBE to be rolled back after an error without having to roll back the |
** entire transaction. If no error is encountered, the statement transaction |
** will automatically commit when the VDBE halts. |
** |
-** If P2 is zero, then a read-lock is obtained on the database file. |
+** If P5!=0 then this opcode also checks the schema cookie against P3 |
+** and the schema generation counter against P4. |
+** The cookie changes its value whenever the database schema changes. |
+** This operation is used to detect when that the cookie has changed |
+** and that the current process needs to reread the schema. If the schema |
+** cookie in P3 differs from the schema cookie in the database header or |
+** if the schema generation counter in P4 differs from the current |
+** generation counter, then an SQLITE_SCHEMA error is raised and execution |
+** halts. The sqlite3_step() wrapper function might then reprepare the |
+** statement and rerun it from the beginning. |
*/ |
case OP_Transaction: { |
Btree *pBt; |
+ int iMeta; |
+ int iGen; |
+ assert( p->bIsReader ); |
+ assert( p->readOnly==0 || pOp->p2==0 ); |
assert( pOp->p1>=0 && pOp->p1<db->nDb ); |
- assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, pOp->p1) ); |
+ if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){ |
+ rc = SQLITE_READONLY; |
+ goto abort_due_to_error; |
+ } |
pBt = db->aDb[pOp->p1].pBt; |
if( pBt ){ |
@@ -2813,7 +3019,7 @@ case OP_Transaction: { |
} |
if( pOp->p2 && p->usesStmtJournal |
- && (db->autoCommit==0 || db->activeVdbeCnt>1) |
+ && (db->autoCommit==0 || db->nVdbeRead>1) |
){ |
assert( sqlite3BtreeIsInTrans(pBt) ); |
if( p->iStatement==0 ){ |
@@ -2821,13 +3027,47 @@ case OP_Transaction: { |
db->nStatement++; |
p->iStatement = db->nSavepoint + db->nStatement; |
} |
- rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); |
+ |
+ rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1); |
+ if( rc==SQLITE_OK ){ |
+ rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); |
+ } |
/* Store the current value of the database handles deferred constraint |
** counter. If the statement transaction needs to be rolled back, |
** the value of this counter needs to be restored too. */ |
p->nStmtDefCons = db->nDeferredCons; |
+ p->nStmtDefImmCons = db->nDeferredImmCons; |
+ } |
+ |
+ /* Gather the schema version number for checking */ |
+ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); |
+ iGen = db->aDb[pOp->p1].pSchema->iGeneration; |
+ }else{ |
+ iGen = iMeta = 0; |
+ } |
+ assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); |
+ if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){ |
+ sqlite3DbFree(db, p->zErrMsg); |
+ p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); |
+ /* If the schema-cookie from the database file matches the cookie |
+ ** stored with the in-memory representation of the schema, do |
+ ** not reload the schema from the database file. |
+ ** |
+ ** If virtual-tables are in use, this is not just an optimization. |
+ ** Often, v-tables store their data in other SQLite tables, which |
+ ** are queried from within xNext() and other v-table methods using |
+ ** prepared queries. If such a query is out-of-date, we do not want to |
+ ** discard the database schema, as the user code implementing the |
+ ** v-table would have to be ready for the sqlite3_vtab structure itself |
+ ** to be invalidated whenever sqlite3_step() is called from within |
+ ** a v-table method. |
+ */ |
+ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ |
+ sqlite3ResetOneSchema(db, pOp->p1); |
} |
+ p->expired = 1; |
+ rc = SQLITE_SCHEMA; |
} |
break; |
} |
@@ -2849,12 +3089,13 @@ case OP_ReadCookie: { /* out2-prerelease */ |
int iDb; |
int iCookie; |
+ assert( p->bIsReader ); |
iDb = pOp->p1; |
iCookie = pOp->p3; |
assert( pOp->p3<SQLITE_N_BTREE_META ); |
assert( iDb>=0 && iDb<db->nDb ); |
assert( db->aDb[iDb].pBt!=0 ); |
- assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, iDb) ); |
sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); |
pOut->u.i = iMeta; |
@@ -2875,7 +3116,8 @@ case OP_SetCookie: { /* in3 */ |
Db *pDb; |
assert( pOp->p2<SQLITE_N_BTREE_META ); |
assert( pOp->p1>=0 && pOp->p1<db->nDb ); |
- assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, pOp->p1) ); |
+ assert( p->readOnly==0 ); |
pDb = &db->aDb[pOp->p1]; |
assert( pDb->pBt!=0 ); |
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); |
@@ -2900,66 +3142,8 @@ case OP_SetCookie: { /* in3 */ |
break; |
} |
-/* Opcode: VerifyCookie P1 P2 P3 * * |
-** |
-** Check the value of global database parameter number 0 (the |
-** schema version) and make sure it is equal to P2 and that the |
-** generation counter on the local schema parse equals P3. |
-** |
-** P1 is the database number which is 0 for the main database file |
-** and 1 for the file holding temporary tables and some higher number |
-** for auxiliary databases. |
-** |
-** The cookie changes its value whenever the database schema changes. |
-** This operation is used to detect when that the cookie has changed |
-** and that the current process needs to reread the schema. |
-** |
-** Either a transaction needs to have been started or an OP_Open needs |
-** to be executed (to establish a read lock) before this opcode is |
-** invoked. |
-*/ |
-case OP_VerifyCookie: { |
- int iMeta; |
- int iGen; |
- Btree *pBt; |
- |
- assert( pOp->p1>=0 && pOp->p1<db->nDb ); |
- assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); |
- assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); |
- pBt = db->aDb[pOp->p1].pBt; |
- if( pBt ){ |
- sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); |
- iGen = db->aDb[pOp->p1].pSchema->iGeneration; |
- }else{ |
- iGen = iMeta = 0; |
- } |
- if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){ |
- sqlite3DbFree(db, p->zErrMsg); |
- p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); |
- /* If the schema-cookie from the database file matches the cookie |
- ** stored with the in-memory representation of the schema, do |
- ** not reload the schema from the database file. |
- ** |
- ** If virtual-tables are in use, this is not just an optimization. |
- ** Often, v-tables store their data in other SQLite tables, which |
- ** are queried from within xNext() and other v-table methods using |
- ** prepared queries. If such a query is out-of-date, we do not want to |
- ** discard the database schema, as the user code implementing the |
- ** v-table would have to be ready for the sqlite3_vtab structure itself |
- ** to be invalidated whenever sqlite3_step() is called from within |
- ** a v-table method. |
- */ |
- if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ |
- sqlite3ResetInternalSchema(db, pOp->p1); |
- } |
- |
- p->expired = 1; |
- rc = SQLITE_SCHEMA; |
- } |
- break; |
-} |
- |
/* Opcode: OpenRead P1 P2 P3 P4 P5 |
+** Synopsis: root=P2 iDb=P3 |
** |
** Open a read-only cursor for the database table whose root page is |
** P2 in a database file. The database file is determined by P3. |
@@ -2987,9 +3171,24 @@ case OP_VerifyCookie: { |
** sequence of the index being opened. Otherwise, if P4 is an integer |
** value, it is set to the number of columns in the table. |
** |
-** See also OpenWrite. |
+** See also: OpenWrite, ReopenIdx |
+*/ |
+/* Opcode: ReopenIdx P1 P2 P3 P4 P5 |
+** Synopsis: root=P2 iDb=P3 |
+** |
+** The ReopenIdx opcode works exactly like ReadOpen except that it first |
+** checks to see if the cursor on P1 is already open with a root page |
+** number of P2 and if it is this opcode becomes a no-op. In other words, |
+** if the cursor is already open, do not reopen it. |
+** |
+** The ReopenIdx opcode may only be used with P5==0 and with P4 being |
+** a P4_KEYINFO object. Furthermore, the P3 value must be the same as |
+** every other ReopenIdx or OpenRead for the same cursor number. |
+** |
+** See the OpenRead opcode documentation for additional information. |
*/ |
/* Opcode: OpenWrite P1 P2 P3 P4 P5 |
+** Synopsis: root=P2 iDb=P3 |
** |
** Open a read/write cursor named P1 on the table or index whose root |
** page is P2. Or if P5!=0 use the content of register P2 to find the |
@@ -3008,6 +3207,19 @@ case OP_VerifyCookie: { |
** |
** See also OpenRead. |
*/ |
+case OP_ReopenIdx: { |
+ VdbeCursor *pCur; |
+ |
+ assert( pOp->p5==0 ); |
+ assert( pOp->p4type==P4_KEYINFO ); |
+ pCur = p->apCsr[pOp->p1]; |
+ if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ |
+ assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ |
+ break; |
+ } |
+ /* If the cursor is not currently open or is open on a different |
+ ** index, then fall through into OP_OpenRead to force a reopen */ |
+} |
case OP_OpenRead: |
case OP_OpenWrite: { |
int nField; |
@@ -3019,8 +3231,14 @@ case OP_OpenWrite: { |
VdbeCursor *pCur; |
Db *pDb; |
+ assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 ); |
+ assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 ); |
+ assert( p->bIsReader ); |
+ assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx |
+ || p->readOnly==0 ); |
+ |
if( p->expired ){ |
- rc = SQLITE_ABORT; |
+ rc = SQLITE_ABORT_ROLLBACK; |
break; |
} |
@@ -3029,7 +3247,7 @@ case OP_OpenWrite: { |
p2 = pOp->p2; |
iDb = pOp->p3; |
assert( iDb>=0 && iDb<db->nDb ); |
- assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, iDb) ); |
pDb = &db->aDb[iDb]; |
pX = pDb->pBt; |
assert( pX!=0 ); |
@@ -3042,9 +3260,9 @@ case OP_OpenWrite: { |
}else{ |
wrFlag = 0; |
} |
- if( pOp->p5 ){ |
+ if( pOp->p5 & OPFLAG_P2ISREG ){ |
assert( p2>0 ); |
- assert( p2<=p->nMem ); |
+ assert( p2<=(p->nMem-p->nCursor) ); |
pIn2 = &aMem[p2]; |
assert( memIsValid(pIn2) ); |
assert( (pIn2->flags & MEM_Int)!=0 ); |
@@ -3061,39 +3279,35 @@ case OP_OpenWrite: { |
} |
if( pOp->p4type==P4_KEYINFO ){ |
pKeyInfo = pOp->p4.pKeyInfo; |
- pKeyInfo->enc = ENC(p->db); |
- nField = pKeyInfo->nField+1; |
+ assert( pKeyInfo->enc==ENC(db) ); |
+ assert( pKeyInfo->db==db ); |
+ nField = pKeyInfo->nField+pKeyInfo->nXField; |
}else if( pOp->p4type==P4_INT32 ){ |
nField = pOp->p4.i; |
} |
assert( pOp->p1>=0 ); |
+ assert( nField>=0 ); |
+ testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ |
pCur = allocateCursor(p, pOp->p1, nField, iDb, 1); |
if( pCur==0 ) goto no_mem; |
pCur->nullRow = 1; |
pCur->isOrdered = 1; |
+ pCur->pgnoRoot = p2; |
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); |
pCur->pKeyInfo = pKeyInfo; |
+ assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); |
+ sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR)); |
- /* Since it performs no memory allocation or IO, the only values that |
- ** sqlite3BtreeCursor() may return are SQLITE_EMPTY and SQLITE_OK. |
- ** SQLITE_EMPTY is only returned when attempting to open the table |
- ** rooted at page 1 of a zero-byte database. */ |
- assert( rc==SQLITE_EMPTY || rc==SQLITE_OK ); |
- if( rc==SQLITE_EMPTY ){ |
- pCur->pCursor = 0; |
- rc = SQLITE_OK; |
- } |
- |
- /* Set the VdbeCursor.isTable and isIndex variables. Previous versions of |
+ /* Set the VdbeCursor.isTable variable. Previous versions of |
** SQLite used to check if the root-page flags were sane at this point |
** and report database corruption if they were not, but this check has |
** since moved into the btree layer. */ |
pCur->isTable = pOp->p4type!=P4_KEYINFO; |
- pCur->isIndex = !pCur->isTable; |
break; |
} |
-/* Opcode: OpenEphemeral P1 P2 * P4 * |
+/* Opcode: OpenEphemeral P1 P2 * P4 P5 |
+** Synopsis: nColumn=P2 |
** |
** Open a new cursor P1 to a transient table. |
** The cursor is always opened read/write even if |
@@ -3105,13 +3319,13 @@ case OP_OpenWrite: { |
** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure |
** that defines the format of keys in the index. |
** |
-** This opcode was once called OpenTemp. But that created |
-** confusion because the term "temp table", might refer either |
-** to a TEMP table at the SQL level, or to a table opened by |
-** this opcode. Then this opcode was call OpenVirtual. But |
-** that created confusion with the whole virtual-table idea. |
+** The P5 parameter can be a mask of the BTREE_* flags defined |
+** in btree.h. These flags control aspects of the operation of |
+** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are |
+** added automatically. |
*/ |
/* Opcode: OpenAutoindex P1 P2 * P4 * |
+** Synopsis: nColumn=P2 |
** |
** This opcode works the same as OP_OpenEphemeral. It has a |
** different name to distinguish its use. Tables created using |
@@ -3121,18 +3335,21 @@ case OP_OpenWrite: { |
case OP_OpenAutoindex: |
case OP_OpenEphemeral: { |
VdbeCursor *pCx; |
+ KeyInfo *pKeyInfo; |
+ |
static const int vfsFlags = |
SQLITE_OPEN_READWRITE | |
SQLITE_OPEN_CREATE | |
SQLITE_OPEN_EXCLUSIVE | |
SQLITE_OPEN_DELETEONCLOSE | |
SQLITE_OPEN_TRANSIENT_DB; |
- |
assert( pOp->p1>=0 ); |
+ assert( pOp->p2>=0 ); |
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); |
if( pCx==0 ) goto no_mem; |
pCx->nullRow = 1; |
- rc = sqlite3BtreeOpen(0, db, &pCx->pBt, |
+ pCx->isEphemeral = 1; |
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, |
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); |
if( rc==SQLITE_OK ){ |
rc = sqlite3BtreeBeginTrans(pCx->pBt, 1); |
@@ -3143,16 +3360,16 @@ case OP_OpenEphemeral: { |
** opening it. If a transient table is required, just use the |
** automatically created table with root-page 1 (an BLOB_INTKEY table). |
*/ |
- if( pOp->p4.pKeyInfo ){ |
+ if( (pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ |
int pgno; |
assert( pOp->p4type==P4_KEYINFO ); |
- rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY); |
+ rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); |
if( rc==SQLITE_OK ){ |
assert( pgno==MASTER_ROOT+1 ); |
- rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, |
- (KeyInfo*)pOp->p4.z, pCx->pCursor); |
- pCx->pKeyInfo = pOp->p4.pKeyInfo; |
- pCx->pKeyInfo->enc = ENC(p->db); |
+ assert( pKeyInfo->db==db ); |
+ assert( pKeyInfo->enc==ENC(db) ); |
+ pCx->pKeyInfo = pKeyInfo; |
+ rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, pKeyInfo, pCx->pCursor); |
} |
pCx->isTable = 0; |
}else{ |
@@ -3161,14 +3378,56 @@ case OP_OpenEphemeral: { |
} |
} |
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); |
- pCx->isIndex = !pCx->isTable; |
+ break; |
+} |
+ |
+/* Opcode: SorterOpen P1 P2 P3 P4 * |
+** |
+** This opcode works like OP_OpenEphemeral except that it opens |
+** a transient index that is specifically designed to sort large |
+** tables using an external merge-sort algorithm. |
+** |
+** If argument P3 is non-zero, then it indicates that the sorter may |
+** assume that a stable sort considering the first P3 fields of each |
+** key is sufficient to produce the required results. |
+*/ |
+case OP_SorterOpen: { |
+ VdbeCursor *pCx; |
+ |
+ assert( pOp->p1>=0 ); |
+ assert( pOp->p2>=0 ); |
+ pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); |
+ if( pCx==0 ) goto no_mem; |
+ pCx->pKeyInfo = pOp->p4.pKeyInfo; |
+ assert( pCx->pKeyInfo->db==db ); |
+ assert( pCx->pKeyInfo->enc==ENC(db) ); |
+ rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx); |
+ break; |
+} |
+ |
+/* Opcode: SequenceTest P1 P2 * * * |
+** Synopsis: if( cursor[P1].ctr++ ) pc = P2 |
+** |
+** P1 is a sorter cursor. If the sequence counter is currently zero, jump |
+** to P2. Regardless of whether or not the jump is taken, increment the |
+** the sequence value. |
+*/ |
+case OP_SequenceTest: { |
+ VdbeCursor *pC; |
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
+ pC = p->apCsr[pOp->p1]; |
+ assert( pC->pSorter ); |
+ if( (pC->seqCount++)==0 ){ |
+ pc = pOp->p2 - 1; |
+ } |
break; |
} |
/* Opcode: OpenPseudo P1 P2 P3 * * |
+** Synopsis: P3 columns in r[P2] |
** |
** Open a new cursor that points to a fake table that contains a single |
-** row of data. The content of that one row in the content of memory |
+** row of data. The content of that one row is the content of memory |
** register P2. In other words, cursor P1 becomes an alias for the |
** MEM_Blob content contained in register P2. |
** |
@@ -3184,12 +3443,13 @@ case OP_OpenPseudo: { |
VdbeCursor *pCx; |
assert( pOp->p1>=0 ); |
+ assert( pOp->p3>=0 ); |
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0); |
if( pCx==0 ) goto no_mem; |
pCx->nullRow = 1; |
pCx->pseudoTableReg = pOp->p2; |
pCx->isTable = 1; |
- pCx->isIndex = 0; |
+ assert( pOp->p5==0 ); |
break; |
} |
@@ -3205,7 +3465,8 @@ case OP_Close: { |
break; |
} |
-/* Opcode: SeekGe P1 P2 P3 P4 * |
+/* Opcode: SeekGE P1 P2 P3 P4 * |
+** Synopsis: key=r[P3@P4] |
** |
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), |
** use the value in register P3 as the key. If cursor P1 refers |
@@ -3216,9 +3477,14 @@ case OP_Close: { |
** is greater than or equal to the key value. If there are no records |
** greater than or equal to the key and P2 is not zero, then jump to P2. |
** |
-** See also: Found, NotFound, Distinct, SeekLt, SeekGt, SeekLe |
+** This opcode leaves the cursor configured to move in forward order, |
+** from the beginning toward the end. In other words, the cursor is |
+** configured to use Next, not Prev. |
+** |
+** See also: Found, NotFound, SeekLt, SeekGt, SeekLe |
*/ |
-/* Opcode: SeekGt P1 P2 P3 P4 * |
+/* Opcode: SeekGT P1 P2 P3 P4 * |
+** Synopsis: key=r[P3@P4] |
** |
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), |
** use the value in register P3 as a key. If cursor P1 refers |
@@ -3229,9 +3495,14 @@ case OP_Close: { |
** is greater than the key value. If there are no records greater than |
** the key and P2 is not zero, then jump to P2. |
** |
-** See also: Found, NotFound, Distinct, SeekLt, SeekGe, SeekLe |
+** This opcode leaves the cursor configured to move in forward order, |
+** from the beginning toward the end. In other words, the cursor is |
+** configured to use Next, not Prev. |
+** |
+** See also: Found, NotFound, SeekLt, SeekGe, SeekLe |
*/ |
-/* Opcode: SeekLt P1 P2 P3 P4 * |
+/* Opcode: SeekLT P1 P2 P3 P4 * |
+** Synopsis: key=r[P3@P4] |
** |
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), |
** use the value in register P3 as a key. If cursor P1 refers |
@@ -3242,9 +3513,14 @@ case OP_Close: { |
** is less than the key value. If there are no records less than |
** the key and P2 is not zero, then jump to P2. |
** |
-** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLe |
+** This opcode leaves the cursor configured to move in reverse order, |
+** from the end toward the beginning. In other words, the cursor is |
+** configured to use Prev, not Next. |
+** |
+** See also: Found, NotFound, SeekGt, SeekGe, SeekLe |
*/ |
-/* Opcode: SeekLe P1 P2 P3 P4 * |
+/* Opcode: SeekLE P1 P2 P3 P4 * |
+** Synopsis: key=r[P3@P4] |
** |
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), |
** use the value in register P3 as a key. If cursor P1 refers |
@@ -3255,12 +3531,16 @@ case OP_Close: { |
** is less than or equal to the key value. If there are no records |
** less than or equal to the key and P2 is not zero, then jump to P2. |
** |
-** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLt |
+** This opcode leaves the cursor configured to move in reverse order, |
+** from the end toward the beginning. In other words, the cursor is |
+** configured to use Prev, not Next. |
+** |
+** See also: Found, NotFound, SeekGt, SeekGe, SeekLt |
*/ |
-case OP_SeekLt: /* jump, in3 */ |
-case OP_SeekLe: /* jump, in3 */ |
-case OP_SeekGe: /* jump, in3 */ |
-case OP_SeekGt: { /* jump, in3 */ |
+case OP_SeekLT: /* jump, in3 */ |
+case OP_SeekLE: /* jump, in3 */ |
+case OP_SeekGE: /* jump, in3 */ |
+case OP_SeekGT: { /* jump, in3 */ |
int res; |
int oc; |
VdbeCursor *pC; |
@@ -3273,143 +3553,130 @@ case OP_SeekGt: { /* jump, in3 */ |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
assert( pC->pseudoTableReg==0 ); |
- assert( OP_SeekLe == OP_SeekLt+1 ); |
- assert( OP_SeekGe == OP_SeekLt+2 ); |
- assert( OP_SeekGt == OP_SeekLt+3 ); |
+ assert( OP_SeekLE == OP_SeekLT+1 ); |
+ assert( OP_SeekGE == OP_SeekLT+2 ); |
+ assert( OP_SeekGT == OP_SeekLT+3 ); |
assert( pC->isOrdered ); |
- if( pC->pCursor!=0 ){ |
- oc = pOp->opcode; |
- pC->nullRow = 0; |
- if( pC->isTable ){ |
- /* The input value in P3 might be of any type: integer, real, string, |
- ** blob, or NULL. But it needs to be an integer before we can do |
- ** the seek, so covert it. */ |
- pIn3 = &aMem[pOp->p3]; |
- applyNumericAffinity(pIn3); |
- iKey = sqlite3VdbeIntValue(pIn3); |
- pC->rowidIsValid = 0; |
- |
- /* If the P3 value could not be converted into an integer without |
- ** loss of information, then special processing is required... */ |
- if( (pIn3->flags & MEM_Int)==0 ){ |
- if( (pIn3->flags & MEM_Real)==0 ){ |
- /* If the P3 value cannot be converted into any kind of a number, |
- ** then the seek is not possible, so jump to P2 */ |
- pc = pOp->p2 - 1; |
- break; |
- } |
- /* If we reach this point, then the P3 value must be a floating |
- ** point number. */ |
- assert( (pIn3->flags & MEM_Real)!=0 ); |
- |
- if( iKey==SMALLEST_INT64 && (pIn3->r<(double)iKey || pIn3->r>0) ){ |
- /* The P3 value is too large in magnitude to be expressed as an |
- ** integer. */ |
- res = 1; |
- if( pIn3->r<0 ){ |
- if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt ); |
- rc = sqlite3BtreeFirst(pC->pCursor, &res); |
- if( rc!=SQLITE_OK ) goto abort_due_to_error; |
- } |
- }else{ |
- if( oc<=OP_SeekLe ){ assert( oc==OP_SeekLt || oc==OP_SeekLe ); |
- rc = sqlite3BtreeLast(pC->pCursor, &res); |
- if( rc!=SQLITE_OK ) goto abort_due_to_error; |
- } |
- } |
- if( res ){ |
- pc = pOp->p2 - 1; |
- } |
- break; |
- }else if( oc==OP_SeekLt || oc==OP_SeekGe ){ |
- /* Use the ceiling() function to convert real->int */ |
- if( pIn3->r > (double)iKey ) iKey++; |
- }else{ |
- /* Use the floor() function to convert real->int */ |
- assert( oc==OP_SeekLe || oc==OP_SeekGt ); |
- if( pIn3->r < (double)iKey ) iKey--; |
- } |
- } |
- rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res); |
- if( rc!=SQLITE_OK ){ |
- goto abort_due_to_error; |
- } |
- if( res==0 ){ |
- pC->rowidIsValid = 1; |
- pC->lastRowid = iKey; |
+ assert( pC->pCursor!=0 ); |
+ oc = pOp->opcode; |
+ pC->nullRow = 0; |
+#ifdef SQLITE_DEBUG |
+ pC->seekOp = pOp->opcode; |
+#endif |
+ if( pC->isTable ){ |
+ /* The input value in P3 might be of any type: integer, real, string, |
+ ** blob, or NULL. But it needs to be an integer before we can do |
+ ** the seek, so convert it. */ |
+ pIn3 = &aMem[pOp->p3]; |
+ if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ |
+ applyNumericAffinity(pIn3, 0); |
+ } |
+ iKey = sqlite3VdbeIntValue(pIn3); |
+ |
+ /* If the P3 value could not be converted into an integer without |
+ ** loss of information, then special processing is required... */ |
+ if( (pIn3->flags & MEM_Int)==0 ){ |
+ if( (pIn3->flags & MEM_Real)==0 ){ |
+ /* If the P3 value cannot be converted into any kind of a number, |
+ ** then the seek is not possible, so jump to P2 */ |
+ pc = pOp->p2 - 1; VdbeBranchTaken(1,2); |
+ break; |
} |
- }else{ |
- nField = pOp->p4.i; |
- assert( pOp->p4type==P4_INT32 ); |
- assert( nField>0 ); |
- r.pKeyInfo = pC->pKeyInfo; |
- r.nField = (u16)nField; |
- |
- /* The next line of code computes as follows, only faster: |
- ** if( oc==OP_SeekGt || oc==OP_SeekLe ){ |
- ** r.flags = UNPACKED_INCRKEY; |
- ** }else{ |
- ** r.flags = 0; |
- ** } |
+ |
+ /* If the approximation iKey is larger than the actual real search |
+ ** term, substitute >= for > and < for <=. e.g. if the search term |
+ ** is 4.9 and the integer approximation 5: |
+ ** |
+ ** (x > 4.9) -> (x >= 5) |
+ ** (x <= 4.9) -> (x < 5) |
*/ |
- r.flags = (u16)(UNPACKED_INCRKEY * (1 & (oc - OP_SeekLt))); |
- assert( oc!=OP_SeekGt || r.flags==UNPACKED_INCRKEY ); |
- assert( oc!=OP_SeekLe || r.flags==UNPACKED_INCRKEY ); |
- assert( oc!=OP_SeekGe || r.flags==0 ); |
- assert( oc!=OP_SeekLt || r.flags==0 ); |
+ if( pIn3->u.r<(double)iKey ){ |
+ assert( OP_SeekGE==(OP_SeekGT-1) ); |
+ assert( OP_SeekLT==(OP_SeekLE-1) ); |
+ assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); |
+ if( (oc & 0x0001)==(OP_SeekGT & 0x0001) ) oc--; |
+ } |
+ |
+ /* If the approximation iKey is smaller than the actual real search |
+ ** term, substitute <= for < and > for >=. */ |
+ else if( pIn3->u.r>(double)iKey ){ |
+ assert( OP_SeekLE==(OP_SeekLT+1) ); |
+ assert( OP_SeekGT==(OP_SeekGE+1) ); |
+ assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); |
+ if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; |
+ } |
+ } |
+ rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res); |
+ pC->movetoTarget = iKey; /* Used by OP_Delete */ |
+ if( rc!=SQLITE_OK ){ |
+ goto abort_due_to_error; |
+ } |
+ }else{ |
+ nField = pOp->p4.i; |
+ assert( pOp->p4type==P4_INT32 ); |
+ assert( nField>0 ); |
+ r.pKeyInfo = pC->pKeyInfo; |
+ r.nField = (u16)nField; |
+ |
+ /* The next line of code computes as follows, only faster: |
+ ** if( oc==OP_SeekGT || oc==OP_SeekLE ){ |
+ ** r.default_rc = -1; |
+ ** }else{ |
+ ** r.default_rc = +1; |
+ ** } |
+ */ |
+ r.default_rc = ((1 & (oc - OP_SeekLT)) ? -1 : +1); |
+ assert( oc!=OP_SeekGT || r.default_rc==-1 ); |
+ assert( oc!=OP_SeekLE || r.default_rc==-1 ); |
+ assert( oc!=OP_SeekGE || r.default_rc==+1 ); |
+ assert( oc!=OP_SeekLT || r.default_rc==+1 ); |
- r.aMem = &aMem[pOp->p3]; |
+ r.aMem = &aMem[pOp->p3]; |
#ifdef SQLITE_DEBUG |
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } |
+ { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } |
#endif |
- ExpandBlob(r.aMem); |
- rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res); |
- if( rc!=SQLITE_OK ){ |
- goto abort_due_to_error; |
- } |
- pC->rowidIsValid = 0; |
+ ExpandBlob(r.aMem); |
+ rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res); |
+ if( rc!=SQLITE_OK ){ |
+ goto abort_due_to_error; |
} |
- pC->deferredMoveto = 0; |
- pC->cacheStatus = CACHE_STALE; |
+ } |
+ pC->deferredMoveto = 0; |
+ pC->cacheStatus = CACHE_STALE; |
#ifdef SQLITE_TEST |
- sqlite3_search_count++; |
+ sqlite3_search_count++; |
#endif |
- if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt ); |
- if( res<0 || (res==0 && oc==OP_SeekGt) ){ |
- rc = sqlite3BtreeNext(pC->pCursor, &res); |
- if( rc!=SQLITE_OK ) goto abort_due_to_error; |
- pC->rowidIsValid = 0; |
- }else{ |
- res = 0; |
- } |
+ if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT ); |
+ if( res<0 || (res==0 && oc==OP_SeekGT) ){ |
+ res = 0; |
+ rc = sqlite3BtreeNext(pC->pCursor, &res); |
+ if( rc!=SQLITE_OK ) goto abort_due_to_error; |
}else{ |
- assert( oc==OP_SeekLt || oc==OP_SeekLe ); |
- if( res>0 || (res==0 && oc==OP_SeekLt) ){ |
- rc = sqlite3BtreePrevious(pC->pCursor, &res); |
- if( rc!=SQLITE_OK ) goto abort_due_to_error; |
- pC->rowidIsValid = 0; |
- }else{ |
- /* res might be negative because the table is empty. Check to |
- ** see if this is the case. |
- */ |
- res = sqlite3BtreeEof(pC->pCursor); |
- } |
- } |
- assert( pOp->p2>0 ); |
- if( res ){ |
- pc = pOp->p2 - 1; |
+ res = 0; |
} |
}else{ |
- /* This happens when attempting to open the sqlite3_master table |
- ** for read access returns SQLITE_EMPTY. In this case always |
- ** take the jump (since there are no records in the table). |
- */ |
+ assert( oc==OP_SeekLT || oc==OP_SeekLE ); |
+ if( res>0 || (res==0 && oc==OP_SeekLT) ){ |
+ res = 0; |
+ rc = sqlite3BtreePrevious(pC->pCursor, &res); |
+ if( rc!=SQLITE_OK ) goto abort_due_to_error; |
+ }else{ |
+ /* res might be negative because the table is empty. Check to |
+ ** see if this is the case. |
+ */ |
+ res = sqlite3BtreeEof(pC->pCursor); |
+ } |
+ } |
+ assert( pOp->p2>0 ); |
+ VdbeBranchTaken(res!=0,2); |
+ if( res ){ |
pc = pOp->p2 - 1; |
} |
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. |
@@ -3424,19 +3691,18 @@ case OP_Seek: { /* in2 */ |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
- if( ALWAYS(pC->pCursor!=0) ){ |
- assert( pC->isTable ); |
- pC->nullRow = 0; |
- pIn2 = &aMem[pOp->p2]; |
- pC->movetoTarget = sqlite3VdbeIntValue(pIn2); |
- pC->rowidIsValid = 0; |
- pC->deferredMoveto = 1; |
- } |
+ assert( pC->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 * |
+** Synopsis: key=r[P3@P4] |
** |
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If |
** P4>0 then register P3 is the first of P4 registers that form an unpacked |
@@ -3445,8 +3711,15 @@ case OP_Seek: { /* in2 */ |
** Cursor P1 is on an index btree. If the record identified by P3 and P4 |
** is a prefix of any entry in P1 then a jump is made to P2 and |
** P1 is left pointing at the matching entry. |
+** |
+** This operation leaves the cursor in a state where it can be |
+** advanced in the forward direction. The Next instruction will work, |
+** but not the Prev instruction. |
+** |
+** See also: NotFound, NoConflict, NotExists. SeekGe |
*/ |
/* Opcode: NotFound P1 P2 P3 P4 * |
+** Synopsis: key=r[P3@P4] |
** |
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If |
** P4>0 then register P3 is the first of P4 registers that form an unpacked |
@@ -3458,168 +3731,134 @@ case OP_Seek: { /* in2 */ |
** falls through to the next instruction and P1 is left pointing at the |
** matching entry. |
** |
-** See also: Found, NotExists, IsUnique |
+** This operation leaves the cursor in a state where it cannot be |
+** advanced in either direction. In other words, the Next and Prev |
+** opcodes do not work after this operation. |
+** |
+** See also: Found, NotExists, NoConflict |
+*/ |
+/* Opcode: NoConflict P1 P2 P3 P4 * |
+** Synopsis: key=r[P3@P4] |
+** |
+** If P4==0 then register P3 holds a blob constructed by MakeRecord. If |
+** P4>0 then register P3 is the first of P4 registers that form an unpacked |
+** record. |
+** |
+** Cursor P1 is on an index btree. If the record identified by P3 and P4 |
+** contains any NULL value, jump immediately to P2. If all terms of the |
+** record are not-NULL then a check is done to determine if any row in the |
+** P1 index btree has a matching key prefix. If there are no matches, jump |
+** immediately to P2. If there is a match, fall through and leave the P1 |
+** cursor pointing to the matching row. |
+** |
+** This opcode is similar to OP_NotFound with the exceptions that the |
+** branch is always taken if any part of the search key input is NULL. |
+** |
+** This operation leaves the cursor in a state where it cannot be |
+** advanced in either direction. In other words, the Next and Prev |
+** opcodes do not work after this operation. |
+** |
+** See also: NotFound, Found, NotExists |
*/ |
+case OP_NoConflict: /* jump, in3 */ |
case OP_NotFound: /* jump, in3 */ |
case OP_Found: { /* jump, in3 */ |
int alreadyExists; |
+ int ii; |
VdbeCursor *pC; |
int res; |
+ char *pFree; |
UnpackedRecord *pIdxKey; |
UnpackedRecord r; |
- char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7]; |
+ char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*4 + 7]; |
#ifdef SQLITE_TEST |
- sqlite3_found_count++; |
+ if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++; |
#endif |
- alreadyExists = 0; |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
assert( pOp->p4type==P4_INT32 ); |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
+#ifdef SQLITE_DEBUG |
+ pC->seekOp = pOp->opcode; |
+#endif |
pIn3 = &aMem[pOp->p3]; |
- if( ALWAYS(pC->pCursor!=0) ){ |
- |
- assert( pC->isTable==0 ); |
- if( pOp->p4.i>0 ){ |
- r.pKeyInfo = pC->pKeyInfo; |
- r.nField = (u16)pOp->p4.i; |
- r.aMem = pIn3; |
+ assert( pC->pCursor!=0 ); |
+ assert( pC->isTable==0 ); |
+ pFree = 0; /* Not needed. Only used to suppress a compiler warning. */ |
+ if( pOp->p4.i>0 ){ |
+ r.pKeyInfo = pC->pKeyInfo; |
+ r.nField = (u16)pOp->p4.i; |
+ r.aMem = pIn3; |
+ for(ii=0; ii<r.nField; ii++){ |
+ assert( memIsValid(&r.aMem[ii]) ); |
+ ExpandBlob(&r.aMem[ii]); |
#ifdef SQLITE_DEBUG |
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } |
+ if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]); |
#endif |
- r.flags = UNPACKED_PREFIX_MATCH; |
- pIdxKey = &r; |
- }else{ |
- assert( pIn3->flags & MEM_Blob ); |
- assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ |
- pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, |
- aTempRec, sizeof(aTempRec)); |
- if( pIdxKey==0 ){ |
- goto no_mem; |
- } |
- pIdxKey->flags |= UNPACKED_PREFIX_MATCH; |
} |
- rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res); |
- if( pOp->p4.i==0 ){ |
- sqlite3VdbeDeleteUnpackedRecord(pIdxKey); |
- } |
- if( rc!=SQLITE_OK ){ |
- break; |
+ pIdxKey = &r; |
+ }else{ |
+ pIdxKey = sqlite3VdbeAllocUnpackedRecord( |
+ pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree |
+ ); |
+ if( pIdxKey==0 ) goto no_mem; |
+ assert( pIn3->flags & MEM_Blob ); |
+ assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ |
+ sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); |
+ } |
+ pIdxKey->default_rc = 0; |
+ if( pOp->opcode==OP_NoConflict ){ |
+ /* For the OP_NoConflict opcode, take the jump if any of the |
+ ** input fields are NULL, since any key with a NULL will not |
+ ** conflict */ |
+ for(ii=0; ii<r.nField; ii++){ |
+ if( r.aMem[ii].flags & MEM_Null ){ |
+ pc = pOp->p2 - 1; VdbeBranchTaken(1,2); |
+ break; |
+ } |
} |
- alreadyExists = (res==0); |
- pC->deferredMoveto = 0; |
- pC->cacheStatus = CACHE_STALE; |
} |
- if( pOp->opcode==OP_Found ){ |
- if( alreadyExists ) pc = pOp->p2 - 1; |
- }else{ |
- if( !alreadyExists ) pc = pOp->p2 - 1; |
+ rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res); |
+ if( pOp->p4.i==0 ){ |
+ sqlite3DbFree(db, pFree); |
} |
- break; |
-} |
- |
-/* Opcode: IsUnique P1 P2 P3 P4 * |
-** |
-** Cursor P1 is open on an index b-tree - that is to say, a btree which |
-** no data and where the key are records generated by OP_MakeRecord with |
-** the list field being the integer ROWID of the entry that the index |
-** entry refers to. |
-** |
-** The P3 register contains an integer record number. Call this record |
-** number R. Register P4 is the first in a set of N contiguous registers |
-** that make up an unpacked index key that can be used with cursor P1. |
-** The value of N can be inferred from the cursor. N includes the rowid |
-** value appended to the end of the index record. This rowid value may |
-** or may not be the same as R. |
-** |
-** If any of the N registers beginning with register P4 contains a NULL |
-** value, jump immediately to P2. |
-** |
-** Otherwise, this instruction checks if cursor P1 contains an entry |
-** where the first (N-1) fields match but the rowid value at the end |
-** of the index entry is not R. If there is no such entry, control jumps |
-** to instruction P2. Otherwise, the rowid of the conflicting index |
-** entry is copied to register P3 and control falls through to the next |
-** instruction. |
-** |
-** See also: NotFound, NotExists, Found |
-*/ |
-case OP_IsUnique: { /* jump, in3 */ |
- u16 ii; |
- VdbeCursor *pCx; |
- BtCursor *pCrsr; |
- u16 nField; |
- Mem *aMx; |
- UnpackedRecord r; /* B-Tree index search key */ |
- i64 R; /* Rowid stored in register P3 */ |
- |
- pIn3 = &aMem[pOp->p3]; |
- aMx = &aMem[pOp->p4.i]; |
- /* Assert that the values of parameters P1 and P4 are in range. */ |
- assert( pOp->p4type==P4_INT32 ); |
- assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem ); |
- assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
- |
- /* Find the index cursor. */ |
- pCx = p->apCsr[pOp->p1]; |
- assert( pCx->deferredMoveto==0 ); |
- pCx->seekResult = 0; |
- pCx->cacheStatus = CACHE_STALE; |
- pCrsr = pCx->pCursor; |
- |
- /* If any of the values are NULL, take the jump. */ |
- nField = pCx->pKeyInfo->nField; |
- for(ii=0; ii<nField; ii++){ |
- if( aMx[ii].flags & MEM_Null ){ |
- pc = pOp->p2 - 1; |
- pCrsr = 0; |
- break; |
- } |
+ if( rc!=SQLITE_OK ){ |
+ break; |
} |
- assert( (aMx[nField].flags & MEM_Null)==0 ); |
- |
- if( pCrsr!=0 ){ |
- /* Populate the index search key. */ |
- r.pKeyInfo = pCx->pKeyInfo; |
- r.nField = nField + 1; |
- r.flags = UNPACKED_PREFIX_SEARCH; |
- r.aMem = aMx; |
-#ifdef SQLITE_DEBUG |
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } |
-#endif |
- |
- /* Extract the value of R from register P3. */ |
- sqlite3VdbeMemIntegerify(pIn3); |
- R = pIn3->u.i; |
- |
- /* Search the B-Tree index. If no conflicting record is found, jump |
- ** to P2. Otherwise, copy the rowid of the conflicting record to |
- ** register P3 and fall through to the next instruction. */ |
- rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &pCx->seekResult); |
- if( (r.flags & UNPACKED_PREFIX_SEARCH) || r.rowid==R ){ |
- pc = pOp->p2 - 1; |
- }else{ |
- pIn3->u.i = r.rowid; |
- } |
+ pC->seekResult = res; |
+ alreadyExists = (res==0); |
+ pC->nullRow = 1-alreadyExists; |
+ pC->deferredMoveto = 0; |
+ pC->cacheStatus = CACHE_STALE; |
+ if( pOp->opcode==OP_Found ){ |
+ VdbeBranchTaken(alreadyExists!=0,2); |
+ if( alreadyExists ) pc = pOp->p2 - 1; |
+ }else{ |
+ VdbeBranchTaken(alreadyExists==0,2); |
+ if( !alreadyExists ) pc = pOp->p2 - 1; |
} |
break; |
} |
/* Opcode: NotExists P1 P2 P3 * * |
+** Synopsis: intkey=r[P3] |
** |
-** Use the content of register P3 as a integer key. If a record |
-** with that key does not exist in table of P1, then jump to P2. |
-** If the record does exist, then fall through. The cursor is left |
-** pointing to the record if it exists. |
+** P1 is the index of a cursor open on an SQL table btree (with integer |
+** keys). P3 is an integer rowid. If P1 does not contain a record with |
+** rowid P3 then jump immediately to P2. If P1 does contain a record |
+** with rowid P3 then leave the cursor pointing at that record and fall |
+** through to the next instruction. |
** |
-** The difference between this operation and NotFound is that this |
-** operation assumes the key is an integer and that P1 is a table whereas |
-** NotFound assumes key is a blob constructed from MakeRecord and |
-** P1 is an index. |
+** The OP_NotFound opcode performs the same operation on index btrees |
+** (with arbitrary multi-value keys). |
** |
-** See also: Found, NotFound, IsUnique |
+** This opcode leaves the cursor in a state where it cannot be advanced |
+** in either direction. In other words, the Next and Prev opcodes will |
+** not work following this opcode. |
+** |
+** See also: Found, NotFound, NoConflict |
*/ |
case OP_NotExists: { /* jump, in3 */ |
VdbeCursor *pC; |
@@ -3632,35 +3871,30 @@ case OP_NotExists: { /* jump, in3 */ |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
+#ifdef SQLITE_DEBUG |
+ pC->seekOp = 0; |
+#endif |
assert( pC->isTable ); |
assert( pC->pseudoTableReg==0 ); |
pCrsr = pC->pCursor; |
- if( pCrsr!=0 ){ |
- res = 0; |
- iKey = pIn3->u.i; |
- rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); |
- pC->lastRowid = pIn3->u.i; |
- pC->rowidIsValid = res==0 ?1:0; |
- pC->nullRow = 0; |
- pC->cacheStatus = CACHE_STALE; |
- pC->deferredMoveto = 0; |
- if( res!=0 ){ |
- pc = pOp->p2 - 1; |
- assert( pC->rowidIsValid==0 ); |
- } |
- pC->seekResult = res; |
- }else{ |
- /* This happens when an attempt to open a read cursor on the |
- ** sqlite_master table returns SQLITE_EMPTY. |
- */ |
+ assert( pCrsr!=0 ); |
+ res = 0; |
+ iKey = pIn3->u.i; |
+ rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); |
+ pC->movetoTarget = iKey; /* Used by OP_Delete */ |
+ pC->nullRow = 0; |
+ pC->cacheStatus = CACHE_STALE; |
+ pC->deferredMoveto = 0; |
+ VdbeBranchTaken(res!=0,2); |
+ if( res!=0 ){ |
pc = pOp->p2 - 1; |
- assert( pC->rowidIsValid==0 ); |
- pC->seekResult = 0; |
} |
+ pC->seekResult = res; |
break; |
} |
/* Opcode: Sequence P1 P2 * * * |
+** Synopsis: r[P2]=cursor[P1].ctr++ |
** |
** Find the next available sequence number for cursor P1. |
** Write the sequence number into register P2. |
@@ -3676,6 +3910,7 @@ case OP_Sequence: { /* out2-prerelease */ |
/* Opcode: NewRowid P1 P2 P3 * * |
+** Synopsis: r[P2]=rowid |
** |
** Get a new integer record number (a.k.a "rowid") used as the key to a table. |
** The record number is not previously used as a key in the database |
@@ -3685,7 +3920,7 @@ case OP_Sequence: { /* out2-prerelease */ |
** If P3>0 then P3 is a register in the root frame of this VDBE that holds |
** the largest previously generated record number. No new record numbers are |
** allowed to be less than this value. When this value reaches its maximum, |
-** a SQLITE_FULL error is generated. The P3 register is updated with the ' |
+** an SQLITE_FULL error is generated. The P3 register is updated with the ' |
** generated record number. This P3 mechanism is used to help implement the |
** AUTOINCREMENT feature. |
*/ |
@@ -3731,59 +3966,54 @@ case OP_NewRowid: { /* out2-prerelease */ |
#endif |
if( !pC->useRandomRowid ){ |
- v = sqlite3BtreeGetCachedRowid(pC->pCursor); |
- if( v==0 ){ |
- rc = sqlite3BtreeLast(pC->pCursor, &res); |
- if( rc!=SQLITE_OK ){ |
- goto abort_due_to_error; |
- } |
- if( res ){ |
- v = 1; /* IMP: R-61914-48074 */ |
+ rc = sqlite3BtreeLast(pC->pCursor, &res); |
+ if( rc!=SQLITE_OK ){ |
+ goto abort_due_to_error; |
+ } |
+ if( res ){ |
+ v = 1; /* IMP: R-61914-48074 */ |
+ }else{ |
+ assert( sqlite3BtreeCursorIsValid(pC->pCursor) ); |
+ rc = sqlite3BtreeKeySize(pC->pCursor, &v); |
+ assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ |
+ if( v>=MAX_ROWID ){ |
+ pC->useRandomRowid = 1; |
}else{ |
- assert( sqlite3BtreeCursorIsValid(pC->pCursor) ); |
- rc = sqlite3BtreeKeySize(pC->pCursor, &v); |
- assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ |
- if( v==MAX_ROWID ){ |
- pC->useRandomRowid = 1; |
- }else{ |
- v++; /* IMP: R-29538-34987 */ |
- } |
+ v++; /* IMP: R-29538-34987 */ |
} |
} |
+ } |
#ifndef SQLITE_OMIT_AUTOINCREMENT |
- if( pOp->p3 ){ |
+ if( pOp->p3 ){ |
+ /* Assert that P3 is a valid memory cell. */ |
+ assert( pOp->p3>0 ); |
+ if( p->pFrame ){ |
+ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); |
/* Assert that P3 is a valid memory cell. */ |
- assert( pOp->p3>0 ); |
- if( p->pFrame ){ |
- for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); |
- /* Assert that P3 is a valid memory cell. */ |
- assert( pOp->p3<=pFrame->nMem ); |
- pMem = &pFrame->aMem[pOp->p3]; |
- }else{ |
- /* Assert that P3 is a valid memory cell. */ |
- assert( pOp->p3<=p->nMem ); |
- pMem = &aMem[pOp->p3]; |
- memAboutToChange(p, pMem); |
- } |
- assert( memIsValid(pMem) ); |
- |
- REGISTER_TRACE(pOp->p3, pMem); |
- sqlite3VdbeMemIntegerify(pMem); |
- assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ |
- if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ |
- rc = SQLITE_FULL; /* IMP: R-12275-61338 */ |
- goto abort_due_to_error; |
- } |
- if( v<pMem->u.i+1 ){ |
- v = pMem->u.i + 1; |
- } |
- pMem->u.i = v; |
+ assert( pOp->p3<=pFrame->nMem ); |
+ pMem = &pFrame->aMem[pOp->p3]; |
+ }else{ |
+ /* Assert that P3 is a valid memory cell. */ |
+ assert( pOp->p3<=(p->nMem-p->nCursor) ); |
+ pMem = &aMem[pOp->p3]; |
+ memAboutToChange(p, pMem); |
} |
-#endif |
+ assert( memIsValid(pMem) ); |
- sqlite3BtreeSetCachedRowid(pC->pCursor, v<MAX_ROWID ? v+1 : 0); |
+ REGISTER_TRACE(pOp->p3, pMem); |
+ sqlite3VdbeMemIntegerify(pMem); |
+ assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ |
+ if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ |
+ rc = SQLITE_FULL; /* IMP: R-12275-61338 */ |
+ goto abort_due_to_error; |
+ } |
+ if( v<pMem->u.i+1 ){ |
+ v = pMem->u.i + 1; |
+ } |
+ pMem->u.i = v; |
} |
+#endif |
if( pC->useRandomRowid ){ |
/* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the |
** largest possible integer (9223372036854775807) then the database |
@@ -3791,32 +4021,20 @@ case OP_NewRowid: { /* out2-prerelease */ |
** it finds one that is not previously used. */ |
assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is |
** an AUTOINCREMENT table. */ |
- /* on the first attempt, simply do one more than previous */ |
- v = db->lastRowid; |
- v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ |
- v++; /* ensure non-zero */ |
cnt = 0; |
- while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v, |
+ do{ |
+ sqlite3_randomness(sizeof(v), &v); |
+ v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ |
+ }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v, |
0, &res))==SQLITE_OK) |
&& (res==0) |
- && (++cnt<100)){ |
- /* collision - try another random rowid */ |
- sqlite3_randomness(sizeof(v), &v); |
- if( cnt<5 ){ |
- /* try "small" random rowids for the initial attempts */ |
- v &= 0xffffff; |
- }else{ |
- v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ |
- } |
- v++; /* ensure non-zero */ |
- } |
+ && (++cnt<100)); |
if( rc==SQLITE_OK && res==0 ){ |
rc = SQLITE_FULL; /* IMP: R-38219-53002 */ |
goto abort_due_to_error; |
} |
assert( v>0 ); /* EV: R-40812-03570 */ |
} |
- pC->rowidIsValid = 0; |
pC->deferredMoveto = 0; |
pC->cacheStatus = CACHE_STALE; |
} |
@@ -3825,6 +4043,7 @@ case OP_NewRowid: { /* out2-prerelease */ |
} |
/* Opcode: Insert P1 P2 P3 P4 P5 |
+** Synopsis: intkey=r[P3] data=r[P2] |
** |
** 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 |
@@ -3864,6 +4083,7 @@ case OP_NewRowid: { /* out2-prerelease */ |
** for indices is OP_IdxInsert. |
*/ |
/* Opcode: InsertInt P1 P2 P3 P4 P5 |
+** Synopsis: intkey=P3 data=r[P2] |
** |
** This works exactly like OP_Insert except that the key is the |
** integer value P3, not the value of the integer stored in register P3. |
@@ -3902,7 +4122,7 @@ case OP_InsertInt: { |
} |
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; |
- if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey; |
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey; |
if( pData->flags & MEM_Null ){ |
pData->z = 0; |
pData->n = 0; |
@@ -3915,12 +4135,10 @@ case OP_InsertInt: { |
}else{ |
nZero = 0; |
} |
- sqlite3BtreeSetCachedRowid(pC->pCursor, 0); |
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, |
pData->z, pData->n, nZero, |
- pOp->p5 & OPFLAG_APPEND, seekResult |
+ (pOp->p5 & OPFLAG_APPEND)!=0, seekResult |
); |
- pC->rowidIsValid = 0; |
pC->deferredMoveto = 0; |
pC->cacheStatus = CACHE_STALE; |
@@ -3943,7 +4161,7 @@ case OP_InsertInt: { |
** 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. Hence it is OK to delete |
-** a record from within an Next loop. |
+** a record from within a Next loop. |
** |
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is |
** incremented (otherwise not). |
@@ -3957,44 +4175,32 @@ case OP_InsertInt: { |
** using OP_NotFound prior to invoking this opcode. |
*/ |
case OP_Delete: { |
- i64 iKey; |
VdbeCursor *pC; |
- iKey = 0; |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */ |
- |
- /* If the update-hook will be invoked, set iKey to the rowid of the |
- ** row being deleted. |
- */ |
- if( db->xUpdateCallback && pOp->p4.z ){ |
- assert( pC->isTable ); |
- assert( pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */ |
- iKey = pC->lastRowid; |
- } |
- |
- /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or |
- ** OP_Column on the same table without any intervening operations that |
- ** might move or invalidate the cursor. Hence cursor pC is always pointing |
- ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation |
- ** below is always a no-op and cannot fail. We will run it anyhow, though, |
- ** to guard against future changes to the code generator. |
- **/ |
assert( pC->deferredMoveto==0 ); |
- rc = sqlite3VdbeCursorMoveto(pC); |
- if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; |
- sqlite3BtreeSetCachedRowid(pC->pCursor, 0); |
+#ifdef SQLITE_DEBUG |
+ /* The seek operation that positioned the cursor prior to OP_Delete will |
+ ** have also set the pC->movetoTarget field to the rowid of the row that |
+ ** is being deleted */ |
+ if( pOp->p4.z && pC->isTable ){ |
+ i64 iKey = 0; |
+ sqlite3BtreeKeySize(pC->pCursor, &iKey); |
+ assert( pC->movetoTarget==iKey ); |
+ } |
+#endif |
+ |
rc = sqlite3BtreeDelete(pC->pCursor); |
pC->cacheStatus = CACHE_STALE; |
/* Invoke the update-hook if required. */ |
- if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ |
- const char *zDb = db->aDb[pC->iDb].zName; |
- const char *zTbl = pOp->p4.z; |
- db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey); |
+ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){ |
+ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, |
+ db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget); |
assert( pC->iDb>=0 ); |
} |
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; |
@@ -4013,7 +4219,67 @@ case OP_ResetCount: { |
break; |
} |
+/* Opcode: SorterCompare P1 P2 P3 P4 |
+** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 |
+** |
+** P1 is a sorter cursor. This instruction compares a prefix of the |
+** record blob in register P3 against a prefix of the entry that |
+** the sorter cursor currently points to. Only the first P4 fields |
+** of r[P3] and the sorter record are compared. |
+** |
+** If either P3 or the sorter contains a NULL in one of their significant |
+** fields (not counting the P4 fields at the end which are ignored) then |
+** the comparison is assumed to be equal. |
+** |
+** Fall through to next instruction if the two records compare equal to |
+** each other. Jump to P2 if they are different. |
+*/ |
+case OP_SorterCompare: { |
+ VdbeCursor *pC; |
+ int res; |
+ int nKeyCol; |
+ |
+ pC = p->apCsr[pOp->p1]; |
+ assert( isSorter(pC) ); |
+ assert( pOp->p4type==P4_INT32 ); |
+ pIn3 = &aMem[pOp->p3]; |
+ nKeyCol = pOp->p4.i; |
+ res = 0; |
+ rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); |
+ VdbeBranchTaken(res!=0,2); |
+ if( res ){ |
+ pc = pOp->p2-1; |
+ } |
+ break; |
+}; |
+ |
+/* Opcode: SorterData P1 P2 P3 * * |
+** Synopsis: r[P2]=data |
+** |
+** Write into register P2 the current sorter data for sorter cursor P1. |
+** Then clear the column header cache on cursor P3. |
+** |
+** This opcode is normally use to move a record out of the sorter and into |
+** a register that is the source for a pseudo-table cursor created using |
+** OpenPseudo. That pseudo-table cursor is the one that is identified by |
+** parameter P3. Clearing the P3 column cache as part of this opcode saves |
+** us from having to issue a separate NullRow instruction to clear that cache. |
+*/ |
+case OP_SorterData: { |
+ VdbeCursor *pC; |
+ |
+ pOut = &aMem[pOp->p2]; |
+ pC = p->apCsr[pOp->p1]; |
+ assert( isSorter(pC) ); |
+ rc = sqlite3VdbeSorterRowkey(pC, pOut); |
+ assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); |
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
+ p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; |
+ break; |
+} |
+ |
/* Opcode: RowData P1 P2 * * * |
+** Synopsis: r[P2]=data |
** |
** Write into register P2 the complete row data for cursor P1. |
** There is no interpretation of the data. |
@@ -4024,10 +4290,11 @@ case OP_ResetCount: { |
** of a real table, not a pseudo-table. |
*/ |
/* Opcode: RowKey P1 P2 * * * |
+** Synopsis: r[P2]=key |
** |
** Write into register P2 the complete row key for cursor P1. |
** There is no interpretation of the data. |
-** The key is copied onto the P3 register exactly as |
+** The key is copied onto the P2 register exactly as |
** it is found in the database file. |
** |
** If the P1 cursor must be pointing to a valid row (not a NULL row) |
@@ -4046,55 +4313,63 @@ case OP_RowData: { |
/* Note that RowKey and RowData are really exactly the same instruction */ |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
pC = p->apCsr[pOp->p1]; |
- assert( pC->isTable || pOp->opcode==OP_RowKey ); |
- assert( pC->isIndex || pOp->opcode==OP_RowData ); |
+ assert( isSorter(pC)==0 ); |
+ assert( pC->isTable || pOp->opcode!=OP_RowData ); |
+ assert( pC->isTable==0 || pOp->opcode==OP_RowData ); |
assert( pC!=0 ); |
assert( pC->nullRow==0 ); |
assert( pC->pseudoTableReg==0 ); |
assert( pC->pCursor!=0 ); |
pCrsr = pC->pCursor; |
- assert( sqlite3BtreeCursorIsValid(pCrsr) ); |
/* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or |
** OP_Rewind/Op_Next with no intervening instructions that might invalidate |
- ** the cursor. Hence the following sqlite3VdbeCursorMoveto() call is always |
- ** a no-op and can never fail. But we leave it in place as a safety. |
+ ** the cursor. If this where not the case, on of the following assert()s |
+ ** would fail. Should this ever change (because of changes in the code |
+ ** generator) then the fix would be to insert a call to |
+ ** sqlite3VdbeCursorMoveto(). |
*/ |
assert( pC->deferredMoveto==0 ); |
+ assert( sqlite3BtreeCursorIsValid(pCrsr) ); |
+#if 0 /* Not required due to the previous to assert() statements */ |
rc = sqlite3VdbeCursorMoveto(pC); |
- if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; |
+ if( rc!=SQLITE_OK ) goto abort_due_to_error; |
+#endif |
- if( pC->isIndex ){ |
+ if( pC->isTable==0 ){ |
assert( !pC->isTable ); |
- rc = sqlite3BtreeKeySize(pCrsr, &n64); |
+ VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64); |
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ |
if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
goto too_big; |
} |
n = (u32)n64; |
}else{ |
- rc = sqlite3BtreeDataSize(pCrsr, &n); |
+ VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n); |
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ |
if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
goto too_big; |
} |
} |
- if( sqlite3VdbeMemGrow(pOut, n, 0) ){ |
+ testcase( n==0 ); |
+ if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){ |
goto no_mem; |
} |
pOut->n = n; |
MemSetTypeFlag(pOut, MEM_Blob); |
- if( pC->isIndex ){ |
+ if( pC->isTable==0 ){ |
rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z); |
}else{ |
rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z); |
} |
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */ |
UPDATE_MAX_BLOBSIZE(pOut); |
+ REGISTER_TRACE(pOp->p2, pOut); |
break; |
} |
/* Opcode: Rowid P1 P2 * * * |
+** Synopsis: r[P2]=rowid |
** |
** Store in register P2 an integer which is the key of the table entry that |
** P1 is currently point to. |
@@ -4112,7 +4387,7 @@ 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 ); |
+ assert( pC->pseudoTableReg==0 || pC->nullRow ); |
if( pC->nullRow ){ |
pOut->flags = MEM_Null; |
break; |
@@ -4124,18 +4399,18 @@ case OP_Rowid: { /* out2-prerelease */ |
pModule = pVtab->pModule; |
assert( pModule->xRowid ); |
rc = pModule->xRowid(pC->pVtabCursor, &v); |
- importVtabErrMsg(p, pVtab); |
+ sqlite3VtabImportErrmsg(p, pVtab); |
#endif /* SQLITE_OMIT_VIRTUALTABLE */ |
}else{ |
assert( pC->pCursor!=0 ); |
- rc = sqlite3VdbeCursorMoveto(pC); |
+ rc = sqlite3VdbeCursorRestore(pC); |
if( rc ) goto abort_due_to_error; |
- if( pC->rowidIsValid ){ |
- v = pC->lastRowid; |
- }else{ |
- rc = sqlite3BtreeKeySize(pC->pCursor, &v); |
- assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */ |
+ if( pC->nullRow ){ |
+ pOut->flags = MEM_Null; |
+ break; |
} |
+ rc = sqlite3BtreeKeySize(pC->pCursor, &v); |
+ assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ |
} |
pOut->u.i = v; |
break; |
@@ -4154,7 +4429,7 @@ case OP_NullRow: { |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
pC->nullRow = 1; |
- pC->rowidIsValid = 0; |
+ pC->cacheStatus = CACHE_STALE; |
if( pC->pCursor ){ |
sqlite3BtreeClearCursor(pC->pCursor); |
} |
@@ -4163,11 +4438,15 @@ case OP_NullRow: { |
/* Opcode: Last P1 P2 * * * |
** |
-** The next use of the Rowid or Column or Next instruction for P1 |
+** The next use of the Rowid or Column or Prev instruction for P1 |
** will refer to the last entry in the database table or index. |
** If the table or index is empty and P2>0, then jump immediately to P2. |
** If P2 is 0 or if the table or index is not empty, fall through |
** to the following instruction. |
+** |
+** This opcode leaves the cursor configured to move in reverse order, |
+** from the end toward the beginning. In other words, the cursor is |
+** configured to use Prev, not Next. |
*/ |
case OP_Last: { /* jump */ |
VdbeCursor *pC; |
@@ -4178,17 +4457,18 @@ case OP_Last: { /* jump */ |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
pCrsr = pC->pCursor; |
- if( pCrsr==0 ){ |
- res = 1; |
- }else{ |
- rc = sqlite3BtreeLast(pCrsr, &res); |
- } |
+ res = 0; |
+ assert( pCrsr!=0 ); |
+ rc = sqlite3BtreeLast(pCrsr, &res); |
pC->nullRow = (u8)res; |
pC->deferredMoveto = 0; |
- pC->rowidIsValid = 0; |
pC->cacheStatus = CACHE_STALE; |
- if( pOp->p2>0 && res ){ |
- pc = pOp->p2 - 1; |
+#ifdef SQLITE_DEBUG |
+ pC->seekOp = OP_Last; |
+#endif |
+ if( pOp->p2>0 ){ |
+ VdbeBranchTaken(res!=0,2); |
+ if( res ) pc = pOp->p2 - 1; |
} |
break; |
} |
@@ -4206,12 +4486,13 @@ case OP_Last: { /* jump */ |
** regression tests can determine whether or not the optimizer is |
** correctly optimizing out sorts. |
*/ |
+case OP_SorterSort: /* jump */ |
case OP_Sort: { /* jump */ |
#ifdef SQLITE_TEST |
sqlite3_sort_count++; |
sqlite3_search_count--; |
#endif |
- p->aCounter[SQLITE_STMTSTATUS_SORT-1]++; |
+ p->aCounter[SQLITE_STMTSTATUS_SORT]++; |
/* Fall through into OP_Rewind */ |
} |
/* Opcode: Rewind P1 P2 * * * |
@@ -4221,6 +4502,10 @@ case OP_Sort: { /* jump */ |
** If the table or index is empty and P2>0, then jump immediately to P2. |
** If P2 is 0 or if the table or index is not empty, fall through |
** to the following instruction. |
+** |
+** This opcode leaves the cursor configured to move in forward order, |
+** from the beginning toward the end. In other words, the cursor is |
+** configured to use Next, not Prev. |
*/ |
case OP_Rewind: { /* jump */ |
VdbeCursor *pC; |
@@ -4230,95 +4515,169 @@ case OP_Rewind: { /* jump */ |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
+ assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); |
res = 1; |
- if( (pCrsr = pC->pCursor)!=0 ){ |
+#ifdef SQLITE_DEBUG |
+ pC->seekOp = OP_Rewind; |
+#endif |
+ if( isSorter(pC) ){ |
+ rc = sqlite3VdbeSorterRewind(pC, &res); |
+ }else{ |
+ pCrsr = pC->pCursor; |
+ assert( pCrsr ); |
rc = sqlite3BtreeFirst(pCrsr, &res); |
- pC->atFirst = res==0 ?1:0; |
pC->deferredMoveto = 0; |
pC->cacheStatus = CACHE_STALE; |
- pC->rowidIsValid = 0; |
} |
pC->nullRow = (u8)res; |
assert( pOp->p2>0 && pOp->p2<p->nOp ); |
+ VdbeBranchTaken(res!=0,2); |
if( res ){ |
pc = pOp->p2 - 1; |
} |
break; |
} |
-/* Opcode: Next P1 P2 * * P5 |
+/* Opcode: Next P1 P2 P3 P4 P5 |
** |
** Advance cursor P1 so that it points to the next key/data pair in its |
** table or index. If there are no more key/value pairs then fall through |
** to the following instruction. But if the cursor advance was successful, |
** jump immediately to P2. |
** |
-** The P1 cursor must be for a real table, not a pseudo-table. |
+** The Next opcode is only valid following an SeekGT, SeekGE, or |
+** OP_Rewind opcode used to position the cursor. Next is not allowed |
+** to follow SeekLT, SeekLE, or OP_Last. |
+** |
+** The P1 cursor must be for a real table, not a pseudo-table. P1 must have |
+** been opened prior to this opcode or the program will segfault. |
+** |
+** The P3 value is a hint to the btree implementation. If P3==1, that |
+** means P1 is an SQL index and that this instruction could have been |
+** omitted if that index had been unique. P3 is usually 0. P3 is |
+** always either 0 or 1. |
+** |
+** P4 is always of type P4_ADVANCE. The function pointer points to |
+** sqlite3BtreeNext(). |
** |
** If P5 is positive and the jump is taken, then event counter |
** number P5-1 in the prepared statement is incremented. |
** |
-** See also: Prev |
+** See also: Prev, NextIfOpen |
+*/ |
+/* Opcode: NextIfOpen P1 P2 P3 P4 P5 |
+** |
+** This opcode works just like Next except that if cursor P1 is not |
+** open it behaves a no-op. |
*/ |
-/* Opcode: Prev P1 P2 * * P5 |
+/* Opcode: Prev P1 P2 P3 P4 P5 |
** |
** Back up cursor P1 so that it points to the previous key/data pair in its |
** table or index. If there is no previous key/value pairs then fall through |
** to the following instruction. But if the cursor backup was successful, |
** jump immediately to P2. |
** |
-** The P1 cursor must be for a real table, not a pseudo-table. |
+** |
+** The Prev opcode is only valid following an SeekLT, SeekLE, or |
+** OP_Last opcode used to position the cursor. Prev is not allowed |
+** to follow SeekGT, SeekGE, or OP_Rewind. |
+** |
+** The P1 cursor must be for a real table, not a pseudo-table. If P1 is |
+** not open then the behavior is undefined. |
+** |
+** The P3 value is a hint to the btree implementation. If P3==1, that |
+** means P1 is an SQL index and that this instruction could have been |
+** omitted if that index had been unique. P3 is usually 0. P3 is |
+** always either 0 or 1. |
+** |
+** P4 is always of type P4_ADVANCE. The function pointer points to |
+** sqlite3BtreePrevious(). |
** |
** If P5 is positive and the jump is taken, then event counter |
** number P5-1 in the prepared statement is incremented. |
*/ |
-case OP_Prev: /* jump */ |
-case OP_Next: { /* jump */ |
+/* Opcode: PrevIfOpen P1 P2 P3 P4 P5 |
+** |
+** This opcode works just like Prev except that if cursor P1 is not |
+** open it behaves a no-op. |
+*/ |
+case OP_SorterNext: { /* jump */ |
VdbeCursor *pC; |
- BtCursor *pCrsr; |
int res; |
- CHECK_FOR_INTERRUPT; |
+ pC = p->apCsr[pOp->p1]; |
+ assert( isSorter(pC) ); |
+ res = 0; |
+ rc = sqlite3VdbeSorterNext(db, pC, &res); |
+ goto next_tail; |
+case OP_PrevIfOpen: /* jump */ |
+case OP_NextIfOpen: /* jump */ |
+ if( p->apCsr[pOp->p1]==0 ) break; |
+ /* Fall through */ |
+case OP_Prev: /* jump */ |
+case OP_Next: /* jump */ |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
- assert( pOp->p5<=ArraySize(p->aCounter) ); |
+ assert( pOp->p5<ArraySize(p->aCounter) ); |
pC = p->apCsr[pOp->p1]; |
- if( pC==0 ){ |
- break; /* See ticket #2273 */ |
- } |
- pCrsr = pC->pCursor; |
- if( pCrsr==0 ){ |
- pC->nullRow = 1; |
- break; |
- } |
- res = 1; |
+ res = pOp->p3; |
+ assert( pC!=0 ); |
assert( pC->deferredMoveto==0 ); |
- rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : |
- sqlite3BtreePrevious(pCrsr, &res); |
- pC->nullRow = (u8)res; |
+ assert( pC->pCursor ); |
+ assert( res==0 || (res==1 && pC->isTable==0) ); |
+ testcase( res==1 ); |
+ assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); |
+ assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); |
+ assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); |
+ assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious); |
+ |
+ /* The Next opcode is only used after SeekGT, SeekGE, and Rewind. |
+ ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ |
+ assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen |
+ || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE |
+ || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found); |
+ assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen |
+ || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE |
+ || pC->seekOp==OP_Last ); |
+ |
+ rc = pOp->p4.xAdvance(pC->pCursor, &res); |
+next_tail: |
pC->cacheStatus = CACHE_STALE; |
+ VdbeBranchTaken(res==0,2); |
if( res==0 ){ |
+ pC->nullRow = 0; |
pc = pOp->p2 - 1; |
- if( pOp->p5 ) p->aCounter[pOp->p5-1]++; |
+ p->aCounter[pOp->p5]++; |
#ifdef SQLITE_TEST |
sqlite3_search_count++; |
#endif |
+ }else{ |
+ pC->nullRow = 1; |
} |
- pC->rowidIsValid = 0; |
- break; |
+ goto check_for_interrupt; |
} |
/* Opcode: IdxInsert P1 P2 P3 * P5 |
+** Synopsis: key=r[P2] |
** |
-** Register P2 holds a SQL index key made using the |
+** Register P2 holds an SQL index key made using the |
** MakeRecord instructions. This opcode writes that key |
** into the index P1. Data for the entry is nil. |
** |
** P3 is a flag that provides a hint to the b-tree layer that this |
** insert is likely to be an append. |
** |
+** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is |
+** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear, |
+** then the change counter is unchanged. |
+** |
+** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have |
+** just done a seek to the spot where the new entry is to be inserted. |
+** This flag avoids doing an extra seek. |
+** |
** This instruction only works for indices. The equivalent instruction |
** for tables is OP_Insert. |
*/ |
+case OP_SorterInsert: /* in2 */ |
case OP_IdxInsert: { /* in2 */ |
VdbeCursor *pC; |
BtCursor *pCrsr; |
@@ -4328,18 +4687,23 @@ case OP_IdxInsert: { /* in2 */ |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
+ assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) ); |
pIn2 = &aMem[pOp->p2]; |
assert( pIn2->flags & MEM_Blob ); |
pCrsr = pC->pCursor; |
- if( ALWAYS(pCrsr!=0) ){ |
- assert( pC->isTable==0 ); |
- rc = ExpandBlob(pIn2); |
- if( rc==SQLITE_OK ){ |
+ if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; |
+ assert( pCrsr!=0 ); |
+ assert( pC->isTable==0 ); |
+ rc = ExpandBlob(pIn2); |
+ if( rc==SQLITE_OK ){ |
+ if( isSorter(pC) ){ |
+ rc = sqlite3VdbeSorterWrite(pC, pIn2); |
+ }else{ |
nKey = pIn2->n; |
zKey = pIn2->z; |
rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p3, |
((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) |
- ); |
+ ); |
assert( pC->deferredMoveto==0 ); |
pC->cacheStatus = CACHE_STALE; |
} |
@@ -4348,6 +4712,7 @@ case OP_IdxInsert: { /* in2 */ |
} |
/* Opcode: IdxDelete P1 P2 P3 * * |
+** Synopsis: key=r[P2@P3] |
** |
** The content of P3 registers starting at register P2 form |
** an unpacked index key. This opcode removes that entry from the |
@@ -4360,30 +4725,31 @@ case OP_IdxDelete: { |
UnpackedRecord r; |
assert( pOp->p3>0 ); |
- assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 ); |
+ assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 ); |
assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
pCrsr = pC->pCursor; |
- if( ALWAYS(pCrsr!=0) ){ |
- r.pKeyInfo = pC->pKeyInfo; |
- r.nField = (u16)pOp->p3; |
- r.flags = 0; |
- r.aMem = &aMem[pOp->p2]; |
+ assert( pCrsr!=0 ); |
+ assert( pOp->p5==0 ); |
+ r.pKeyInfo = pC->pKeyInfo; |
+ 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]) ); } |
+ { 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); |
- } |
- assert( pC->deferredMoveto==0 ); |
- pC->cacheStatus = CACHE_STALE; |
+ rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res); |
+ if( rc==SQLITE_OK && res==0 ){ |
+ rc = sqlite3BtreeDelete(pCrsr); |
} |
+ assert( pC->deferredMoveto==0 ); |
+ pC->cacheStatus = CACHE_STALE; |
break; |
} |
/* Opcode: IdxRowid P1 P2 * * * |
+** Synopsis: r[P2]=rowid |
** |
** Write into register P2 an integer which is the last entry in the record at |
** the end of the index key pointed to by cursor P1. This integer should be |
@@ -4400,52 +4766,78 @@ case OP_IdxRowid: { /* out2-prerelease */ |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
pCrsr = pC->pCursor; |
+ assert( pCrsr!=0 ); |
pOut->flags = MEM_Null; |
- if( ALWAYS(pCrsr!=0) ){ |
- rc = sqlite3VdbeCursorMoveto(pC); |
- if( NEVER(rc) ) goto abort_due_to_error; |
- assert( pC->deferredMoveto==0 ); |
- assert( pC->isTable==0 ); |
- if( !pC->nullRow ){ |
- rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid); |
- if( rc!=SQLITE_OK ){ |
- goto abort_due_to_error; |
- } |
- pOut->u.i = rowid; |
- pOut->flags = MEM_Int; |
+ assert( pC->isTable==0 ); |
+ assert( pC->deferredMoveto==0 ); |
+ |
+ /* 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); |
+ 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); |
+ if( rc!=SQLITE_OK ){ |
+ goto abort_due_to_error; |
} |
+ pOut->u.i = rowid; |
+ pOut->flags = MEM_Int; |
} |
break; |
} |
/* Opcode: IdxGE P1 P2 P3 P4 P5 |
+** Synopsis: key=r[P3@P4] |
** |
** The P4 register values beginning with P3 form an unpacked index |
-** key that omits the ROWID. Compare this key value against the index |
-** that P1 is currently pointing to, ignoring the ROWID on the P1 index. |
+** key that omits the PRIMARY KEY. Compare this key value against the index |
+** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID |
+** fields at the end. |
** |
** If the P1 index entry is greater than or equal to the key value |
** then jump to P2. Otherwise fall through to the next instruction. |
+*/ |
+/* Opcode: IdxGT P1 P2 P3 P4 P5 |
+** Synopsis: key=r[P3@P4] |
+** |
+** The P4 register values beginning with P3 form an unpacked index |
+** key that omits the PRIMARY KEY. Compare this key value against the index |
+** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID |
+** fields at the end. |
** |
-** If P5 is non-zero then the key value is increased by an epsilon |
-** prior to the comparison. This make the opcode work like IdxGT except |
-** that if the key from register P3 is a prefix of the key in the cursor, |
-** the result is false whereas it would be true with IdxGT. |
+** If the P1 index entry is greater than the key value |
+** then jump to P2. Otherwise fall through to the next instruction. |
*/ |
/* Opcode: IdxLT P1 P2 P3 P4 P5 |
+** Synopsis: key=r[P3@P4] |
** |
** The P4 register values beginning with P3 form an unpacked index |
-** key that omits the ROWID. Compare this key value against the index |
-** that P1 is currently pointing to, ignoring the ROWID on the P1 index. |
+** key that omits the PRIMARY KEY or ROWID. Compare this key value against |
+** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or |
+** ROWID on the P1 index. |
** |
** If the P1 index entry is less than the key value then jump to P2. |
** Otherwise fall through to the next instruction. |
+*/ |
+/* Opcode: IdxLE P1 P2 P3 P4 P5 |
+** Synopsis: key=r[P3@P4] |
+** |
+** The P4 register values beginning with P3 form an unpacked index |
+** key that omits the PRIMARY KEY or ROWID. Compare this key value against |
+** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or |
+** ROWID on the P1 index. |
** |
-** If P5 is non-zero then the key value is increased by an epsilon prior |
-** to the comparison. This makes the opcode work like IdxLE. |
+** If the P1 index entry is less than or equal to the key value then jump |
+** to P2. Otherwise fall through to the next instruction. |
*/ |
+case OP_IdxLE: /* jump */ |
+case OP_IdxGT: /* jump */ |
case OP_IdxLT: /* jump */ |
-case OP_IdxGE: { /* jump */ |
+case OP_IdxGE: { /* jump */ |
VdbeCursor *pC; |
int res; |
UnpackedRecord r; |
@@ -4454,31 +4846,36 @@ case OP_IdxGE: { /* jump */ |
pC = p->apCsr[pOp->p1]; |
assert( pC!=0 ); |
assert( pC->isOrdered ); |
- if( ALWAYS(pC->pCursor!=0) ){ |
- assert( pC->deferredMoveto==0 ); |
- assert( pOp->p5==0 || pOp->p5==1 ); |
- assert( pOp->p4type==P4_INT32 ); |
- r.pKeyInfo = pC->pKeyInfo; |
- r.nField = (u16)pOp->p4.i; |
- if( pOp->p5 ){ |
- r.flags = UNPACKED_INCRKEY | UNPACKED_IGNORE_ROWID; |
- }else{ |
- r.flags = UNPACKED_IGNORE_ROWID; |
- } |
- r.aMem = &aMem[pOp->p3]; |
+ assert( pC->pCursor!=0); |
+ assert( pC->deferredMoveto==0 ); |
+ assert( pOp->p5==0 || pOp->p5==1 ); |
+ assert( pOp->p4type==P4_INT32 ); |
+ r.pKeyInfo = pC->pKeyInfo; |
+ r.nField = (u16)pOp->p4.i; |
+ if( pOp->opcode<OP_IdxLT ){ |
+ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxGT ); |
+ r.default_rc = -1; |
+ }else{ |
+ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT ); |
+ r.default_rc = 0; |
+ } |
+ r.aMem = &aMem[pOp->p3]; |
#ifdef SQLITE_DEBUG |
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } |
+ { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } |
#endif |
- rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res); |
- if( pOp->opcode==OP_IdxLT ){ |
- res = -res; |
- }else{ |
- assert( pOp->opcode==OP_IdxGE ); |
- res++; |
- } |
- if( res>0 ){ |
- pc = pOp->p2 - 1 ; |
- } |
+ res = 0; /* Not needed. Only used to silence a warning. */ |
+ rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res); |
+ assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) ); |
+ if( (pOp->opcode&1)==(OP_IdxLT&1) ){ |
+ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); |
+ res = -res; |
+ }else{ |
+ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxGT ); |
+ res++; |
+ } |
+ VdbeBranchTaken(res>0,2); |
+ if( res>0 ){ |
+ pc = pOp->p2 - 1 ; |
} |
break; |
} |
@@ -4508,15 +4905,19 @@ case OP_Destroy: { /* out2-prerelease */ |
int iCnt; |
Vdbe *pVdbe; |
int iDb; |
+ |
+ assert( p->readOnly==0 ); |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
iCnt = 0; |
for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){ |
- if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){ |
+ if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->bIsReader |
+ && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 |
+ ){ |
iCnt++; |
} |
} |
#else |
- iCnt = db->activeVdbeCnt; |
+ iCnt = db->nVdbeRead; |
#endif |
pOut->flags = MEM_Null; |
if( iCnt>1 ){ |
@@ -4525,7 +4926,8 @@ case OP_Destroy: { /* out2-prerelease */ |
}else{ |
iDb = pOp->p3; |
assert( iCnt==1 ); |
- assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, iDb) ); |
+ iMoved = 0; /* Not needed. Only to silence a warning. */ |
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); |
pOut->flags = MEM_Int; |
pOut->u.i = iMoved; |
@@ -4563,7 +4965,8 @@ case OP_Clear: { |
int nChange; |
nChange = 0; |
- assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 ); |
+ assert( p->readOnly==0 ); |
+ assert( DbMaskTest(p->btreeMask, pOp->p2) ); |
rc = sqlite3BtreeClearTable( |
db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) |
); |
@@ -4578,7 +4981,31 @@ case OP_Clear: { |
break; |
} |
+/* Opcode: ResetSorter P1 * * * * |
+** |
+** Delete all contents from the ephemeral table or sorter |
+** that is open on cursor P1. |
+** |
+** This opcode only works for cursors used for sorting and |
+** opened with OP_OpenEphemeral or OP_SorterOpen. |
+*/ |
+case OP_ResetSorter: { |
+ VdbeCursor *pC; |
+ |
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
+ pC = p->apCsr[pOp->p1]; |
+ assert( pC!=0 ); |
+ if( pC->pSorter ){ |
+ sqlite3VdbeSorterReset(db, pC->pSorter); |
+ }else{ |
+ assert( pC->isEphemeral ); |
+ rc = sqlite3BtreeClearTableOfCursor(pC->pCursor); |
+ } |
+ break; |
+} |
+ |
/* Opcode: CreateTable P1 P2 * * * |
+** Synopsis: r[P2]=root iDb=P1 |
** |
** Allocate a new table in the main database file if P1==0 or in the |
** auxiliary database file if P1==1 or in an attached database if |
@@ -4592,6 +5019,7 @@ case OP_Clear: { |
** See also: CreateIndex |
*/ |
/* Opcode: CreateIndex P1 P2 * * * |
+** Synopsis: r[P2]=root iDb=P1 |
** |
** Allocate a new index in the main database file if P1==0 or in the |
** auxiliary database file if P1==1 or in an attached database if |
@@ -4608,7 +5036,8 @@ case OP_CreateTable: { /* out2-prerelease */ |
pgno = 0; |
assert( pOp->p1>=0 && pOp->p1<db->nDb ); |
- assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, pOp->p1) ); |
+ assert( p->readOnly==0 ); |
pDb = &db->aDb[pOp->p1]; |
assert( pDb->pBt!=0 ); |
if( pOp->opcode==OP_CreateTable ){ |
@@ -4670,6 +5099,7 @@ case OP_ParseSchema: { |
db->init.busy = 0; |
} |
} |
+ if( rc ) sqlite3ResetAllSchemasOfConnection(db); |
if( rc==SQLITE_NOMEM ){ |
goto no_mem; |
} |
@@ -4694,7 +5124,8 @@ case OP_LoadAnalysis: { |
** |
** Remove the internal (in-memory) data structures that describe |
** the table named P4 in database P1. This is called after a table |
-** is dropped in order to keep the internal representation of the |
+** is dropped from disk (using the Destroy opcode) in order to keep |
+** the internal representation of the |
** schema consistent with what is on disk. |
*/ |
case OP_DropTable: { |
@@ -4706,7 +5137,8 @@ case OP_DropTable: { |
** |
** Remove the internal (in-memory) data structures that describe |
** the index named P4 in database P1. This is called after an index |
-** is dropped in order to keep the internal representation of the |
+** is dropped from disk (using the Destroy opcode) |
+** in order to keep the internal representation of the |
** schema consistent with what is on disk. |
*/ |
case OP_DropIndex: { |
@@ -4718,7 +5150,8 @@ case OP_DropIndex: { |
** |
** Remove the internal (in-memory) data structures that describe |
** the trigger named P4 in database P1. This is called after a trigger |
-** is dropped in order to keep the internal representation of the |
+** is dropped from disk (using the Destroy opcode) in order to keep |
+** the internal representation of the |
** schema consistent with what is on disk. |
*/ |
case OP_DropTrigger: { |
@@ -4755,12 +5188,13 @@ case OP_IntegrityCk: { |
int nErr; /* Number of errors reported */ |
char *z; /* Text of the error report */ |
Mem *pnErr; /* Register keeping track of errors remaining */ |
- |
+ |
+ assert( p->bIsReader ); |
nRoot = pOp->p2; |
assert( nRoot>0 ); |
aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) ); |
if( aRoot==0 ) goto no_mem; |
- assert( pOp->p3>0 && pOp->p3<=p->nMem ); |
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); |
pnErr = &aMem[pOp->p3]; |
assert( (pnErr->flags & MEM_Int)!=0 ); |
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 ); |
@@ -4770,7 +5204,7 @@ case OP_IntegrityCk: { |
} |
aRoot[j] = 0; |
assert( pOp->p5<db->nDb ); |
- assert( (p->btreeMask & (((yDbMask)1)<<pOp->p5))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, pOp->p5) ); |
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot, |
(int)pnErr->u.i, &nErr); |
sqlite3DbFree(db, aRoot); |
@@ -4790,6 +5224,7 @@ case OP_IntegrityCk: { |
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ |
/* Opcode: RowSetAdd P1 P2 * * * |
+** Synopsis: rowset(P1)=r[P2] |
** |
** Insert the integer value held by register P2 into a boolean index |
** held in register P1. |
@@ -4809,6 +5244,7 @@ case OP_RowSetAdd: { /* in1, in2 */ |
} |
/* Opcode: RowSetRead P1 P2 P3 * * |
+** Synopsis: r[P3]=rowset(P1) |
** |
** Extract the smallest value from boolean index P1 and put that value into |
** register P3. Or, if boolean index P1 is initially empty, leave P3 |
@@ -4816,7 +5252,7 @@ case OP_RowSetAdd: { /* in1, in2 */ |
*/ |
case OP_RowSetRead: { /* jump, in1, out3 */ |
i64 val; |
- CHECK_FOR_INTERRUPT; |
+ |
pIn1 = &aMem[pOp->p1]; |
if( (pIn1->flags & MEM_RowSet)==0 |
|| sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0 |
@@ -4824,14 +5260,17 @@ case OP_RowSetRead: { /* jump, in1, out3 */ |
/* The boolean index is empty */ |
sqlite3VdbeMemSetNull(pIn1); |
pc = pOp->p2 - 1; |
+ VdbeBranchTaken(1,2); |
}else{ |
/* A value was pulled from the index */ |
sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val); |
+ VdbeBranchTaken(0,2); |
} |
- break; |
+ goto check_for_interrupt; |
} |
/* Opcode: RowSetTest P1 P2 P3 P4 |
+** Synopsis: if r[P3] in rowset(P1) goto P2 |
** |
** Register P3 is assumed to hold a 64-bit integer value. If register P1 |
** contains a RowSet object and that RowSet object contains |
@@ -4874,9 +5313,8 @@ case OP_RowSetTest: { /* jump, in1, in3 */ |
assert( pOp->p4type==P4_INT32 ); |
assert( iSet==-1 || iSet>=0 ); |
if( iSet ){ |
- exists = sqlite3RowSetTest(pIn1->u.pRowSet, |
- (u8)(iSet>=0 ? iSet & 0xf : 0xff), |
- pIn3->u.i); |
+ exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); |
+ VdbeBranchTaken(exists!=0,2); |
if( exists ){ |
pc = pOp->p2 - 1; |
break; |
@@ -4891,7 +5329,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */ |
#ifndef SQLITE_OMIT_TRIGGER |
-/* Opcode: Program P1 P2 P3 P4 * |
+/* Opcode: Program P1 P2 P3 P4 P5 |
** |
** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). |
** |
@@ -4903,6 +5341,8 @@ case OP_RowSetTest: { /* jump, in1, in3 */ |
** memory required by the sub-vdbe at runtime. |
** |
** P4 is a pointer to the VM containing the trigger program. |
+** |
+** If P5 is non-zero, then recursive program invocation is enabled. |
*/ |
case OP_Program: { /* jump */ |
int nMem; /* Number of memory registers for sub-program */ |
@@ -4916,7 +5356,6 @@ case OP_Program: { /* jump */ |
pProgram = pOp->p4.pProgram; |
pRt = &aMem[pOp->p3]; |
- assert( memIsValid(pRt) ); |
assert( pProgram->nOp>0 ); |
/* If the p5 flag is clear, then recursive invocation of triggers is |
@@ -4955,7 +5394,8 @@ case OP_Program: { /* jump */ |
nMem = pProgram->nMem + pProgram->nCsr; |
nByte = ROUND8(sizeof(VdbeFrame)) |
+ nMem * sizeof(Mem) |
- + pProgram->nCsr * sizeof(VdbeCursor *); |
+ + pProgram->nCsr * sizeof(VdbeCursor *) |
+ + pProgram->nOnce * sizeof(u8); |
pFrame = sqlite3DbMallocZero(db, nByte); |
if( !pFrame ){ |
goto no_mem; |
@@ -4975,10 +5415,12 @@ case OP_Program: { /* jump */ |
pFrame->aOp = p->aOp; |
pFrame->nOp = p->nOp; |
pFrame->token = pProgram->token; |
+ pFrame->aOnceFlag = p->aOnceFlag; |
+ pFrame->nOnceFlag = p->nOnceFlag; |
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; |
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ |
- pMem->flags = MEM_Null; |
+ pMem->flags = MEM_Undefined; |
pMem->db = db; |
} |
}else{ |
@@ -4990,7 +5432,7 @@ case OP_Program: { /* jump */ |
p->nFrame++; |
pFrame->pParent = p->pFrame; |
- pFrame->lastRowid = db->lastRowid; |
+ pFrame->lastRowid = lastRowid; |
pFrame->nChange = p->nChange; |
p->nChange = 0; |
p->pFrame = pFrame; |
@@ -5000,7 +5442,10 @@ case OP_Program: { /* jump */ |
p->apCsr = (VdbeCursor **)&aMem[p->nMem+1]; |
p->aOp = aOp = pProgram->aOp; |
p->nOp = pProgram->nOp; |
+ p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; |
+ p->nOnceFlag = pProgram->nOnce; |
pc = -1; |
+ memset(p->aOnceFlag, 0, p->nOnceFlag); |
break; |
} |
@@ -5030,6 +5475,7 @@ case OP_Param: { /* out2-prerelease */ |
#ifndef SQLITE_OMIT_FOREIGN_KEY |
/* Opcode: FkCounter P1 P2 * * * |
+** Synopsis: fkctr[P1]+=P2 |
** |
** Increment a "constraint counter" by P2 (P2 may be negative or positive). |
** If P1 is non-zero, the database constraint counter is incremented |
@@ -5037,7 +5483,9 @@ case OP_Param: { /* out2-prerelease */ |
** statement counter is incremented (immediate foreign key constraints). |
*/ |
case OP_FkCounter: { |
- if( pOp->p1 ){ |
+ if( db->flags & SQLITE_DeferFKs ){ |
+ db->nDeferredImmCons += pOp->p2; |
+ }else if( pOp->p1 ){ |
db->nDeferredCons += pOp->p2; |
}else{ |
p->nFkConstraint += pOp->p2; |
@@ -5046,6 +5494,7 @@ case OP_FkCounter: { |
} |
/* Opcode: FkIfZero P1 P2 * * * |
+** Synopsis: if fkctr[P1]==0 goto P2 |
** |
** This opcode tests if a foreign key constraint-counter is currently zero. |
** If so, jump to instruction P2. Otherwise, fall through to the next |
@@ -5058,9 +5507,11 @@ case OP_FkCounter: { |
*/ |
case OP_FkIfZero: { /* jump */ |
if( pOp->p1 ){ |
- if( db->nDeferredCons==0 ) pc = pOp->p2-1; |
+ VdbeBranchTaken(db->nDeferredCons==0 && db->nDeferredImmCons==0, 2); |
+ if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1; |
}else{ |
- if( p->nFkConstraint==0 ) pc = pOp->p2-1; |
+ VdbeBranchTaken(p->nFkConstraint==0 && db->nDeferredImmCons==0, 2); |
+ if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1; |
} |
break; |
} |
@@ -5068,6 +5519,7 @@ case OP_FkIfZero: { /* jump */ |
#ifndef SQLITE_OMIT_AUTOINCREMENT |
/* Opcode: MemMax P1 P2 * * * |
+** Synopsis: r[P1]=max(r[P1],r[P2]) |
** |
** P1 is a register in the root frame of this VM (the root frame is |
** different from the current frame if this instruction is being executed |
@@ -5078,7 +5530,6 @@ case OP_FkIfZero: { /* jump */ |
** an integer. |
*/ |
case OP_MemMax: { /* in2 */ |
- Mem *pIn1; |
VdbeFrame *pFrame; |
if( p->pFrame ){ |
for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); |
@@ -5098,6 +5549,7 @@ case OP_MemMax: { /* in2 */ |
#endif /* SQLITE_OMIT_AUTOINCREMENT */ |
/* Opcode: IfPos P1 P2 * * * |
+** Synopsis: if r[P1]>0 goto P2 |
** |
** If the value of register P1 is 1 or greater, jump to P2. |
** |
@@ -5107,22 +5559,24 @@ case OP_MemMax: { /* in2 */ |
case OP_IfPos: { /* jump, in1 */ |
pIn1 = &aMem[pOp->p1]; |
assert( pIn1->flags&MEM_Int ); |
+ VdbeBranchTaken( pIn1->u.i>0, 2); |
if( pIn1->u.i>0 ){ |
pc = pOp->p2 - 1; |
} |
break; |
} |
-/* Opcode: IfNeg P1 P2 * * * |
-** |
-** If the value of register P1 is less than zero, jump to P2. |
+/* Opcode: IfNeg P1 P2 P3 * * |
+** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2 |
** |
-** It is illegal to use this instruction on a register that does |
-** not contain an integer. An assertion fault will result if you try. |
+** Register P1 must contain an integer. Add literal P3 to the value in |
+** register P1 then if the value of register P1 is less than zero, jump to P2. |
*/ |
case OP_IfNeg: { /* jump, in1 */ |
pIn1 = &aMem[pOp->p1]; |
assert( pIn1->flags&MEM_Int ); |
+ pIn1->u.i += pOp->p3; |
+ VdbeBranchTaken(pIn1->u.i<0, 2); |
if( pIn1->u.i<0 ){ |
pc = pOp->p2 - 1; |
} |
@@ -5130,17 +5584,16 @@ case OP_IfNeg: { /* jump, in1 */ |
} |
/* Opcode: IfZero P1 P2 P3 * * |
+** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2 |
** |
** The register P1 must contain an integer. Add literal P3 to the |
** value in register P1. If the result is exactly 0, jump to P2. |
-** |
-** It is illegal to use this instruction on a register that does |
-** not contain an integer. An assertion fault will result if you try. |
*/ |
case OP_IfZero: { /* jump, in1 */ |
pIn1 = &aMem[pOp->p1]; |
assert( pIn1->flags&MEM_Int ); |
pIn1->u.i += pOp->p3; |
+ VdbeBranchTaken(pIn1->u.i==0, 2); |
if( pIn1->u.i==0 ){ |
pc = pOp->p2 - 1; |
} |
@@ -5148,6 +5601,7 @@ case OP_IfZero: { /* jump, in1 */ |
} |
/* Opcode: AggStep * P2 P3 P4 P5 |
+** Synopsis: accum=r[P3] step(r[P2@P5]) |
** |
** Execute the step function for an aggregate. The |
** function has P5 arguments. P4 is a pointer to the FuncDef |
@@ -5162,6 +5616,7 @@ case OP_AggStep: { |
int i; |
Mem *pMem; |
Mem *pRec; |
+ Mem t; |
sqlite3_context ctx; |
sqlite3_value **apVal; |
@@ -5174,37 +5629,33 @@ case OP_AggStep: { |
assert( memIsValid(pRec) ); |
apVal[i] = pRec; |
memAboutToChange(p, pRec); |
- sqlite3VdbeMemStoreType(pRec); |
} |
ctx.pFunc = pOp->p4.pFunc; |
- assert( pOp->p3>0 && pOp->p3<=p->nMem ); |
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); |
ctx.pMem = pMem = &aMem[pOp->p3]; |
pMem->n++; |
- ctx.s.flags = MEM_Null; |
- ctx.s.z = 0; |
- ctx.s.zMalloc = 0; |
- ctx.s.xDel = 0; |
- ctx.s.db = db; |
+ sqlite3VdbeMemInit(&t, db, MEM_Null); |
+ ctx.pOut = &t; |
ctx.isError = 0; |
- ctx.pColl = 0; |
- if( ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){ |
- assert( pOp>p->aOp ); |
- assert( pOp[-1].p4type==P4_COLLSEQ ); |
- assert( pOp[-1].opcode==OP_CollSeq ); |
- ctx.pColl = pOp[-1].p4.pColl; |
- } |
+ ctx.pVdbe = p; |
+ ctx.iOp = pc; |
+ ctx.skipFlag = 0; |
(ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */ |
if( ctx.isError ){ |
- sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s)); |
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&t)); |
rc = ctx.isError; |
} |
- |
- sqlite3VdbeMemRelease(&ctx.s); |
- |
+ if( ctx.skipFlag ){ |
+ assert( pOp[-1].opcode==OP_CollSeq ); |
+ i = pOp[-1].p1; |
+ if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1); |
+ } |
+ sqlite3VdbeMemRelease(&t); |
break; |
} |
/* Opcode: AggFinal P1 P2 * P4 * |
+** Synopsis: accum=r[P1] N=P2 |
** |
** Execute the finalizer function for an aggregate. P1 is |
** the memory location that is the accumulator for the aggregate. |
@@ -5218,7 +5669,7 @@ case OP_AggStep: { |
*/ |
case OP_AggFinal: { |
Mem *pMem; |
- assert( pOp->p1>0 && pOp->p1<=p->nMem ); |
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); |
pMem = &aMem[pOp->p1]; |
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); |
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); |
@@ -5250,6 +5701,7 @@ case OP_Checkpoint: { |
int aRes[3]; /* Results */ |
Mem *pMem; /* Write results here */ |
+ assert( p->readOnly==0 ); |
aRes[0] = 0; |
aRes[1] = aRes[2] = -1; |
assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE |
@@ -5269,7 +5721,7 @@ case OP_Checkpoint: { |
#endif |
#ifndef SQLITE_OMIT_PRAGMA |
-/* Opcode: JournalMode P1 P2 P3 * P5 |
+/* Opcode: JournalMode P1 P2 P3 * * |
** |
** Change the journal mode of database P1 to P3. P3 must be one of the |
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback |
@@ -5285,7 +5737,9 @@ case OP_JournalMode: { /* out2-prerelease */ |
Pager *pPager; /* Pager associated with pBt */ |
int eNew; /* New journal mode */ |
int eOld; /* The old journal mode */ |
+#ifndef SQLITE_OMIT_WAL |
const char *zFilename; /* Name of database file for pPager */ |
+#endif |
eNew = pOp->p3; |
assert( eNew==PAGER_JOURNALMODE_DELETE |
@@ -5297,6 +5751,7 @@ case OP_JournalMode: { /* out2-prerelease */ |
|| eNew==PAGER_JOURNALMODE_QUERY |
); |
assert( pOp->p1>=0 && pOp->p1<db->nDb ); |
+ assert( p->readOnly==0 ); |
pBt = db->aDb[pOp->p1].pBt; |
pPager = sqlite3BtreePager(pBt); |
@@ -5305,13 +5760,13 @@ case OP_JournalMode: { /* out2-prerelease */ |
if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; |
#ifndef SQLITE_OMIT_WAL |
- zFilename = sqlite3PagerFilename(pPager); |
+ zFilename = sqlite3PagerFilename(pPager, 1); |
/* Do not allow a transition to journal_mode=WAL for a database |
** in temporary storage or if the VFS does not support shared memory |
*/ |
if( eNew==PAGER_JOURNALMODE_WAL |
- && (zFilename[0]==0 /* Temp file */ |
+ && (sqlite3Strlen30(zFilename)==0 /* Temp file */ |
|| !sqlite3PagerWalSupported(pPager)) /* No shared-memory support */ |
){ |
eNew = eOld; |
@@ -5320,7 +5775,7 @@ case OP_JournalMode: { /* out2-prerelease */ |
if( (eNew!=eOld) |
&& (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL) |
){ |
- if( !db->autoCommit || db->activeVdbeCnt>1 ){ |
+ if( !db->autoCommit || db->nVdbeRead>1 ){ |
rc = SQLITE_ERROR; |
sqlite3SetString(&p->zErrMsg, db, |
"cannot change %s wal mode from within a transaction", |
@@ -5379,6 +5834,7 @@ case OP_JournalMode: { /* out2-prerelease */ |
** a transaction. |
*/ |
case OP_Vacuum: { |
+ assert( p->readOnly==0 ); |
rc = sqlite3RunVacuum(&p->zErrMsg, db); |
break; |
} |
@@ -5395,9 +5851,11 @@ case OP_IncrVacuum: { /* jump */ |
Btree *pBt; |
assert( pOp->p1>=0 && pOp->p1<db->nDb ); |
- assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, pOp->p1) ); |
+ assert( p->readOnly==0 ); |
pBt = db->aDb[pOp->p1].pBt; |
rc = sqlite3BtreeIncrVacuum(pBt); |
+ VdbeBranchTaken(rc==SQLITE_DONE,2); |
if( rc==SQLITE_DONE ){ |
pc = pOp->p2 - 1; |
rc = SQLITE_OK; |
@@ -5408,12 +5866,13 @@ case OP_IncrVacuum: { /* jump */ |
/* Opcode: Expire P1 * * * * |
** |
-** Cause precompiled statements to become expired. An expired statement |
-** fails with an error code of SQLITE_SCHEMA if it is ever executed |
-** (via sqlite3_step()). |
+** Cause precompiled statements to expire. When an expired statement |
+** is executed using sqlite3_step() it will either automatically |
+** reprepare itself (if it was originally created using sqlite3_prepare_v2()) |
+** or it will fail with SQLITE_SCHEMA. |
** |
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, |
-** then only the currently executing statement is affected. |
+** then only the currently executing statement is expired. |
*/ |
case OP_Expire: { |
if( !pOp->p1 ){ |
@@ -5426,6 +5885,7 @@ case OP_Expire: { |
#ifndef SQLITE_OMIT_SHARED_CACHE |
/* Opcode: TableLock P1 P2 P3 P4 * |
+** Synopsis: iDb=P1 root=P2 write=P3 |
** |
** Obtain a lock on a particular table. This instruction is only used when |
** the shared-cache feature is enabled. |
@@ -5444,7 +5904,7 @@ case OP_TableLock: { |
if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ |
int p1 = pOp->p1; |
assert( p1>=0 && p1<db->nDb ); |
- assert( (p->btreeMask & (((yDbMask)1)<<p1))!=0 ); |
+ assert( DbMaskTest(p->btreeMask, p1) ); |
assert( isWriteLock==0 || isWriteLock==1 ); |
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); |
if( (rc&0xFF)==SQLITE_LOCKED ){ |
@@ -5470,7 +5930,7 @@ case OP_VBegin: { |
VTable *pVTab; |
pVTab = pOp->p4.pVtab; |
rc = sqlite3VtabBegin(db, pVTab); |
- if( pVTab ) importVtabErrMsg(p, pVTab->pVtab); |
+ if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab); |
break; |
} |
#endif /* SQLITE_OMIT_VIRTUALTABLE */ |
@@ -5514,22 +5974,22 @@ case OP_VOpen: { |
sqlite3_vtab *pVtab; |
sqlite3_module *pModule; |
+ assert( p->bIsReader ); |
pCur = 0; |
pVtabCursor = 0; |
pVtab = pOp->p4.pVtab->pVtab; |
pModule = (sqlite3_module *)pVtab->pModule; |
assert(pVtab && pModule); |
rc = pModule->xOpen(pVtab, &pVtabCursor); |
- importVtabErrMsg(p, pVtab); |
+ sqlite3VtabImportErrmsg(p, pVtab); |
if( SQLITE_OK==rc ){ |
/* Initialize sqlite3_vtab_cursor base class */ |
pVtabCursor->pVtab = pVtab; |
- /* Initialise vdbe cursor object */ |
+ /* Initialize vdbe cursor object */ |
pCur = allocateCursor(p, pOp->p1, 0, -1, 0); |
if( pCur ){ |
pCur->pVtabCursor = pVtabCursor; |
- pCur->pModule = pVtabCursor->pVtab->pModule; |
}else{ |
db->mallocFailed = 1; |
pModule->xClose(pVtabCursor); |
@@ -5541,6 +6001,7 @@ case OP_VOpen: { |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
/* Opcode: VFilter P1 P2 P3 P4 * |
+** Synopsis: iplan=r[P3] zplan='P4' |
** |
** P1 is a cursor opened using VOpen. P2 is an address to jump to if |
** the filtered result set is empty. |
@@ -5592,17 +6053,16 @@ case OP_VFilter: { /* jump */ |
apArg = p->apArg; |
for(i = 0; i<nArg; i++){ |
apArg[i] = &pArgc[i+1]; |
- sqlite3VdbeMemStoreType(apArg[i]); |
} |
p->inVtabMethod = 1; |
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg); |
p->inVtabMethod = 0; |
- importVtabErrMsg(p, pVtab); |
+ sqlite3VtabImportErrmsg(p, pVtab); |
if( rc==SQLITE_OK ){ |
res = pModule->xEof(pVtabCursor); |
} |
- |
+ VdbeBranchTaken(res!=0,2); |
if( res ){ |
pc = pOp->p2 - 1; |
} |
@@ -5615,6 +6075,7 @@ case OP_VFilter: { /* jump */ |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
/* Opcode: VColumn P1 P2 P3 * * |
+** Synopsis: r[P3]=vcolumn(P2) |
** |
** Store the value of the P2-th column of |
** the row of the virtual-table that the |
@@ -5628,7 +6089,7 @@ case OP_VColumn: { |
VdbeCursor *pCur = p->apCsr[pOp->p1]; |
assert( pCur->pVtabCursor ); |
- assert( pOp->p3>0 && pOp->p3<=p->nMem ); |
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); |
pDest = &aMem[pOp->p3]; |
memAboutToChange(p, pDest); |
if( pCur->nullRow ){ |
@@ -5639,27 +6100,14 @@ case OP_VColumn: { |
pModule = pVtab->pModule; |
assert( pModule->xColumn ); |
memset(&sContext, 0, sizeof(sContext)); |
- |
- /* The output cell may already have a buffer allocated. Move |
- ** the current contents to sContext.s so in case the user-function |
- ** can use the already allocated buffer instead of allocating a |
- ** new one. |
- */ |
- sqlite3VdbeMemMove(&sContext.s, pDest); |
- MemSetTypeFlag(&sContext.s, MEM_Null); |
- |
+ sContext.pOut = pDest; |
+ MemSetTypeFlag(pDest, MEM_Null); |
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2); |
- importVtabErrMsg(p, pVtab); |
+ sqlite3VtabImportErrmsg(p, pVtab); |
if( sContext.isError ){ |
rc = sContext.isError; |
} |
- |
- /* Copy the result of the function to the P3 register. We |
- ** do this regardless of whether or not an error occurred to ensure any |
- ** dynamic allocation in sContext.s (a Mem struct) is released. |
- */ |
- sqlite3VdbeChangeEncoding(&sContext.s, encoding); |
- sqlite3VdbeMemMove(pDest, &sContext.s); |
+ sqlite3VdbeChangeEncoding(pDest, encoding); |
REGISTER_TRACE(pOp->p3, pDest); |
UPDATE_MAX_BLOBSIZE(pDest); |
@@ -5702,16 +6150,16 @@ case OP_VNext: { /* jump */ |
p->inVtabMethod = 1; |
rc = pModule->xNext(pCur->pVtabCursor); |
p->inVtabMethod = 0; |
- importVtabErrMsg(p, pVtab); |
+ sqlite3VtabImportErrmsg(p, pVtab); |
if( rc==SQLITE_OK ){ |
res = pModule->xEof(pCur->pVtabCursor); |
} |
- |
+ VdbeBranchTaken(!res,2); |
if( !res ){ |
/* If there is data, jump to P2 */ |
pc = pOp->p2 - 1; |
} |
- break; |
+ goto check_for_interrupt; |
} |
#endif /* SQLITE_OMIT_VIRTUALTABLE */ |
@@ -5730,18 +6178,25 @@ case OP_VRename: { |
pName = &aMem[pOp->p1]; |
assert( pVtab->pModule->xRename ); |
assert( memIsValid(pName) ); |
+ assert( p->readOnly==0 ); |
REGISTER_TRACE(pOp->p1, pName); |
assert( pName->flags & MEM_Str ); |
- rc = pVtab->pModule->xRename(pVtab, pName->z); |
- importVtabErrMsg(p, pVtab); |
- p->expired = 0; |
- |
+ testcase( pName->enc==SQLITE_UTF8 ); |
+ testcase( pName->enc==SQLITE_UTF16BE ); |
+ testcase( pName->enc==SQLITE_UTF16LE ); |
+ rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); |
+ if( rc==SQLITE_OK ){ |
+ rc = pVtab->pModule->xRename(pVtab, pName->z); |
+ sqlite3VtabImportErrmsg(p, pVtab); |
+ p->expired = 0; |
+ } |
break; |
} |
#endif |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
-/* Opcode: VUpdate P1 P2 P3 P4 * |
+/* Opcode: VUpdate P1 P2 P3 P4 P5 |
+** Synopsis: data=r[P3@P2] |
** |
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. |
** This opcode invokes the corresponding xUpdate method. P2 values |
@@ -5763,6 +6218,9 @@ case OP_VRename: { |
** P1 is a boolean flag. If it is set to true and the xUpdate call |
** is successful, then the value returned by sqlite3_last_insert_rowid() |
** is set to the value of the rowid for the row just inserted. |
+** |
+** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to |
+** apply in the case of a constraint failure on an insert or update. |
*/ |
case OP_VUpdate: { |
sqlite3_vtab *pVtab; |
@@ -5773,27 +6231,41 @@ case OP_VUpdate: { |
Mem **apArg; |
Mem *pX; |
+ assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback |
+ || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace |
+ ); |
+ assert( p->readOnly==0 ); |
pVtab = pOp->p4.pVtab->pVtab; |
pModule = (sqlite3_module *)pVtab->pModule; |
nArg = pOp->p2; |
assert( pOp->p4type==P4_VTAB ); |
if( ALWAYS(pModule->xUpdate) ){ |
+ u8 vtabOnConflict = db->vtabOnConflict; |
apArg = p->apArg; |
pX = &aMem[pOp->p3]; |
for(i=0; i<nArg; i++){ |
assert( memIsValid(pX) ); |
memAboutToChange(p, pX); |
- sqlite3VdbeMemStoreType(pX); |
apArg[i] = pX; |
pX++; |
} |
+ db->vtabOnConflict = pOp->p5; |
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); |
- importVtabErrMsg(p, pVtab); |
+ db->vtabOnConflict = vtabOnConflict; |
+ sqlite3VtabImportErrmsg(p, pVtab); |
if( rc==SQLITE_OK && pOp->p1 ){ |
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); |
- db->lastRowid = rowid; |
+ db->lastRowid = lastRowid = rowid; |
+ } |
+ if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ |
+ if( pOp->p5==OE_Ignore ){ |
+ rc = SQLITE_OK; |
+ }else{ |
+ p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5); |
+ } |
+ }else{ |
+ p->nChange++; |
} |
- p->nChange++; |
} |
break; |
} |
@@ -5836,31 +6308,54 @@ case OP_MaxPgcnt: { /* out2-prerelease */ |
#endif |
-#ifndef SQLITE_OMIT_TRACE |
-/* Opcode: Trace * * * P4 * |
+/* Opcode: Init * P2 * P4 * |
+** Synopsis: Start at P2 |
+** |
+** Programs contain a single instance of this opcode as the very first |
+** opcode. |
** |
** If tracing is enabled (by the sqlite3_trace()) interface, then |
** the UTF-8 string contained in P4 is emitted on the trace callback. |
+** Or if P4 is blank, use the string returned by sqlite3_sql(). |
+** |
+** If P2 is not zero, jump to instruction P2. |
*/ |
-case OP_Trace: { |
+case OP_Init: { /* jump */ |
char *zTrace; |
+ char *z; |
+ if( pOp->p2 ){ |
+ pc = pOp->p2 - 1; |
+ } |
+#ifndef SQLITE_OMIT_TRACE |
+ if( db->xTrace |
+ && !p->doingRerun |
+ && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 |
+ ){ |
+ z = sqlite3VdbeExpandSql(p, zTrace); |
+ db->xTrace(db->pTraceArg, z); |
+ sqlite3DbFree(db, z); |
+ } |
+#ifdef SQLITE_USE_FCNTL_TRACE |
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); |
if( zTrace ){ |
- if( db->xTrace ){ |
- char *z = sqlite3VdbeExpandSql(p, zTrace); |
- db->xTrace(db->pTraceArg, z); |
- sqlite3DbFree(db, z); |
+ int i; |
+ for(i=0; i<db->nDb; i++){ |
+ if( DbMaskTest(p->btreeMask, i)==0 ) continue; |
+ sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace); |
} |
+ } |
+#endif /* SQLITE_USE_FCNTL_TRACE */ |
#ifdef SQLITE_DEBUG |
- if( (db->flags & SQLITE_SqlTrace)!=0 ){ |
- sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); |
- } |
-#endif /* SQLITE_DEBUG */ |
+ if( (db->flags & SQLITE_SqlTrace)!=0 |
+ && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 |
+ ){ |
+ sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); |
} |
+#endif /* SQLITE_DEBUG */ |
+#endif /* SQLITE_OMIT_TRACE */ |
break; |
} |
-#endif |
/* Opcode: Noop * * * * * |
@@ -5889,13 +6384,9 @@ default: { /* This is really OP_Noop and OP_Explain */ |
#ifdef VDBE_PROFILE |
{ |
- u64 elapsed = sqlite3Hwtime() - start; |
- pOp->cycles += elapsed; |
+ u64 endTime = sqlite3Hwtime(); |
+ if( endTime>start ) pOp->cycles += endTime - start; |
pOp->cnt++; |
-#if 0 |
- fprintf(stdout, "%10llu ", elapsed); |
- sqlite3VdbePrintOp(stdout, origPc, &aOp[origPc]); |
-#endif |
} |
#endif |
@@ -5908,13 +6399,13 @@ default: { /* This is really OP_Noop and OP_Explain */ |
assert( pc>=-1 && pc<p->nOp ); |
#ifdef SQLITE_DEBUG |
- if( p->trace ){ |
- if( rc!=0 ) fprintf(p->trace,"rc=%d\n",rc); |
+ if( db->flags & SQLITE_VdbeTrace ){ |
+ if( rc!=0 ) printf("rc=%d\n",rc); |
if( pOp->opflags & (OPFLG_OUT2_PRERELEASE|OPFLG_OUT2) ){ |
- registerTrace(p->trace, pOp->p2, &aMem[pOp->p2]); |
+ registerTrace(pOp->p2, &aMem[pOp->p2]); |
} |
if( pOp->opflags & OPFLG_OUT3 ){ |
- registerTrace(p->trace, pOp->p3, &aMem[pOp->p3]); |
+ registerTrace(pOp->p3, &aMem[pOp->p3]); |
} |
} |
#endif /* SQLITE_DEBUG */ |
@@ -5934,13 +6425,16 @@ vdbe_error_halt: |
if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1; |
rc = SQLITE_ERROR; |
if( resetSchemaOnFault>0 ){ |
- sqlite3ResetInternalSchema(db, resetSchemaOnFault-1); |
+ sqlite3ResetOneSchema(db, resetSchemaOnFault-1); |
} |
/* This is the only way out of this procedure. We have to |
** release the mutexes on btrees that were acquired at the |
** top. */ |
vdbe_return: |
+ db->lastRowid = lastRowid; |
+ testcase( nVmStep>0 ); |
+ p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; |
sqlite3VdbeLeave(p); |
return rc; |