| 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 e25280a9e2cb6327683d0730ceb5001229565e86..5376b08a00ef9d9f2d27e0d54627fcbe64af20ff 100644
|
| --- a/third_party/sqlite/src/src/vdbe.c
|
| +++ b/third_party/sqlite/src/src/vdbe.c
|
| @@ -42,13 +42,22 @@
|
| ** of the code in this file is, therefore, important. See other comments
|
| ** in this file for details. If in doubt, do not deviate from existing
|
| ** commenting and indentation practices when changing or adding code.
|
| -**
|
| -** $Id: vdbe.c,v 1.874 2009/07/24 17:58:53 danielk1977 Exp $
|
| */
|
| #include "sqliteInt.h"
|
| #include "vdbeInt.h"
|
|
|
| /*
|
| +** Invoke this macro on memory cells just prior to changing the
|
| +** value of the cell. This macro verifies that shallow copies are
|
| +** not misused.
|
| +*/
|
| +#ifdef SQLITE_DEBUG
|
| +# define memAboutToChange(P,M) sqlite3VdbeMemPrepareToChange(P,M)
|
| +#else
|
| +# define memAboutToChange(P,M)
|
| +#endif
|
| +
|
| +/*
|
| ** The following global variable is incremented every time a cursor
|
| ** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test
|
| ** procedures use this information to make sure that indices are
|
| @@ -99,6 +108,17 @@ static void updateMaxBlobsize(Mem *p){
|
| #endif
|
|
|
| /*
|
| +** The next global variable is incremented each type 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
|
| +** library.
|
| +*/
|
| +#ifdef SQLITE_TEST
|
| +int sqlite3_found_count = 0;
|
| +#endif
|
| +
|
| +/*
|
| ** Test a register to see if it exceeds the current maximum blob size.
|
| ** If it does, record the new maximum blob size.
|
| */
|
| @@ -140,12 +160,10 @@ static void updateMaxBlobsize(Mem *p){
|
| /*
|
| ** 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.
|
| -** The second argument, 'db_enc' is the text encoding used by the vdbe for
|
| -** register variables. This routine sets the pMem->enc and pMem->type
|
| -** variables used by the sqlite3_value_*() routines.
|
| +** This routine sets the pMem->type variable used by the sqlite3_value_*()
|
| +** routines.
|
| */
|
| -#define storeTypeInfo(A,B) _storeTypeInfo(A)
|
| -static void _storeTypeInfo(Mem *pMem){
|
| +void sqlite3VdbeMemStoreType(Mem *pMem){
|
| int flags = pMem->flags;
|
| if( flags & MEM_Null ){
|
| pMem->type = SQLITE_NULL;
|
| @@ -164,23 +182,6 @@ static void _storeTypeInfo(Mem *pMem){
|
| }
|
|
|
| /*
|
| -** Properties of opcodes. The OPFLG_INITIALIZER macro is
|
| -** created by mkopcodeh.awk during compilation. Data is obtained
|
| -** from the comments following the "case OP_xxxx:" statements in
|
| -** this file.
|
| -*/
|
| -static const unsigned char opcodeProperty[] = OPFLG_INITIALIZER;
|
| -
|
| -/*
|
| -** Return true if an opcode has any of the OPFLG_xxx properties
|
| -** specified by mask.
|
| -*/
|
| -int sqlite3VdbeOpcodeHasProperty(int opcode, int mask){
|
| - assert( opcode>0 && opcode<(int)sizeof(opcodeProperty) );
|
| - return (opcodeProperty[opcode]&mask)!=0;
|
| -}
|
| -
|
| -/*
|
| ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL
|
| ** if we run out of memory.
|
| */
|
| @@ -214,7 +215,7 @@ static VdbeCursor *allocateCursor(
|
| int nByte;
|
| VdbeCursor *pCx = 0;
|
| nByte =
|
| - sizeof(VdbeCursor) +
|
| + ROUND8(sizeof(VdbeCursor)) +
|
| (isBtreeCursor?sqlite3BtreeCursorSize():0) +
|
| 2*nField*sizeof(u32);
|
|
|
| @@ -225,15 +226,16 @@ static VdbeCursor *allocateCursor(
|
| }
|
| if( SQLITE_OK==sqlite3VdbeMemGrow(pMem, nByte, 0) ){
|
| p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
|
| - memset(pMem->z, 0, nByte);
|
| + memset(pCx, 0, sizeof(VdbeCursor));
|
| pCx->iDb = iDb;
|
| pCx->nField = nField;
|
| if( nField ){
|
| - pCx->aType = (u32 *)&pMem->z[sizeof(VdbeCursor)];
|
| + pCx->aType = (u32 *)&pMem->z[ROUND8(sizeof(VdbeCursor))];
|
| }
|
| if( isBtreeCursor ){
|
| pCx->pCursor = (BtCursor*)
|
| - &pMem->z[sizeof(VdbeCursor)+2*nField*sizeof(u32)];
|
| + &pMem->z[ROUND8(sizeof(VdbeCursor))+2*nField*sizeof(u32)];
|
| + sqlite3BtreeCursorZero(pCx->pCursor);
|
| }
|
| }
|
| return pCx;
|
| @@ -247,18 +249,17 @@ static VdbeCursor *allocateCursor(
|
| */
|
| static void applyNumericAffinity(Mem *pRec){
|
| if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
|
| - int realnum;
|
| - sqlite3VdbeMemNulTerminate(pRec);
|
| - if( (pRec->flags&MEM_Str)
|
| - && sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
|
| - i64 value;
|
| - sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
|
| - if( !realnum && sqlite3Atoi64(pRec->z, &value) ){
|
| - pRec->u.i = value;
|
| - MemSetTypeFlag(pRec, MEM_Int);
|
| - }else{
|
| - sqlite3VdbeMemRealify(pRec);
|
| - }
|
| + 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;
|
| }
|
| }
|
| }
|
| @@ -310,13 +311,13 @@ static void applyAffinity(
|
| ** into a numeric representation. Use either INTEGER or REAL whichever
|
| ** is appropriate. But only do the conversion if it is possible without
|
| ** loss of information and return the revised type of the argument.
|
| -**
|
| -** This is an EXPERIMENTAL api and is subject to change or removal.
|
| */
|
| int sqlite3_value_numeric_type(sqlite3_value *pVal){
|
| Mem *pMem = (Mem*)pVal;
|
| - applyNumericAffinity(pMem);
|
| - storeTypeInfo(pMem, 0);
|
| + if( pMem->type==SQLITE_TEXT ){
|
| + applyNumericAffinity(pMem);
|
| + sqlite3VdbeMemStoreType(pMem);
|
| + }
|
| return pMem->type;
|
| }
|
|
|
| @@ -476,22 +477,6 @@ static void registerTrace(FILE *out, int iReg, Mem *p){
|
| #define CHECK_FOR_INTERRUPT \
|
| if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
|
|
| -#ifdef SQLITE_DEBUG
|
| -static int fileExists(sqlite3 *db, const char *zFile){
|
| - int res = 0;
|
| - int rc = SQLITE_OK;
|
| -#ifdef SQLITE_TEST
|
| - /* If we are currently testing IO errors, then do not call OsAccess() to
|
| - ** test for the presence of zFile. This is because any IO error that
|
| - ** occurs here will not be reported, causing the test to fail.
|
| - */
|
| - extern int sqlite3_io_error_pending;
|
| - if( sqlite3_io_error_pending<=0 )
|
| -#endif
|
| - rc = sqlite3OsAccess(db->pVfs, zFile, SQLITE_ACCESS_EXISTS, &res);
|
| - return (res && rc==SQLITE_OK);
|
| -}
|
| -#endif
|
|
|
| #ifndef NDEBUG
|
| /*
|
| @@ -514,6 +499,20 @@ 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
|
| @@ -547,30 +546,32 @@ static int checkSavepointCount(sqlite3 *db){
|
| int sqlite3VdbeExec(
|
| Vdbe *p /* The VDBE */
|
| ){
|
| - int pc; /* The program counter */
|
| + int pc=0; /* The program counter */
|
| + Op *aOp = p->aOp; /* Copy of p->aOp */
|
| Op *pOp; /* Current operation */
|
| int rc = SQLITE_OK; /* Value to return */
|
| sqlite3 *db = p->db; /* The database */
|
| + u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
|
| u8 encoding = ENC(db); /* The database encoding */
|
| +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
| + int checkProgress; /* True if progress callbacks are enabled */
|
| + int nProgressOps = 0; /* Opcodes executed since progress callback. */
|
| +#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 */
|
| - u8 opProperty;
|
| int iCompare = 0; /* Result of last OP_Compare operation */
|
| int *aPermute = 0; /* Permutation of columns for OP_Compare */
|
| #ifdef VDBE_PROFILE
|
| u64 start; /* CPU clock count at start of opcode */
|
| int origPc; /* Program counter at start of opcode */
|
| #endif
|
| -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
| - int nProgressOps = 0; /* Opcodes executed since progress callback. */
|
| -#endif
|
| /*** INSERT STACK UNION HERE ***/
|
|
|
| assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
|
| - assert( db->magic==SQLITE_MAGIC_BUSY );
|
| - sqlite3VdbeMutexArrayEnter(p);
|
| + sqlite3VdbeEnter(p);
|
| if( p->rc==SQLITE_NOMEM ){
|
| /* This happens if a malloc() inside a call to sqlite3_column_text() or
|
| ** sqlite3_column_text16() failed. */
|
| @@ -583,21 +584,19 @@ int sqlite3VdbeExec(
|
| db->busyHandler.nBusy = 0;
|
| CHECK_FOR_INTERRUPT;
|
| sqlite3VdbeIOTraceSql(p);
|
| +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
| + checkProgress = db->xProgress!=0;
|
| +#endif
|
| #ifdef SQLITE_DEBUG
|
| sqlite3BeginBenignMalloc();
|
| - if( p->pc==0
|
| - && ((p->db->flags & SQLITE_VdbeListing) || fileExists(db, "vdbe_explain"))
|
| - ){
|
| + if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
|
| int i;
|
| printf("VDBE Program Listing:\n");
|
| sqlite3VdbePrintSql(p);
|
| for(i=0; i<p->nOp; i++){
|
| - sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
|
| + sqlite3VdbePrintOp(stdout, i, &aOp[i]);
|
| }
|
| }
|
| - if( fileExists(db, "vdbe_trace") ){
|
| - p->trace = stdout;
|
| - }
|
| sqlite3EndBenignMalloc();
|
| #endif
|
| for(pc=p->pc; rc==SQLITE_OK; pc++){
|
| @@ -607,7 +606,7 @@ int sqlite3VdbeExec(
|
| origPc = pc;
|
| start = sqlite3Hwtime();
|
| #endif
|
| - pOp = &p->aOp[pc];
|
| + pOp = &aOp[pc];
|
|
|
| /* Only allow tracing if SQLITE_DEBUG is defined.
|
| */
|
| @@ -619,13 +618,6 @@ int sqlite3VdbeExec(
|
| }
|
| sqlite3VdbePrintOp(p->trace, pc, pOp);
|
| }
|
| - if( p->trace==0 && pc==0 ){
|
| - sqlite3BeginBenignMalloc();
|
| - if( fileExists(db, "vdbe_sqltrace") ){
|
| - sqlite3VdbePrintSql(p);
|
| - }
|
| - sqlite3EndBenignMalloc();
|
| - }
|
| #endif
|
|
|
|
|
| @@ -648,12 +640,10 @@ int sqlite3VdbeExec(
|
| ** If the progress callback returns non-zero, exit the virtual machine with
|
| ** a return code SQLITE_ABORT.
|
| */
|
| - if( db->xProgress ){
|
| + if( checkProgress ){
|
| if( db->nProgressOps==nProgressOps ){
|
| int prc;
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| - prc =db->xProgress(db->pProgressArg);
|
| - if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
| + prc = db->xProgress(db->pProgressArg);
|
| if( prc!=0 ){
|
| rc = SQLITE_INTERRUPT;
|
| goto vdbe_error_halt;
|
| @@ -664,66 +654,53 @@ int sqlite3VdbeExec(
|
| }
|
| #endif
|
|
|
| - /* Do common setup processing for any opcode that is marked
|
| - ** with the "out2-prerelease" tag. Such opcodes have a single
|
| - ** output which is specified by the P2 parameter. The P2 register
|
| - ** is initialized to a NULL.
|
| + /* On any opcode with the "out2-prerelase" 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.
|
| */
|
| - opProperty = opcodeProperty[pOp->opcode];
|
| - if( (opProperty & OPFLG_OUT2_PRERELEASE)!=0 ){
|
| + assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
|
| + if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){
|
| assert( pOp->p2>0 );
|
| assert( pOp->p2<=p->nMem );
|
| - pOut = &p->aMem[pOp->p2];
|
| + pOut = &aMem[pOp->p2];
|
| + memAboutToChange(p, pOut);
|
| sqlite3VdbeMemReleaseExternal(pOut);
|
| - pOut->flags = MEM_Null;
|
| - pOut->n = 0;
|
| - }else
|
| -
|
| - /* Do common setup for opcodes marked with one of the following
|
| - ** combinations of properties.
|
| - **
|
| - ** in1
|
| - ** in1 in2
|
| - ** in1 in2 out3
|
| - ** in1 in3
|
| - **
|
| - ** Variables pIn1, pIn2, and pIn3 are made to point to appropriate
|
| - ** registers for inputs. Variable pOut points to the output register.
|
| - */
|
| - if( (opProperty & OPFLG_IN1)!=0 ){
|
| + pOut->flags = MEM_Int;
|
| + }
|
| +
|
| + /* Sanity checking on other operands */
|
| +#ifdef SQLITE_DEBUG
|
| + if( (pOp->opflags & OPFLG_IN1)!=0 ){
|
| assert( pOp->p1>0 );
|
| assert( pOp->p1<=p->nMem );
|
| - pIn1 = &p->aMem[pOp->p1];
|
| - REGISTER_TRACE(pOp->p1, pIn1);
|
| - if( (opProperty & OPFLG_IN2)!=0 ){
|
| - assert( pOp->p2>0 );
|
| - assert( pOp->p2<=p->nMem );
|
| - pIn2 = &p->aMem[pOp->p2];
|
| - REGISTER_TRACE(pOp->p2, pIn2);
|
| - /* As currently implemented, in2 implies out3. There is no reason
|
| - ** why this has to be, it just worked out that way. */
|
| - assert( (opProperty & OPFLG_OUT3)!=0 );
|
| - assert( pOp->p3>0 );
|
| - assert( pOp->p3<=p->nMem );
|
| - pOut = &p->aMem[pOp->p3];
|
| - }else if( (opProperty & OPFLG_IN3)!=0 ){
|
| - assert( pOp->p3>0 );
|
| - assert( pOp->p3<=p->nMem );
|
| - pIn3 = &p->aMem[pOp->p3];
|
| - REGISTER_TRACE(pOp->p3, pIn3);
|
| - }
|
| - }else if( (opProperty & OPFLG_IN2)!=0 ){
|
| + assert( memIsValid(&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 );
|
| - pIn2 = &p->aMem[pOp->p2];
|
| - REGISTER_TRACE(pOp->p2, pIn2);
|
| - }else if( (opProperty & OPFLG_IN3)!=0 ){
|
| + assert( memIsValid(&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 );
|
| - pIn3 = &p->aMem[pOp->p3];
|
| - REGISTER_TRACE(pOp->p3, pIn3);
|
| + assert( memIsValid(&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 );
|
| + memAboutToChange(p, &aMem[pOp->p2]);
|
| + }
|
| + if( (pOp->opflags & OPFLG_OUT3)!=0 ){
|
| + assert( pOp->p3>0 );
|
| + assert( pOp->p3<=p->nMem );
|
| + memAboutToChange(p, &aMem[pOp->p3]);
|
| + }
|
| +#endif
|
| +
|
| switch( pOp->opcode ){
|
|
|
| /*****************************************************************************
|
| @@ -779,11 +756,10 @@ case OP_Goto: { /* jump */
|
| ** Write the current address onto register P1
|
| ** and then jump to address P2.
|
| */
|
| -case OP_Gosub: { /* jump */
|
| - assert( pOp->p1>0 );
|
| - assert( pOp->p1<=p->nMem );
|
| - pIn1 = &p->aMem[pOp->p1];
|
| +case OP_Gosub: { /* jump, in1 */
|
| + pIn1 = &aMem[pOp->p1];
|
| assert( (pIn1->flags & MEM_Dyn)==0 );
|
| + memAboutToChange(p, pIn1);
|
| pIn1->flags = MEM_Int;
|
| pIn1->u.i = pc;
|
| REGISTER_TRACE(pOp->p1, pIn1);
|
| @@ -796,6 +772,7 @@ case OP_Gosub: { /* jump */
|
| ** Jump to the next instruction after the address in register P1.
|
| */
|
| case OP_Return: { /* in1 */
|
| + pIn1 = &aMem[pOp->p1];
|
| assert( pIn1->flags & MEM_Int );
|
| pc = (int)pIn1->u.i;
|
| break;
|
| @@ -807,6 +784,7 @@ case OP_Return: { /* in1 */
|
| */
|
| case OP_Yield: { /* in1 */
|
| int pcDest;
|
| + pIn1 = &aMem[pOp->p1];
|
| assert( (pIn1->flags & MEM_Dyn)==0 );
|
| pIn1->flags = MEM_Int;
|
| pcDest = (int)pIn1->u.i;
|
| @@ -823,6 +801,7 @@ case OP_Yield: { /* in1 */
|
| ** value in register P3 is not NULL, then this routine is a no-op.
|
| */
|
| case OP_HaltIfNull: { /* in3 */
|
| + pIn3 = &aMem[pOp->p3];
|
| if( (pIn3->flags & MEM_Null)==0 ) break;
|
| /* Fall through into OP_Halt */
|
| }
|
| @@ -862,6 +841,8 @@ case OP_Halt: {
|
| ** as the p2 of the calling OP_Program. */
|
| pc = p->aOp[pc].p2-1;
|
| }
|
| + aOp = p->aOp;
|
| + aMem = p->aMem;
|
| break;
|
| }
|
|
|
| @@ -869,13 +850,21 @@ case OP_Halt: {
|
| 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);
|
| }
|
| rc = sqlite3VdbeHalt(p);
|
| - assert( rc==SQLITE_BUSY || rc==SQLITE_OK );
|
| + 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 );
|
| rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
|
| }
|
| goto vdbe_return;
|
| @@ -886,7 +875,6 @@ case OP_Halt: {
|
| ** The 32-bit integer value P1 is written into register P2.
|
| */
|
| case OP_Integer: { /* out2-prerelease */
|
| - pOut->flags = MEM_Int;
|
| pOut->u.i = pOp->p1;
|
| break;
|
| }
|
| @@ -898,11 +886,11 @@ case OP_Integer: { /* out2-prerelease */
|
| */
|
| case OP_Int64: { /* out2-prerelease */
|
| assert( pOp->p4.pI64!=0 );
|
| - pOut->flags = MEM_Int;
|
| pOut->u.i = *pOp->p4.pI64;
|
| break;
|
| }
|
|
|
| +#ifndef SQLITE_OMIT_FLOATING_POINT
|
| /* Opcode: Real * P2 * P4 *
|
| **
|
| ** P4 is a pointer to a 64-bit floating point value.
|
| @@ -914,6 +902,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
| pOut->r = *pOp->p4.pReal;
|
| break;
|
| }
|
| +#endif
|
|
|
| /* Opcode: String8 * P2 * P4 *
|
| **
|
| @@ -968,6 +957,7 @@ case OP_String: { /* out2-prerelease */
|
| ** Write a NULL into register P2.
|
| */
|
| case OP_Null: { /* out2-prerelease */
|
| + pOut->flags = MEM_Null;
|
| break;
|
| }
|
|
|
| @@ -975,11 +965,7 @@ case OP_Null: { /* out2-prerelease */
|
| /* Opcode: Blob P1 P2 * P4
|
| **
|
| ** P4 points to a blob of data P1 bytes long. Store this
|
| -** blob in register P2. This instruction is not coded directly
|
| -** by the compiler. Instead, the compiler layer specifies
|
| -** an OP_HexBlob opcode, with the hex string representation of
|
| -** the blob as P4. This opcode is transformed to an OP_Blob
|
| -** the first time it is executed.
|
| +** blob in register P2.
|
| */
|
| case OP_Blob: { /* out2-prerelease */
|
| assert( pOp->p1 <= SQLITE_MAX_LENGTH );
|
| @@ -989,38 +975,23 @@ case OP_Blob: { /* out2-prerelease */
|
| break;
|
| }
|
|
|
| -/* Opcode: Variable P1 P2 P3 P4 *
|
| +/* Opcode: Variable P1 P2 * P4 *
|
| **
|
| -** Transfer the values of bound parameters P1..P1+P3-1 into registers
|
| -** P2..P2+P3-1.
|
| +** Transfer the values of bound parameter P1 into register P2
|
| **
|
| ** If the parameter is named, then its name appears in P4 and P3==1.
|
| ** The P4 value is used by sqlite3_bind_parameter_name().
|
| */
|
| -case OP_Variable: {
|
| - int p1; /* Variable to copy from */
|
| - int p2; /* Register to copy to */
|
| - int n; /* Number of values left to copy */
|
| +case OP_Variable: { /* out2-prerelease */
|
| Mem *pVar; /* Value being transferred */
|
|
|
| - p1 = pOp->p1 - 1;
|
| - p2 = pOp->p2;
|
| - n = pOp->p3;
|
| - assert( p1>=0 && p1+n<=p->nVar );
|
| - assert( p2>=1 && p2+n-1<=p->nMem );
|
| - assert( pOp->p4.z==0 || pOp->p3==1 );
|
| -
|
| - while( n-- > 0 ){
|
| - pVar = &p->aVar[p1++];
|
| - if( sqlite3VdbeMemTooBig(pVar) ){
|
| - goto too_big;
|
| - }
|
| - pOut = &p->aMem[p2++];
|
| - sqlite3VdbeMemReleaseExternal(pOut);
|
| - pOut->flags = MEM_Null;
|
| - sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
|
| - UPDATE_MAX_BLOBSIZE(pOut);
|
| + assert( pOp->p1>0 && pOp->p1<=p->nVar );
|
| + pVar = &p->aVar[pOp->p1 - 1];
|
| + if( sqlite3VdbeMemTooBig(pVar) ){
|
| + goto too_big;
|
| }
|
| + sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
|
| + UPDATE_MAX_BLOBSIZE(pOut);
|
| break;
|
| }
|
|
|
| @@ -1043,11 +1014,13 @@ case OP_Move: {
|
| assert( n>0 && p1>0 && p2>0 );
|
| assert( p1+n<=p2 || p2+n<=p1 );
|
|
|
| - pIn1 = &p->aMem[p1];
|
| - pOut = &p->aMem[p2];
|
| + pIn1 = &aMem[p1];
|
| + pOut = &aMem[p2];
|
| while( n-- ){
|
| - assert( pOut<=&p->aMem[p->nMem] );
|
| - assert( pIn1<=&p->aMem[p->nMem] );
|
| + assert( pOut<=&aMem[p->nMem] );
|
| + assert( pIn1<=&aMem[p->nMem] );
|
| + assert( memIsValid(pIn1) );
|
| + memAboutToChange(p, pOut);
|
| zMalloc = pOut->zMalloc;
|
| pOut->zMalloc = 0;
|
| sqlite3VdbeMemMove(pOut, pIn1);
|
| @@ -1066,10 +1039,9 @@ case OP_Move: {
|
| ** 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 */
|
| - assert( pOp->p2>0 );
|
| - assert( pOp->p2<=p->nMem );
|
| - pOut = &p->aMem[pOp->p2];
|
| +case OP_Copy: { /* in1, out2 */
|
| + pIn1 = &aMem[pOp->p1];
|
| + pOut = &aMem[pOp->p2];
|
| assert( pOut!=pIn1 );
|
| sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
|
| Deephemeralize(pOut);
|
| @@ -1089,13 +1061,14 @@ case OP_Copy: { /* in1 */
|
| ** during the lifetime of the copy. Use OP_Copy to make a complete
|
| ** copy.
|
| */
|
| -case OP_SCopy: { /* in1 */
|
| - REGISTER_TRACE(pOp->p1, pIn1);
|
| - assert( pOp->p2>0 );
|
| - assert( pOp->p2<=p->nMem );
|
| - pOut = &p->aMem[pOp->p2];
|
| +case OP_SCopy: { /* in1, out2 */
|
| + pIn1 = &aMem[pOp->p1];
|
| + pOut = &aMem[pOp->p2];
|
| assert( pOut!=pIn1 );
|
| sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
|
| +#ifdef SQLITE_DEBUG
|
| + if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
|
| +#endif
|
| REGISTER_TRACE(pOp->p2, pOut);
|
| break;
|
| }
|
| @@ -1115,6 +1088,15 @@ case OP_ResultRow: {
|
| assert( pOp->p1>0 );
|
| assert( pOp->p1+pOp->p2<=p->nMem+1 );
|
|
|
| + /* If this statement has violated immediate foreign key constraints, do
|
| + ** not return the number of rows modified. And do not RELEASE the statement
|
| + ** transaction. It needs to be rolled back. */
|
| + if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){
|
| + assert( db->flags&SQLITE_CountRows );
|
| + assert( p->usesStmtJournal );
|
| + break;
|
| + }
|
| +
|
| /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then
|
| ** DML statements invoke this opcode to return the number of rows
|
| ** modified to the user. This is the only way that a VM that
|
| @@ -1143,10 +1125,14 @@ case OP_ResultRow: {
|
| ** and have an assigned type. The results are de-ephemeralized as
|
| ** as side effect.
|
| */
|
| - pMem = p->pResultSet = &p->aMem[pOp->p1];
|
| + pMem = p->pResultSet = &aMem[pOp->p1];
|
| for(i=0; i<pOp->p2; i++){
|
| + assert( memIsValid(&pMem[i]) );
|
| + Deephemeralize(&pMem[i]);
|
| + assert( (pMem[i].flags & MEM_Ephem)==0
|
| + || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
|
| sqlite3VdbeMemNulTerminate(&pMem[i]);
|
| - storeTypeInfo(&pMem[i], encoding);
|
| + sqlite3VdbeMemStoreType(&pMem[i]);
|
| REGISTER_TRACE(pOp->p1+i, &pMem[i]);
|
| }
|
| if( db->mallocFailed ) goto no_mem;
|
| @@ -1173,6 +1159,9 @@ case OP_ResultRow: {
|
| case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
|
| i64 nByte;
|
|
|
| + pIn1 = &aMem[pOp->p1];
|
| + pIn2 = &aMem[pOp->p2];
|
| + pOut = &aMem[pOp->p3];
|
| assert( pIn1!=pOut );
|
| if( (pIn1->flags | pIn2->flags) & MEM_Null ){
|
| sqlite3VdbeMemSetNull(pOut);
|
| @@ -1246,27 +1235,23 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
| double rA; /* Real value of left operand */
|
| double rB; /* Real value of right operand */
|
|
|
| + pIn1 = &aMem[pOp->p1];
|
| applyNumericAffinity(pIn1);
|
| + pIn2 = &aMem[pOp->p2];
|
| applyNumericAffinity(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 ){
|
| iA = pIn1->u.i;
|
| iB = pIn2->u.i;
|
| switch( pOp->opcode ){
|
| - case OP_Add: iB += iA; break;
|
| - case OP_Subtract: iB -= iA; break;
|
| - case OP_Multiply: iB *= iA; break;
|
| + case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
|
| + case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break;
|
| + case OP_Multiply: if( sqlite3MulInt64(&iB,iA) ) goto fp_math; break;
|
| case OP_Divide: {
|
| if( iA==0 ) goto arithmetic_result_is_null;
|
| - /* Dividing the largest possible negative 64-bit integer (1<<63) by
|
| - ** -1 returns an integer too large to store in a 64-bit data-type. On
|
| - ** some architectures, the value overflows to (1<<63). On others,
|
| - ** a SIGFPE is issued. The following statement normalizes this
|
| - ** behavior so that all architectures behave as if integer
|
| - ** overflow occurred.
|
| - */
|
| - if( iA==-1 && iB==SMALLEST_INT64 ) iA = 1;
|
| + if( iA==-1 && iB==SMALLEST_INT64 ) goto fp_math;
|
| iB /= iA;
|
| break;
|
| }
|
| @@ -1280,6 +1265,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
| pOut->u.i = iB;
|
| MemSetTypeFlag(pOut, MEM_Int);
|
| }else{
|
| +fp_math:
|
| rA = sqlite3VdbeRealValue(pIn1);
|
| rB = sqlite3VdbeRealValue(pIn2);
|
| switch( pOp->opcode ){
|
| @@ -1301,6 +1287,10 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
| break;
|
| }
|
| }
|
| +#ifdef SQLITE_OMIT_FLOATING_POINT
|
| + pOut->u.i = rB;
|
| + MemSetTypeFlag(pOut, MEM_Int);
|
| +#else
|
| if( sqlite3IsNaN(rB) ){
|
| goto arithmetic_result_is_null;
|
| }
|
| @@ -1309,6 +1299,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
| if( (flags & MEM_Real)==0 ){
|
| sqlite3VdbeIntegerAffinity(pOut);
|
| }
|
| +#endif
|
| }
|
| break;
|
|
|
| @@ -1359,14 +1350,19 @@ 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( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
|
| assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
|
| - pArg = &p->aMem[pOp->p2];
|
| + pArg = &aMem[pOp->p2];
|
| for(i=0; i<n; i++, pArg++){
|
| + assert( memIsValid(pArg) );
|
| apVal[i] = pArg;
|
| - storeTypeInfo(pArg, encoding);
|
| - REGISTER_TRACE(pOp->p2, pArg);
|
| + Deephemeralize(pArg);
|
| + sqlite3VdbeMemStoreType(pArg);
|
| + REGISTER_TRACE(pOp->p2+i, pArg);
|
| }
|
|
|
| assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
|
| @@ -1378,8 +1374,6 @@ case OP_Function: {
|
| ctx.pFunc = ctx.pVdbeFunc->pFunc;
|
| }
|
|
|
| - assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
| - pOut = &p->aMem[pOp->p3];
|
| ctx.s.flags = MEM_Null;
|
| ctx.s.db = db;
|
| ctx.s.xDel = 0;
|
| @@ -1394,26 +1388,17 @@ case OP_Function: {
|
|
|
| ctx.isError = 0;
|
| if( ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
|
| - assert( pOp>p->aOp );
|
| + assert( pOp>aOp );
|
| assert( pOp[-1].p4type==P4_COLLSEQ );
|
| assert( pOp[-1].opcode==OP_CollSeq );
|
| ctx.pColl = pOp[-1].p4.pColl;
|
| }
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| - (*ctx.pFunc->xFunc)(&ctx, n, apVal);
|
| - if( sqlite3SafetyOn(db) ){
|
| - sqlite3VdbeMemRelease(&ctx.s);
|
| - goto abort_due_to_misuse;
|
| - }
|
| + (*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.
|
| - **
|
| - ** Note: Maybe MemRelease() should be called if sqlite3SafetyOn()
|
| - ** fails also (the if(...) statement above). But if people are
|
| - ** misusing sqlite, they have bigger problems than a leaked value.
|
| */
|
| sqlite3VdbeMemRelease(&ctx.s);
|
| goto no_mem;
|
| @@ -1440,6 +1425,15 @@ case OP_Function: {
|
| if( sqlite3VdbeMemTooBig(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);
|
| break;
|
| @@ -1460,7 +1454,7 @@ case OP_Function: {
|
| /* Opcode: ShiftLeft P1 P2 P3 * *
|
| **
|
| ** Shift the integer value in register P2 to the left by the
|
| -** number of bits specified by the integer in regiser P1.
|
| +** number of bits specified by the integer in register P1.
|
| ** Store the result in register P3.
|
| ** If either input is NULL, the result is NULL.
|
| */
|
| @@ -1475,23 +1469,50 @@ case OP_BitAnd: /* same as TK_BITAND, in1, in2, out3 */
|
| case OP_BitOr: /* same as TK_BITOR, in1, in2, out3 */
|
| case OP_ShiftLeft: /* same as TK_LSHIFT, in1, in2, out3 */
|
| case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
|
| - i64 a;
|
| - i64 b;
|
| -
|
| + i64 iA;
|
| + u64 uA;
|
| + i64 iB;
|
| + u8 op;
|
| +
|
| + pIn1 = &aMem[pOp->p1];
|
| + pIn2 = &aMem[pOp->p2];
|
| + pOut = &aMem[pOp->p3];
|
| if( (pIn1->flags | pIn2->flags) & MEM_Null ){
|
| sqlite3VdbeMemSetNull(pOut);
|
| break;
|
| }
|
| - a = sqlite3VdbeIntValue(pIn2);
|
| - b = sqlite3VdbeIntValue(pIn1);
|
| - switch( pOp->opcode ){
|
| - case OP_BitAnd: a &= b; break;
|
| - case OP_BitOr: a |= b; break;
|
| - case OP_ShiftLeft: a <<= b; break;
|
| - default: assert( pOp->opcode==OP_ShiftRight );
|
| - a >>= b; break;
|
| + iA = sqlite3VdbeIntValue(pIn2);
|
| + iB = sqlite3VdbeIntValue(pIn1);
|
| + op = pOp->opcode;
|
| + if( op==OP_BitAnd ){
|
| + iA &= iB;
|
| + }else if( op==OP_BitOr ){
|
| + iA |= iB;
|
| + }else if( iB!=0 ){
|
| + assert( op==OP_ShiftRight || op==OP_ShiftLeft );
|
| +
|
| + /* If shifting by a negative amount, shift in the other direction */
|
| + if( iB<0 ){
|
| + assert( OP_ShiftRight==OP_ShiftLeft+1 );
|
| + op = 2*OP_ShiftLeft + 1 - op;
|
| + iB = iB>(-64) ? -iB : 64;
|
| + }
|
| +
|
| + if( iB>=64 ){
|
| + iA = (iA>=0 || op==OP_ShiftLeft) ? 0 : -1;
|
| + }else{
|
| + memcpy(&uA, &iA, sizeof(uA));
|
| + if( op==OP_ShiftLeft ){
|
| + uA <<= iB;
|
| + }else{
|
| + uA >>= iB;
|
| + /* Sign-extend on a right shift of a negative number */
|
| + if( iA<0 ) uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-iB);
|
| + }
|
| + memcpy(&iA, &uA, sizeof(iA));
|
| + }
|
| }
|
| - pOut->u.i = a;
|
| + pOut->u.i = iA;
|
| MemSetTypeFlag(pOut, MEM_Int);
|
| break;
|
| }
|
| @@ -1504,6 +1525,8 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
|
| ** To force any register to be an integer, just add 0.
|
| */
|
| case OP_AddImm: { /* in1 */
|
| + pIn1 = &aMem[pOp->p1];
|
| + memAboutToChange(p, pIn1);
|
| sqlite3VdbeMemIntegerify(pIn1);
|
| pIn1->u.i += pOp->p2;
|
| break;
|
| @@ -1517,6 +1540,7 @@ case OP_AddImm: { /* in1 */
|
| ** raise an SQLITE_MISMATCH exception.
|
| */
|
| 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 ){
|
| @@ -1531,6 +1555,7 @@ case OP_MustBeInt: { /* jump, in1 */
|
| break;
|
| }
|
|
|
| +#ifndef SQLITE_OMIT_FLOATING_POINT
|
| /* Opcode: RealAffinity P1 * * * *
|
| **
|
| ** If register P1 holds an integer convert it to a real value.
|
| @@ -1541,11 +1566,13 @@ case OP_MustBeInt: { /* jump, in1 */
|
| ** to have only a real value.
|
| */
|
| case OP_RealAffinity: { /* in1 */
|
| + pIn1 = &aMem[pOp->p1];
|
| if( pIn1->flags & MEM_Int ){
|
| sqlite3VdbeMemRealify(pIn1);
|
| }
|
| break;
|
| }
|
| +#endif
|
|
|
| #ifndef SQLITE_OMIT_CAST
|
| /* Opcode: ToText P1 * * * *
|
| @@ -1558,6 +1585,8 @@ case OP_RealAffinity: { /* in1 */
|
| ** A NULL value is not changed by this routine. It remains NULL.
|
| */
|
| case OP_ToText: { /* same as TK_TO_TEXT, in1 */
|
| + 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;
|
| @@ -1579,6 +1608,7 @@ case OP_ToText: { /* same as TK_TO_TEXT, in1 */
|
| ** 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);
|
| @@ -1602,16 +1632,15 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
|
| ** A NULL value is not changed by this routine. It remains NULL.
|
| */
|
| case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
|
| - if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
|
| - sqlite3VdbeMemNumerify(pIn1);
|
| - }
|
| + pIn1 = &aMem[pOp->p1];
|
| + sqlite3VdbeMemNumerify(pIn1);
|
| break;
|
| }
|
| #endif /* SQLITE_OMIT_CAST */
|
|
|
| /* Opcode: ToInt P1 * * * *
|
| **
|
| -** Force the value in register P1 be an integer. If
|
| +** 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.
|
| @@ -1619,13 +1648,14 @@ case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
|
| ** 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;
|
| }
|
|
|
| -#ifndef SQLITE_OMIT_CAST
|
| +#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.
|
| @@ -1636,12 +1666,14 @@ case OP_ToInt: { /* same as TK_TO_INT, in1 */
|
| ** 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 /* SQLITE_OMIT_CAST */
|
| +#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */
|
|
|
| /* Opcode: Lt P1 P2 P3 P4 P5
|
| **
|
| @@ -1650,7 +1682,7 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
|
| **
|
| ** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
|
| ** reg(P3) is NULL then take the jump. If the SQLITE_JUMPIFNULL
|
| -** bit is clear then fall thru if either operand is NULL.
|
| +** bit is clear then fall through if either operand is NULL.
|
| **
|
| ** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
|
| ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
|
| @@ -1678,12 +1710,24 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
|
| ** 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
|
| ** additional information.
|
| +**
|
| +** 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
|
| +** the SQLITE_NULLEQ flag were omitted from P5.
|
| */
|
| /* Opcode: Eq P1 P2 P3 P4 P5
|
| **
|
| ** This works just like the Lt opcode except that the jump is taken if
|
| ** the operands in registers P1 and P3 are equal.
|
| ** See the Lt opcode for additional information.
|
| +**
|
| +** 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
|
| +** the SQLITE_NULLEQ flag were omitted from P5.
|
| */
|
| /* Opcode: Le P1 P2 P3 P4 P5
|
| **
|
| @@ -1709,37 +1753,52 @@ case OP_Lt: /* same as TK_LT, jump, in1, in3 */
|
| case OP_Le: /* same as TK_LE, jump, in1, in3 */
|
| case OP_Gt: /* same as TK_GT, jump, in1, in3 */
|
| case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
| - int flags;
|
| - int res;
|
| - char affinity;
|
| -
|
| - flags = pIn1->flags|pIn3->flags;
|
| -
|
| - if( flags&MEM_Null ){
|
| - /* If either operand is NULL then the result is always NULL.
|
| - ** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
|
| - */
|
| - if( pOp->p5 & SQLITE_STOREP2 ){
|
| - pOut = &p->aMem[pOp->p2];
|
| - MemSetTypeFlag(pOut, MEM_Null);
|
| - REGISTER_TRACE(pOp->p2, pOut);
|
| - }else if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
| - pc = pOp->p2-1;
|
| + int res; /* Result of the comparison of pIn1 against pIn3 */
|
| + char affinity; /* Affinity to use for comparison */
|
| + u16 flags1; /* Copy of initial value of pIn1->flags */
|
| + u16 flags3; /* Copy of initial value of pIn3->flags */
|
| +
|
| + pIn1 = &aMem[pOp->p1];
|
| + pIn3 = &aMem[pOp->p3];
|
| + flags1 = pIn1->flags;
|
| + flags3 = pIn3->flags;
|
| + if( (pIn1->flags | pIn3->flags)&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
|
| + ** OP_Eq or OP_Ne) then take the jump or not depending on whether
|
| + ** or not both operands are null.
|
| + */
|
| + assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
|
| + res = (pIn1->flags & pIn3->flags & MEM_Null)==0;
|
| + }else{
|
| + /* SQLITE_NULLEQ is clear and at least one operand is NULL,
|
| + ** then the result is always NULL.
|
| + ** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
|
| + */
|
| + if( pOp->p5 & SQLITE_STOREP2 ){
|
| + pOut = &aMem[pOp->p2];
|
| + MemSetTypeFlag(pOut, MEM_Null);
|
| + REGISTER_TRACE(pOp->p2, pOut);
|
| + }else 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;
|
| }
|
| - break;
|
| - }
|
|
|
| - affinity = pOp->p5 & SQLITE_AFF_MASK;
|
| - if( affinity ){
|
| - applyAffinity(pIn1, affinity, encoding);
|
| - applyAffinity(pIn3, affinity, encoding);
|
| - if( db->mallocFailed ) goto no_mem;
|
| + assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
|
| + ExpandBlob(pIn1);
|
| + ExpandBlob(pIn3);
|
| + res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
|
| }
|
| -
|
| - assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
|
| - ExpandBlob(pIn1);
|
| - ExpandBlob(pIn3);
|
| - res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
|
| switch( pOp->opcode ){
|
| case OP_Eq: res = res==0; break;
|
| case OP_Ne: res = res!=0; break;
|
| @@ -1750,13 +1809,18 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
| }
|
|
|
| if( pOp->p5 & SQLITE_STOREP2 ){
|
| - pOut = &p->aMem[pOp->p2];
|
| + pOut = &aMem[pOp->p2];
|
| + memAboutToChange(p, pOut);
|
| MemSetTypeFlag(pOut, MEM_Int);
|
| pOut->u.i = res;
|
| REGISTER_TRACE(pOp->p2, pOut);
|
| }else 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);
|
| break;
|
| }
|
|
|
| @@ -1778,8 +1842,8 @@ case OP_Permutation: {
|
|
|
| /* Opcode: Compare P1 P2 P3 P4 *
|
| **
|
| -** Compare to vectors of registers in reg(P1)..reg(P1+P3-1) (all this
|
| -** one "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
|
| +** 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.
|
| **
|
| ** P4 is a KeyInfo structure that defines collating sequences and sort
|
| @@ -1805,17 +1869,28 @@ case OP_Compare: {
|
| assert( n>0 );
|
| assert( pKeyInfo!=0 );
|
| p1 = pOp->p1;
|
| - assert( p1>0 && p1+n<=p->nMem+1 );
|
| p2 = pOp->p2;
|
| - assert( p2>0 && p2+n<=p->nMem+1 );
|
| +#if SQLITE_DEBUG
|
| + 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 );
|
| + }else{
|
| + assert( p1>0 && p1+n<=p->nMem+1 );
|
| + assert( p2>0 && p2+n<=p->nMem+1 );
|
| + }
|
| +#endif /* SQLITE_DEBUG */
|
| for(i=0; i<n; i++){
|
| idx = aPermute ? aPermute[i] : i;
|
| - REGISTER_TRACE(p1+idx, &p->aMem[p1+idx]);
|
| - REGISTER_TRACE(p2+idx, &p->aMem[p2+idx]);
|
| + assert( memIsValid(&aMem[p1+idx]) );
|
| + assert( memIsValid(&aMem[p2+idx]) );
|
| + REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
|
| + REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
|
| assert( i<pKeyInfo->nField );
|
| pColl = pKeyInfo->aColl[i];
|
| bRev = pKeyInfo->aSortOrder[i];
|
| - iCompare = sqlite3MemCompare(&p->aMem[p1+idx], &p->aMem[p2+idx], pColl);
|
| + iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
|
| if( iCompare ){
|
| if( bRev ) iCompare = -iCompare;
|
| break;
|
| @@ -1865,11 +1940,13 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
|
| int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
|
| int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
|
|
|
| + pIn1 = &aMem[pOp->p1];
|
| if( pIn1->flags & MEM_Null ){
|
| v1 = 2;
|
| }else{
|
| v1 = sqlite3VdbeIntValue(pIn1)!=0;
|
| }
|
| + pIn2 = &aMem[pOp->p2];
|
| if( pIn2->flags & MEM_Null ){
|
| v2 = 2;
|
| }else{
|
| @@ -1882,6 +1959,7 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
|
| static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
|
| v1 = or_logic[v1*3+v2];
|
| }
|
| + pOut = &aMem[pOp->p3];
|
| if( v1==2 ){
|
| MemSetTypeFlag(pOut, MEM_Null);
|
| }else{
|
| @@ -1897,8 +1975,9 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
|
| ** boolean complement in register P2. If the value in register P1 is
|
| ** NULL, then a NULL is stored in P2.
|
| */
|
| -case OP_Not: { /* same as TK_NOT, in1 */
|
| - pOut = &p->aMem[pOp->p2];
|
| +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{
|
| @@ -1913,8 +1992,9 @@ case OP_Not: { /* same as TK_NOT, in1 */
|
| ** ones-complement of the P1 value into register P2. If P1 holds
|
| ** a NULL then store a NULL in P2.
|
| */
|
| -case OP_BitNot: { /* same as TK_BITNOT, in1 */
|
| - pOut = &p->aMem[pOp->p2];
|
| +case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
| + pIn1 = &aMem[pOp->p1];
|
| + pOut = &aMem[pOp->p2];
|
| if( pIn1->flags & MEM_Null ){
|
| sqlite3VdbeMemSetNull(pOut);
|
| }else{
|
| @@ -1938,6 +2018,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1 */
|
| case OP_If: /* jump, in1 */
|
| case OP_IfNot: { /* jump, in1 */
|
| int c;
|
| + pIn1 = &aMem[pOp->p1];
|
| if( pIn1->flags & MEM_Null ){
|
| c = pOp->p3;
|
| }else{
|
| @@ -1959,6 +2040,7 @@ case OP_IfNot: { /* jump, in1 */
|
| ** Jump to P2 if the value in register P1 is NULL.
|
| */
|
| case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
|
| + pIn1 = &aMem[pOp->p1];
|
| if( (pIn1->flags & MEM_Null)!=0 ){
|
| pc = pOp->p2 - 1;
|
| }
|
| @@ -1970,6 +2052,7 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
|
| ** 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];
|
| if( (pIn1->flags & MEM_Null)==0 ){
|
| pc = pOp->p2 - 1;
|
| }
|
| @@ -2014,7 +2097,7 @@ case OP_Column: {
|
| u8 *zIdx; /* Index into header */
|
| u8 *zEndHdr; /* Pointer to first byte after the header */
|
| u32 offset; /* Offset into the data */
|
| - u64 offset64; /* 64-bit offset. 64 bits needed to catch overflow */
|
| + 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 */
|
| Mem *pReg; /* PseudoTable input register */
|
| @@ -2026,7 +2109,8 @@ case OP_Column: {
|
| memset(&sMem, 0, sizeof(sMem));
|
| assert( p1<p->nCursor );
|
| assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
| - pDest = &p->aMem[pOp->p3];
|
| + pDest = &aMem[pOp->p3];
|
| + memAboutToChange(p, pDest);
|
| MemSetTypeFlag(pDest, MEM_Null);
|
| zRec = 0;
|
|
|
| @@ -2072,8 +2156,9 @@ case OP_Column: {
|
| assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
|
| }
|
| }else if( pC->pseudoTableReg>0 ){
|
| - pReg = &p->aMem[pC->pseudoTableReg];
|
| + 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;
|
| @@ -2189,12 +2274,16 @@ case OP_Column: {
|
| ** 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
|
| */
|
| - offset64 = offset;
|
| for(i=0; i<nField; i++){
|
| if( zIdx<zEndHdr ){
|
| - aOffset[i] = (u32)offset64;
|
| + aOffset[i] = offset;
|
| zIdx += getVarint32(zIdx, aType[i]);
|
| - offset64 += sqlite3VdbeSerialTypeLen(aType[i]);
|
| + szField = sqlite3VdbeSerialTypeLen(aType[i]);
|
| + offset += szField;
|
| + if( offset<szField ){ /* True if offset overflows */
|
| + zIdx = &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
|
| @@ -2214,8 +2303,8 @@ case OP_Column: {
|
| ** of the record (when all fields present), then we must be dealing
|
| ** with a corrupt database.
|
| */
|
| - if( (zIdx > zEndHdr)|| (offset64 > payloadSize)
|
| - || (zIdx==zEndHdr && offset64!=(u64)payloadSize) ){
|
| + if( (zIdx > zEndHdr) || (offset > payloadSize)
|
| + || (zIdx==zEndHdr && offset!=payloadSize) ){
|
| rc = SQLITE_CORRUPT_BKPT;
|
| goto op_column_out;
|
| }
|
| @@ -2283,29 +2372,28 @@ op_column_out:
|
| ** memory cell in the range.
|
| */
|
| case OP_Affinity: {
|
| - char *zAffinity; /* The affinity to be applied */
|
| - Mem *pData0; /* First register to which to apply affinity */
|
| - Mem *pLast; /* Last register to which to apply affinity */
|
| - Mem *pRec; /* Current register */
|
| + const char *zAffinity; /* The affinity to be applied */
|
| + char cAff; /* A single character of affinity */
|
|
|
| zAffinity = pOp->p4.z;
|
| - pData0 = &p->aMem[pOp->p1];
|
| - pLast = &pData0[pOp->p2-1];
|
| - for(pRec=pData0; pRec<=pLast; pRec++){
|
| - ExpandBlob(pRec);
|
| - applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
|
| + assert( zAffinity!=0 );
|
| + assert( zAffinity[pOp->p2]==0 );
|
| + pIn1 = &aMem[pOp->p1];
|
| + while( (cAff = *(zAffinity++))!=0 ){
|
| + assert( pIn1 <= &p->aMem[p->nMem] );
|
| + assert( memIsValid(pIn1) );
|
| + ExpandBlob(pIn1);
|
| + applyAffinity(pIn1, cAff, encoding);
|
| + pIn1++;
|
| }
|
| break;
|
| }
|
|
|
| /* Opcode: MakeRecord P1 P2 P3 P4 *
|
| **
|
| -** Convert P2 registers beginning with P1 into a single entry
|
| -** suitable for use as a data record in a database table or as a key
|
| -** in an index. The details of the format are irrelevant as long as
|
| -** the OP_Column opcode can decode the record later.
|
| -** Refer to source code comments for the details of the record
|
| -** format.
|
| +** Convert P2 registers beginning with P1 into the [record format]
|
| +** use as a data record in a database table or as a key
|
| +** in an index. The OP_Column opcode can decode the record later.
|
| **
|
| ** P4 may be a string that is P2 characters long. The nth character of the
|
| ** string indicates the column affinity that should be used for the nth
|
| @@ -2350,20 +2438,25 @@ case OP_MakeRecord: {
|
| */
|
| nData = 0; /* Number of bytes of data space */
|
| nHdr = 0; /* Number of bytes of header space */
|
| - nByte = 0; /* Data space required for this record */
|
| 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 );
|
| - pData0 = &p->aMem[nField];
|
| + pData0 = &aMem[nField];
|
| nField = pOp->p2;
|
| pLast = &pData0[nField-1];
|
| file_format = p->minWriteFileFormat;
|
|
|
| + /* Identify the output register */
|
| + assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
|
| + pOut = &aMem[pOp->p3];
|
| + memAboutToChange(p, pOut);
|
| +
|
| /* 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++){
|
| + assert( memIsValid(pRec) );
|
| if( zAffinity ){
|
| applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
|
| }
|
| @@ -2398,8 +2491,6 @@ case OP_MakeRecord: {
|
| ** be one of the input registers (because the following call to
|
| ** sqlite3VdbeMemGrow() could clobber the value before it is used).
|
| */
|
| - assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
|
| - pOut = &p->aMem[pOp->p3];
|
| if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){
|
| goto no_mem;
|
| }
|
| @@ -2446,7 +2537,6 @@ case OP_Count: { /* out2-prerelease */
|
| }else{
|
| nEntry = 0;
|
| }
|
| - pOut->flags = MEM_Int;
|
| pOut->u.i = nEntry;
|
| break;
|
| }
|
| @@ -2508,6 +2598,7 @@ case OP_Savepoint: {
|
| /* Link the new savepoint into the database handle's list. */
|
| pNew->pNext = db->pSavepoint;
|
| db->pSavepoint = pNew;
|
| + pNew->nDeferredCons = db->nDeferredCons;
|
| }
|
| }
|
| }else{
|
| @@ -2545,6 +2636,9 @@ case OP_Savepoint: {
|
| */
|
| int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint;
|
| if( isTransaction && p1==SAVEPOINT_RELEASE ){
|
| + if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
|
| + goto vdbe_return;
|
| + }
|
| db->autoCommit = 1;
|
| if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
|
| p->pc = pc;
|
| @@ -2564,7 +2658,8 @@ case OP_Savepoint: {
|
| }
|
| if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
|
| sqlite3ExpirePreparedStatements(db);
|
| - sqlite3ResetInternalSchema(db, 0);
|
| + sqlite3ResetInternalSchema(db, -1);
|
| + db->flags = (db->flags | SQLITE_InternChanges);
|
| }
|
| }
|
|
|
| @@ -2577,7 +2672,10 @@ case OP_Savepoint: {
|
| db->nSavepoint--;
|
| }
|
|
|
| - /* If it is a RELEASE, then destroy the savepoint being operated on too */
|
| + /* If it is a RELEASE, then destroy the savepoint being operated on
|
| + ** too. If it is a ROLLBACK TO, then set the number of deferred
|
| + ** constraint violations present in the database to the value stored
|
| + ** when the savepoint was created. */
|
| if( p1==SAVEPOINT_RELEASE ){
|
| assert( pSavepoint==db->pSavepoint );
|
| db->pSavepoint = pSavepoint->pNext;
|
| @@ -2585,6 +2683,8 @@ case OP_Savepoint: {
|
| if( !isTransaction ){
|
| db->nSavepoint--;
|
| }
|
| + }else{
|
| + db->nDeferredCons = pSavepoint->nDeferredCons;
|
| }
|
| }
|
| }
|
| @@ -2633,6 +2733,8 @@ case OP_AutoCommit: {
|
| assert( desiredAutoCommit==1 );
|
| sqlite3RollbackAll(db);
|
| db->autoCommit = 1;
|
| + }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
|
| + goto vdbe_return;
|
| }else{
|
| db->autoCommit = (u8)desiredAutoCommit;
|
| if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
|
| @@ -2696,7 +2798,7 @@ case OP_Transaction: {
|
| Btree *pBt;
|
|
|
| assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
| - assert( (p->btreeMask & (1<<pOp->p1))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
| pBt = db->aDb[pOp->p1].pBt;
|
|
|
| if( pBt ){
|
| @@ -2706,7 +2808,7 @@ case OP_Transaction: {
|
| p->rc = rc = SQLITE_BUSY;
|
| goto vdbe_return;
|
| }
|
| - if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){
|
| + if( rc!=SQLITE_OK ){
|
| goto abort_due_to_error;
|
| }
|
|
|
| @@ -2720,6 +2822,11 @@ case OP_Transaction: {
|
| p->iStatement = db->nSavepoint + db->nStatement;
|
| }
|
| 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;
|
| }
|
| }
|
| break;
|
| @@ -2747,11 +2854,10 @@ case OP_ReadCookie: { /* out2-prerelease */
|
| assert( pOp->p3<SQLITE_N_BTREE_META );
|
| assert( iDb>=0 && iDb<db->nDb );
|
| assert( db->aDb[iDb].pBt!=0 );
|
| - assert( (p->btreeMask & (1<<iDb))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 );
|
|
|
| sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta);
|
| pOut->u.i = iMeta;
|
| - MemSetTypeFlag(pOut, MEM_Int);
|
| break;
|
| }
|
|
|
| @@ -2769,9 +2875,11 @@ case OP_SetCookie: { /* in3 */
|
| Db *pDb;
|
| assert( pOp->p2<SQLITE_N_BTREE_META );
|
| assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
| - assert( (p->btreeMask & (1<<pOp->p1))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
| pDb = &db->aDb[pOp->p1];
|
| assert( pDb->pBt!=0 );
|
| + assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
|
| + pIn3 = &aMem[pOp->p3];
|
| sqlite3VdbeMemIntegerify(pIn3);
|
| /* See note about index shifting on OP_ReadCookie */
|
| rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, (int)pIn3->u.i);
|
| @@ -2787,14 +2895,17 @@ case OP_SetCookie: { /* in3 */
|
| /* Invalidate all prepared statements whenever the TEMP database
|
| ** schema is changed. Ticket #1644 */
|
| sqlite3ExpirePreparedStatements(db);
|
| + p->expired = 0;
|
| }
|
| break;
|
| }
|
|
|
| -/* Opcode: VerifyCookie P1 P2 *
|
| +/* 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.
|
| +** 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.
|
| @@ -2809,16 +2920,20 @@ case OP_SetCookie: { /* in3 */
|
| */
|
| case OP_VerifyCookie: {
|
| int iMeta;
|
| + int iGen;
|
| Btree *pBt;
|
| +
|
| assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
| - assert( (p->btreeMask & (1<<pOp->p1))!=0 );
|
| + 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{
|
| - iMeta = 0;
|
| + iGen = iMeta = 0;
|
| }
|
| - if( iMeta!=pOp->p2 ){
|
| + 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
|
| @@ -2838,7 +2953,7 @@ case OP_VerifyCookie: {
|
| sqlite3ResetInternalSchema(db, pOp->p1);
|
| }
|
|
|
| - sqlite3ExpirePreparedStatements(db);
|
| + p->expired = 1;
|
| rc = SQLITE_SCHEMA;
|
| }
|
| break;
|
| @@ -2904,17 +3019,23 @@ case OP_OpenWrite: {
|
| VdbeCursor *pCur;
|
| Db *pDb;
|
|
|
| + if( p->expired ){
|
| + rc = SQLITE_ABORT;
|
| + break;
|
| + }
|
| +
|
| nField = 0;
|
| pKeyInfo = 0;
|
| p2 = pOp->p2;
|
| iDb = pOp->p3;
|
| assert( iDb>=0 && iDb<db->nDb );
|
| - assert( (p->btreeMask & (1<<iDb))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 );
|
| pDb = &db->aDb[iDb];
|
| pX = pDb->pBt;
|
| assert( pX!=0 );
|
| if( pOp->opcode==OP_OpenWrite ){
|
| wrFlag = 1;
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| if( pDb->pSchema->file_format < p->minWriteFileFormat ){
|
| p->minWriteFileFormat = pDb->pSchema->file_format;
|
| }
|
| @@ -2924,7 +3045,9 @@ case OP_OpenWrite: {
|
| if( pOp->p5 ){
|
| assert( p2>0 );
|
| assert( p2<=p->nMem );
|
| - pIn2 = &p->aMem[p2];
|
| + pIn2 = &aMem[p2];
|
| + assert( memIsValid(pIn2) );
|
| + assert( (pIn2->flags & MEM_Int)!=0 );
|
| sqlite3VdbeMemIntegerify(pIn2);
|
| p2 = (int)pIn2->u.i;
|
| /* The p2 value always comes from a prior OP_CreateTable opcode and
|
| @@ -2947,6 +3070,7 @@ case OP_OpenWrite: {
|
| pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
|
| if( pCur==0 ) goto no_mem;
|
| pCur->nullRow = 1;
|
| + pCur->isOrdered = 1;
|
| rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
|
| pCur->pKeyInfo = pKeyInfo;
|
|
|
| @@ -2973,10 +3097,10 @@ case OP_OpenWrite: {
|
| **
|
| ** Open a new cursor P1 to a transient table.
|
| ** The cursor is always opened read/write even if
|
| -** the main database is read-only. The transient or virtual
|
| +** the main database is read-only. The ephemeral
|
| ** table is deleted automatically when the cursor is closed.
|
| **
|
| -** P2 is the number of columns in the virtual table.
|
| +** P2 is the number of columns in the ephemeral table.
|
| ** The cursor points to a BTree table if P4==0 and to a BTree index
|
| ** 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.
|
| @@ -2987,9 +3111,17 @@ case OP_OpenWrite: {
|
| ** this opcode. Then this opcode was call OpenVirtual. But
|
| ** that created confusion with the whole virtual-table idea.
|
| */
|
| +/* Opcode: OpenAutoindex P1 P2 * P4 *
|
| +**
|
| +** This opcode works the same as OP_OpenEphemeral. It has a
|
| +** different name to distinguish its use. Tables created using
|
| +** by this opcode will be used for automatically created transient
|
| +** indices in joins.
|
| +*/
|
| +case OP_OpenAutoindex:
|
| case OP_OpenEphemeral: {
|
| VdbeCursor *pCx;
|
| - static const int openFlags =
|
| + static const int vfsFlags =
|
| SQLITE_OPEN_READWRITE |
|
| SQLITE_OPEN_CREATE |
|
| SQLITE_OPEN_EXCLUSIVE |
|
| @@ -3000,21 +3132,21 @@ case OP_OpenEphemeral: {
|
| pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
| if( pCx==0 ) goto no_mem;
|
| pCx->nullRow = 1;
|
| - rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags,
|
| - &pCx->pBt);
|
| + rc = sqlite3BtreeOpen(0, db, &pCx->pBt,
|
| + BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
|
| if( rc==SQLITE_OK ){
|
| rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
|
| }
|
| if( rc==SQLITE_OK ){
|
| /* If a transient index is required, create it by calling
|
| - ** sqlite3BtreeCreateTable() with the BTREE_ZERODATA flag before
|
| + ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
|
| ** opening it. If a transient table is required, just use the
|
| - ** automatically created table with root-page 1 (an INTKEY table).
|
| + ** automatically created table with root-page 1 (an BLOB_INTKEY table).
|
| */
|
| if( pOp->p4.pKeyInfo ){
|
| int pgno;
|
| assert( pOp->p4type==P4_KEYINFO );
|
| - rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
|
| + rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY);
|
| if( rc==SQLITE_OK ){
|
| assert( pgno==MASTER_ROOT+1 );
|
| rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1,
|
| @@ -3028,6 +3160,7 @@ case OP_OpenEphemeral: {
|
| pCx->isTable = 1;
|
| }
|
| }
|
| + pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
|
| pCx->isIndex = !pCx->isTable;
|
| break;
|
| }
|
| @@ -3039,7 +3172,7 @@ case OP_OpenEphemeral: {
|
| ** register P2. In other words, cursor P1 becomes an alias for the
|
| ** MEM_Blob content contained in register P2.
|
| **
|
| -** A pseudo-table created by this opcode is used to hold the a single
|
| +** A pseudo-table created by this opcode is used to hold a single
|
| ** row output from the sorter so that the row can be decomposed into
|
| ** individual columns using the OP_Column opcode. The OP_Column opcode
|
| ** is the only cursor opcode that works with a pseudo-table.
|
| @@ -3140,6 +3273,10 @@ 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( pC->isOrdered );
|
| if( pC->pCursor!=0 ){
|
| oc = pOp->opcode;
|
| pC->nullRow = 0;
|
| @@ -3147,6 +3284,7 @@ case OP_SeekGt: { /* jump, in3 */
|
| /* 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;
|
| @@ -3169,12 +3307,12 @@ case OP_SeekGt: { /* jump, in3 */
|
| ** integer. */
|
| res = 1;
|
| if( pIn3->r<0 ){
|
| - if( oc==OP_SeekGt || oc==OP_SeekGe ){
|
| + 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_SeekLt || oc==OP_SeekLe ){
|
| + 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;
|
| }
|
| @@ -3206,12 +3344,25 @@ case OP_SeekGt: { /* jump, in3 */
|
| assert( nField>0 );
|
| r.pKeyInfo = pC->pKeyInfo;
|
| r.nField = (u16)nField;
|
| - if( oc==OP_SeekGt || oc==OP_SeekLe ){
|
| - r.flags = UNPACKED_INCRKEY;
|
| - }else{
|
| - r.flags = 0;
|
| - }
|
| - r.aMem = &p->aMem[pOp->p3];
|
| +
|
| + /* 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;
|
| + ** }
|
| + */
|
| + 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 );
|
| +
|
| + r.aMem = &aMem[pOp->p3];
|
| +#ifdef SQLITE_DEBUG
|
| + { 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;
|
| @@ -3223,7 +3374,7 @@ case OP_SeekGt: { /* jump, in3 */
|
| #ifdef SQLITE_TEST
|
| sqlite3_search_count++;
|
| #endif
|
| - if( oc==OP_SeekGe || oc==OP_SeekGt ){
|
| + 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;
|
| @@ -3276,6 +3427,7 @@ case OP_Seek: { /* in2 */
|
| 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;
|
| @@ -3284,33 +3436,27 @@ case OP_Seek: { /* in2 */
|
| }
|
|
|
|
|
| -/* Opcode: Found P1 P2 P3 * *
|
| -**
|
| -** Register P3 holds a blob constructed by MakeRecord. P1 is an index.
|
| -** If an entry that matches the value in register p3 exists in P1 then
|
| -** jump to P2. If the P3 value does not match any entry in P1
|
| -** then fall thru. The P1 cursor is left pointing at the matching entry
|
| -** if it exists.
|
| -**
|
| -** This instruction is used to implement the IN operator where the
|
| -** left-hand side is a SELECT statement. P1 may be a true index, or it
|
| -** may be a temporary index that holds the results of the SELECT
|
| -** statement. This instruction is also used to implement the
|
| -** DISTINCT keyword in SELECT statements.
|
| +/* Opcode: Found P1 P2 P3 P4 *
|
| **
|
| -** This instruction checks if index P1 contains a record for which
|
| -** the first N serialized values exactly match the N serialized values
|
| -** in the record in register P3, where N is the total number of values in
|
| -** the P3 record (the P3 record is a prefix of the P1 record).
|
| +** 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.
|
| **
|
| -** See also: NotFound, IsUnique, NotExists
|
| +** 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.
|
| */
|
| -/* Opcode: NotFound P1 P2 P3 * *
|
| +/* Opcode: NotFound P1 P2 P3 P4 *
|
| **
|
| -** Register P3 holds a blob constructed by MakeRecord. P1 is
|
| -** an index. If no entry exists in P1 that matches the blob then jump
|
| -** to P2. If an entry does existing, fall through. The cursor is left
|
| -** pointing to the entry that matches.
|
| +** 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
|
| +** is not the prefix of any entry in P1 then a jump is made to P2. If P1
|
| +** does contain an entry whose prefix matches the P3/P4 record then control
|
| +** falls through to the next instruction and P1 is left pointing at the
|
| +** matching entry.
|
| **
|
| ** See also: Found, NotExists, IsUnique
|
| */
|
| @@ -3320,27 +3466,45 @@ case OP_Found: { /* jump, in3 */
|
| VdbeCursor *pC;
|
| int res;
|
| UnpackedRecord *pIdxKey;
|
| + UnpackedRecord r;
|
| char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
|
|
|
| +#ifdef SQLITE_TEST
|
| + 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 );
|
| + pIn3 = &aMem[pOp->p3];
|
| if( ALWAYS(pC->pCursor!=0) ){
|
|
|
| assert( pC->isTable==0 );
|
| - assert( pIn3->flags & MEM_Blob );
|
| - ExpandBlob(pIn3);
|
| - pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z,
|
| - aTempRec, sizeof(aTempRec));
|
| - if( pIdxKey==0 ){
|
| - goto no_mem;
|
| - }
|
| - if( pOp->opcode==OP_Found ){
|
| + if( pOp->p4.i>0 ){
|
| + r.pKeyInfo = pC->pKeyInfo;
|
| + r.nField = (u16)pOp->p4.i;
|
| + r.aMem = pIn3;
|
| +#ifdef SQLITE_DEBUG
|
| + { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
| +#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);
|
| - sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
|
| + if( pOp->p4.i==0 ){
|
| + sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
|
| + }
|
| if( rc!=SQLITE_OK ){
|
| break;
|
| }
|
| @@ -3358,9 +3522,10 @@ case OP_Found: { /* jump, in3 */
|
|
|
| /* Opcode: IsUnique P1 P2 P3 P4 *
|
| **
|
| -** Cursor P1 is open on an index. So it has no data and its key consists
|
| -** of a record generated by OP_MakeRecord where the last field is the
|
| -** rowid of the entry that the index refers to.
|
| +** 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
|
| @@ -3386,11 +3551,12 @@ case OP_IsUnique: { /* jump, in3 */
|
| VdbeCursor *pCx;
|
| BtCursor *pCrsr;
|
| u16 nField;
|
| - Mem *aMem;
|
| + Mem *aMx;
|
| UnpackedRecord r; /* B-Tree index search key */
|
| i64 R; /* Rowid stored in register P3 */
|
|
|
| - aMem = &p->aMem[pOp->p4.i];
|
| + 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 );
|
| @@ -3406,20 +3572,23 @@ case OP_IsUnique: { /* jump, in3 */
|
| /* If any of the values are NULL, take the jump. */
|
| nField = pCx->pKeyInfo->nField;
|
| for(ii=0; ii<nField; ii++){
|
| - if( aMem[ii].flags & MEM_Null ){
|
| + if( aMx[ii].flags & MEM_Null ){
|
| pc = pOp->p2 - 1;
|
| pCrsr = 0;
|
| break;
|
| }
|
| }
|
| - assert( (aMem[nField].flags & MEM_Null)==0 );
|
| + 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 = aMem;
|
| + 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);
|
| @@ -3442,7 +3611,7 @@ case OP_IsUnique: { /* jump, in3 */
|
| **
|
| ** 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 thru. The cursor is left
|
| +** If the record does exist, then fall through. The cursor is left
|
| ** pointing to the record if it exists.
|
| **
|
| ** The difference between this operation and NotFound is that this
|
| @@ -3458,6 +3627,7 @@ case OP_NotExists: { /* jump, in3 */
|
| int res;
|
| u64 iKey;
|
|
|
| + pIn3 = &aMem[pOp->p3];
|
| assert( pIn3->flags & MEM_Int );
|
| assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
| pC = p->apCsr[pOp->p1];
|
| @@ -3501,7 +3671,6 @@ case OP_Sequence: { /* out2-prerelease */
|
| assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
| assert( p->apCsr[pOp->p1]!=0 );
|
| pOut->u.i = p->apCsr[pOp->p1]->seqCount++;
|
| - MemSetTypeFlag(pOut, MEM_Int);
|
| break;
|
| }
|
|
|
| @@ -3550,7 +3719,6 @@ case OP_NewRowid: { /* out2-prerelease */
|
| ** and try again, up to 100 times.
|
| */
|
| assert( pC->isTable );
|
| - cnt = 0;
|
|
|
| #ifdef SQLITE_32BIT_ROWID
|
| # define MAX_ROWID 0x7fffffff
|
| @@ -3570,7 +3738,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
| goto abort_due_to_error;
|
| }
|
| if( res ){
|
| - v = 1;
|
| + v = 1; /* IMP: R-61914-48074 */
|
| }else{
|
| assert( sqlite3BtreeCursorIsValid(pC->pCursor) );
|
| rc = sqlite3BtreeKeySize(pC->pCursor, &v);
|
| @@ -3578,7 +3746,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
| if( v==MAX_ROWID ){
|
| pC->useRandomRowid = 1;
|
| }else{
|
| - v++;
|
| + v++; /* IMP: R-29538-34987 */
|
| }
|
| }
|
| }
|
| @@ -3595,14 +3763,16 @@ case OP_NewRowid: { /* out2-prerelease */
|
| }else{
|
| /* Assert that P3 is a valid memory cell. */
|
| assert( pOp->p3<=p->nMem );
|
| - pMem = &p->aMem[pOp->p3];
|
| + 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;
|
| + rc = SQLITE_FULL; /* IMP: R-12275-61338 */
|
| goto abort_due_to_error;
|
| }
|
| if( v<pMem->u.i+1 ){
|
| @@ -3615,30 +3785,41 @@ case OP_NewRowid: { /* out2-prerelease */
|
| sqlite3BtreeSetCachedRowid(pC->pCursor, v<MAX_ROWID ? v+1 : 0);
|
| }
|
| if( pC->useRandomRowid ){
|
| + /* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the
|
| + ** largest possible integer (9223372036854775807) then the database
|
| + ** engine starts picking positive candidate ROWIDs at random until
|
| + ** 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;
|
| - do{
|
| - if( cnt==0 && (v&0xffffff)==v ){
|
| - v++;
|
| + 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{
|
| - sqlite3_randomness(sizeof(v), &v);
|
| - if( cnt<5 ) v &= 0xffffff;
|
| + v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
|
| }
|
| - rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v, 0, &res);
|
| - cnt++;
|
| - }while( cnt<100 && rc==SQLITE_OK && res==0 );
|
| + v++; /* ensure non-zero */
|
| + }
|
| if( rc==SQLITE_OK && res==0 ){
|
| - rc = SQLITE_FULL;
|
| + 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;
|
| }
|
| - MemSetTypeFlag(pOut, MEM_Int);
|
| pOut->u.i = v;
|
| break;
|
| }
|
| @@ -3682,7 +3863,13 @@ case OP_NewRowid: { /* out2-prerelease */
|
| ** This instruction only works on tables. The equivalent instruction
|
| ** for indices is OP_IdxInsert.
|
| */
|
| -case OP_Insert: {
|
| +/* Opcode: InsertInt P1 P2 P3 P4 P5
|
| +**
|
| +** 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.
|
| +*/
|
| +case OP_Insert:
|
| +case OP_InsertInt: {
|
| Mem *pData; /* MEM cell holding data for the record to be inserted */
|
| Mem *pKey; /* MEM cell holding key for the record */
|
| i64 iKey; /* The integer ROWID or key for the record to be inserted */
|
| @@ -3693,21 +3880,29 @@ case OP_Insert: {
|
| const char *zTbl; /* Table name - used by the opdate hook */
|
| int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
|
|
|
| - pData = &p->aMem[pOp->p2];
|
| - pKey = &p->aMem[pOp->p3];
|
| + pData = &aMem[pOp->p2];
|
| assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
| + assert( memIsValid(pData) );
|
| pC = p->apCsr[pOp->p1];
|
| assert( pC!=0 );
|
| assert( pC->pCursor!=0 );
|
| assert( pC->pseudoTableReg==0 );
|
| - assert( pKey->flags & MEM_Int );
|
| assert( pC->isTable );
|
| REGISTER_TRACE(pOp->p2, pData);
|
| - REGISTER_TRACE(pOp->p3, pKey);
|
|
|
| - iKey = pKey->u.i;
|
| + if( pOp->opcode==OP_Insert ){
|
| + pKey = &aMem[pOp->p3];
|
| + assert( pKey->flags & MEM_Int );
|
| + assert( memIsValid(pKey) );
|
| + REGISTER_TRACE(pOp->p3, pKey);
|
| + iKey = pKey->u.i;
|
| + }else{
|
| + assert( pOp->opcode==OP_InsertInt );
|
| + iKey = pOp->p3;
|
| + }
|
| +
|
| if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
| - if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = pKey->u.i;
|
| + if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey;
|
| if( pData->flags & MEM_Null ){
|
| pData->z = 0;
|
| pData->n = 0;
|
| @@ -3845,7 +4040,8 @@ case OP_RowData: {
|
| u32 n;
|
| i64 n64;
|
|
|
| - pOut = &p->aMem[pOp->p2];
|
| + pOut = &aMem[pOp->p2];
|
| + memAboutToChange(p, pOut);
|
|
|
| /* Note that RowKey and RowData are really exactly the same instruction */
|
| assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
| @@ -3918,7 +4114,7 @@ case OP_Rowid: { /* out2-prerelease */
|
| assert( pC!=0 );
|
| assert( pC->pseudoTableReg==0 );
|
| if( pC->nullRow ){
|
| - /* Do nothing so that reg[P2] remains NULL */
|
| + pOut->flags = MEM_Null;
|
| break;
|
| }else if( pC->deferredMoveto ){
|
| v = pC->movetoTarget;
|
| @@ -3927,12 +4123,8 @@ case OP_Rowid: { /* out2-prerelease */
|
| pVtab = pC->pVtabCursor->pVtab;
|
| pModule = pVtab->pModule;
|
| assert( pModule->xRowid );
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| rc = pModule->xRowid(pC->pVtabCursor, &v);
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = pVtab->zErrMsg;
|
| - pVtab->zErrMsg = 0;
|
| - if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
| + importVtabErrMsg(p, pVtab);
|
| #endif /* SQLITE_OMIT_VIRTUALTABLE */
|
| }else{
|
| assert( pC->pCursor!=0 );
|
| @@ -3946,7 +4138,6 @@ case OP_Rowid: { /* out2-prerelease */
|
| }
|
| }
|
| pOut->u.i = v;
|
| - MemSetTypeFlag(pOut, MEM_Int);
|
| break;
|
| }
|
|
|
| @@ -4039,14 +4230,13 @@ case OP_Rewind: { /* jump */
|
| assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
| pC = p->apCsr[pOp->p1];
|
| assert( pC!=0 );
|
| + res = 1;
|
| if( (pCrsr = pC->pCursor)!=0 ){
|
| rc = sqlite3BtreeFirst(pCrsr, &res);
|
| pC->atFirst = res==0 ?1:0;
|
| pC->deferredMoveto = 0;
|
| pC->cacheStatus = CACHE_STALE;
|
| pC->rowidIsValid = 0;
|
| - }else{
|
| - res = 1;
|
| }
|
| pC->nullRow = (u8)res;
|
| assert( pOp->p2>0 && pOp->p2<p->nOp );
|
| @@ -4056,7 +4246,7 @@ case OP_Rewind: { /* jump */
|
| break;
|
| }
|
|
|
| -/* Opcode: Next P1 P2 * * *
|
| +/* Opcode: Next P1 P2 * * 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
|
| @@ -4065,9 +4255,12 @@ case OP_Rewind: { /* jump */
|
| **
|
| ** The P1 cursor must be for a real table, not a pseudo-table.
|
| **
|
| +** If P5 is positive and the jump is taken, then event counter
|
| +** number P5-1 in the prepared statement is incremented.
|
| +**
|
| ** See also: Prev
|
| */
|
| -/* Opcode: Prev P1 P2 * * *
|
| +/* Opcode: Prev P1 P2 * * 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
|
| @@ -4075,6 +4268,9 @@ case OP_Rewind: { /* jump */
|
| ** jump immediately to P2.
|
| **
|
| ** The P1 cursor must be for a real table, not a pseudo-table.
|
| +**
|
| +** 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 */
|
| @@ -4084,6 +4280,7 @@ case OP_Next: { /* jump */
|
|
|
| CHECK_FOR_INTERRUPT;
|
| assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
| + assert( pOp->p5<=ArraySize(p->aCounter) );
|
| pC = p->apCsr[pOp->p1];
|
| if( pC==0 ){
|
| break; /* See ticket #2273 */
|
| @@ -4131,6 +4328,7 @@ case OP_IdxInsert: { /* in2 */
|
| assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
| pC = p->apCsr[pOp->p1];
|
| assert( pC!=0 );
|
| + pIn2 = &aMem[pOp->p2];
|
| assert( pIn2->flags & MEM_Blob );
|
| pCrsr = pC->pCursor;
|
| if( ALWAYS(pCrsr!=0) ){
|
| @@ -4171,7 +4369,10 @@ case OP_IdxDelete: {
|
| r.pKeyInfo = pC->pKeyInfo;
|
| r.nField = (u16)pOp->p3;
|
| r.flags = 0;
|
| - r.aMem = &p->aMem[pOp->p2];
|
| + r.aMem = &aMem[pOp->p2];
|
| +#ifdef SQLITE_DEBUG
|
| + { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
| +#endif
|
| rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
|
| if( rc==SQLITE_OK && res==0 ){
|
| rc = sqlite3BtreeDelete(pCrsr);
|
| @@ -4199,6 +4400,7 @@ case OP_IdxRowid: { /* out2-prerelease */
|
| pC = p->apCsr[pOp->p1];
|
| assert( pC!=0 );
|
| pCrsr = pC->pCursor;
|
| + pOut->flags = MEM_Null;
|
| if( ALWAYS(pCrsr!=0) ){
|
| rc = sqlite3VdbeCursorMoveto(pC);
|
| if( NEVER(rc) ) goto abort_due_to_error;
|
| @@ -4209,8 +4411,8 @@ case OP_IdxRowid: { /* out2-prerelease */
|
| if( rc!=SQLITE_OK ){
|
| goto abort_due_to_error;
|
| }
|
| - MemSetTypeFlag(pOut, MEM_Int);
|
| pOut->u.i = rowid;
|
| + pOut->flags = MEM_Int;
|
| }
|
| }
|
| break;
|
| @@ -4230,7 +4432,7 @@ case OP_IdxRowid: { /* out2-prerelease */
|
| ** 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.
|
| */
|
| -/* Opcode: IdxLT P1 P2 P3 * P5
|
| +/* Opcode: IdxLT P1 P2 P3 P4 P5
|
| **
|
| ** The P4 register values beginning with P3 form an unpacked index
|
| ** key that omits the ROWID. Compare this key value against the index
|
| @@ -4242,8 +4444,8 @@ case OP_IdxRowid: { /* out2-prerelease */
|
| ** 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.
|
| */
|
| -case OP_IdxLT: /* jump, in3 */
|
| -case OP_IdxGE: { /* jump, in3 */
|
| +case OP_IdxLT: /* jump */
|
| +case OP_IdxGE: { /* jump */
|
| VdbeCursor *pC;
|
| int res;
|
| UnpackedRecord r;
|
| @@ -4251,6 +4453,7 @@ case OP_IdxGE: { /* jump, in3 */
|
| assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
| 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 );
|
| @@ -4262,7 +4465,10 @@ case OP_IdxGE: { /* jump, in3 */
|
| }else{
|
| r.flags = UNPACKED_IGNORE_ROWID;
|
| }
|
| - r.aMem = &p->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]) ); }
|
| +#endif
|
| rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res);
|
| if( pOp->opcode==OP_IdxLT ){
|
| res = -res;
|
| @@ -4312,19 +4518,23 @@ case OP_Destroy: { /* out2-prerelease */
|
| #else
|
| iCnt = db->activeVdbeCnt;
|
| #endif
|
| + pOut->flags = MEM_Null;
|
| if( iCnt>1 ){
|
| rc = SQLITE_LOCKED;
|
| p->errorAction = OE_Abort;
|
| }else{
|
| iDb = pOp->p3;
|
| assert( iCnt==1 );
|
| - assert( (p->btreeMask & (1<<iDb))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 );
|
| rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
|
| - MemSetTypeFlag(pOut, MEM_Int);
|
| + pOut->flags = MEM_Int;
|
| pOut->u.i = iMoved;
|
| #ifndef SQLITE_OMIT_AUTOVACUUM
|
| if( rc==SQLITE_OK && iMoved!=0 ){
|
| - sqlite3RootPageMoved(&db->aDb[iDb], iMoved, pOp->p1);
|
| + sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1);
|
| + /* All OP_Destroy operations occur on the same btree */
|
| + assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 );
|
| + resetSchemaOnFault = iDb+1;
|
| }
|
| #endif
|
| }
|
| @@ -4353,14 +4563,16 @@ case OP_Clear: {
|
| int nChange;
|
|
|
| nChange = 0;
|
| - assert( (p->btreeMask & (1<<pOp->p2))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 );
|
| rc = sqlite3BtreeClearTable(
|
| db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
|
| );
|
| if( pOp->p3 ){
|
| p->nChange += nChange;
|
| if( pOp->p3>0 ){
|
| - p->aMem[pOp->p3].u.i += nChange;
|
| + assert( memIsValid(&aMem[pOp->p3]) );
|
| + memAboutToChange(p, &aMem[pOp->p3]);
|
| + aMem[pOp->p3].u.i += nChange;
|
| }
|
| }
|
| break;
|
| @@ -4396,29 +4608,24 @@ case OP_CreateTable: { /* out2-prerelease */
|
|
|
| pgno = 0;
|
| assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
| - assert( (p->btreeMask & (1<<pOp->p1))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
| pDb = &db->aDb[pOp->p1];
|
| assert( pDb->pBt!=0 );
|
| if( pOp->opcode==OP_CreateTable ){
|
| /* flags = BTREE_INTKEY; */
|
| - flags = BTREE_LEAFDATA|BTREE_INTKEY;
|
| + flags = BTREE_INTKEY;
|
| }else{
|
| - flags = BTREE_ZERODATA;
|
| + flags = BTREE_BLOBKEY;
|
| }
|
| rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
|
| pOut->u.i = pgno;
|
| - MemSetTypeFlag(pOut, MEM_Int);
|
| break;
|
| }
|
|
|
| -/* Opcode: ParseSchema P1 P2 * P4 *
|
| +/* Opcode: ParseSchema P1 * * P4 *
|
| **
|
| ** Read and parse all entries from the SQLITE_MASTER table of database P1
|
| -** that match the WHERE clause P4. P2 is the "force" flag. Always do
|
| -** the parsing if P2 is true. If P2 is false, then this routine is a
|
| -** no-op if the schema is not currently loaded. In other words, if P2
|
| -** is false, the SQLITE_MASTER table is only parsed if the rest of the
|
| -** schema is already loaded into the symbol table.
|
| +** that match the WHERE clause P4.
|
| **
|
| ** This opcode invokes the parser to create a new virtual machine,
|
| ** then runs the new virtual machine. It is thus a re-entrant opcode.
|
| @@ -4429,44 +4636,30 @@ case OP_ParseSchema: {
|
| char *zSql;
|
| InitData initData;
|
|
|
| + /* Any prepared statement that invokes this opcode will hold mutexes
|
| + ** on every btree. This is a prerequisite for invoking
|
| + ** sqlite3InitCallback().
|
| + */
|
| +#ifdef SQLITE_DEBUG
|
| + for(iDb=0; iDb<db->nDb; iDb++){
|
| + assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
|
| + }
|
| +#endif
|
| +
|
| iDb = pOp->p1;
|
| assert( iDb>=0 && iDb<db->nDb );
|
| -
|
| - /* If pOp->p2 is 0, then this opcode is being executed to read a
|
| - ** single row, for example the row corresponding to a new index
|
| - ** created by this VDBE, from the sqlite_master table. It only
|
| - ** does this if the corresponding in-memory schema is currently
|
| - ** loaded. Otherwise, the new index definition can be loaded along
|
| - ** with the rest of the schema when it is required.
|
| - **
|
| - ** Although the mutex on the BtShared object that corresponds to
|
| - ** database iDb (the database containing the sqlite_master table
|
| - ** read by this instruction) is currently held, it is necessary to
|
| - ** obtain the mutexes on all attached databases before checking if
|
| - ** the schema of iDb is loaded. This is because, at the start of
|
| - ** the sqlite3_exec() call below, SQLite will invoke
|
| - ** sqlite3BtreeEnterAll(). If all mutexes are not already held, the
|
| - ** iDb mutex may be temporarily released to avoid deadlock. If
|
| - ** this happens, then some other thread may delete the in-memory
|
| - ** schema of database iDb before the SQL statement runs. The schema
|
| - ** will not be reloaded becuase the db->init.busy flag is set. This
|
| - ** can result in a "no such table: sqlite_master" or "malformed
|
| - ** database schema" error being returned to the user.
|
| - */
|
| - assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
|
| - sqlite3BtreeEnterAll(db);
|
| - if( pOp->p2 || DbHasProperty(db, iDb, DB_SchemaLoaded) ){
|
| + assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
|
| + /* Used to be a conditional */ {
|
| zMaster = SCHEMA_TABLE(iDb);
|
| initData.db = db;
|
| initData.iDb = pOp->p1;
|
| initData.pzErrMsg = &p->zErrMsg;
|
| zSql = sqlite3MPrintf(db,
|
| - "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
|
| + "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
|
| db->aDb[iDb].zName, zMaster, pOp->p4.z);
|
| if( zSql==0 ){
|
| rc = SQLITE_NOMEM;
|
| }else{
|
| - (void)sqlite3SafetyOff(db);
|
| assert( db->init.busy==0 );
|
| db->init.busy = 1;
|
| initData.rc = SQLITE_OK;
|
| @@ -4475,10 +4668,8 @@ case OP_ParseSchema: {
|
| if( rc==SQLITE_OK ) rc = initData.rc;
|
| sqlite3DbFree(db, zSql);
|
| db->init.busy = 0;
|
| - (void)sqlite3SafetyOn(db);
|
| }
|
| }
|
| - sqlite3BtreeLeaveAll(db);
|
| if( rc==SQLITE_NOMEM ){
|
| goto no_mem;
|
| }
|
| @@ -4570,16 +4761,16 @@ case OP_IntegrityCk: {
|
| aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) );
|
| if( aRoot==0 ) goto no_mem;
|
| assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
| - pnErr = &p->aMem[pOp->p3];
|
| + pnErr = &aMem[pOp->p3];
|
| assert( (pnErr->flags & MEM_Int)!=0 );
|
| assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
|
| - pIn1 = &p->aMem[pOp->p1];
|
| + pIn1 = &aMem[pOp->p1];
|
| for(j=0; j<nRoot; j++){
|
| aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
|
| }
|
| aRoot[j] = 0;
|
| assert( pOp->p5<db->nDb );
|
| - assert( (p->btreeMask & (1<<pOp->p5))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<pOp->p5))!=0 );
|
| z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
|
| (int)pnErr->u.i, &nErr);
|
| sqlite3DbFree(db, aRoot);
|
| @@ -4605,19 +4796,15 @@ case OP_IntegrityCk: {
|
| **
|
| ** An assertion fails if P2 is not an integer.
|
| */
|
| -case OP_RowSetAdd: { /* in2 */
|
| - Mem *pIdx;
|
| - Mem *pVal;
|
| - assert( pOp->p1>0 && pOp->p1<=p->nMem );
|
| - pIdx = &p->aMem[pOp->p1];
|
| - assert( pOp->p2>0 && pOp->p2<=p->nMem );
|
| - pVal = &p->aMem[pOp->p2];
|
| - assert( (pVal->flags & MEM_Int)!=0 );
|
| - if( (pIdx->flags & MEM_RowSet)==0 ){
|
| - sqlite3VdbeMemSetRowSet(pIdx);
|
| - if( (pIdx->flags & MEM_RowSet)==0 ) goto no_mem;
|
| - }
|
| - sqlite3RowSetInsert(pIdx->u.pRowSet, pVal->u.i);
|
| +case OP_RowSetAdd: { /* in1, in2 */
|
| + pIn1 = &aMem[pOp->p1];
|
| + pIn2 = &aMem[pOp->p2];
|
| + assert( (pIn2->flags & MEM_Int)!=0 );
|
| + if( (pIn1->flags & MEM_RowSet)==0 ){
|
| + sqlite3VdbeMemSetRowSet(pIn1);
|
| + if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem;
|
| + }
|
| + sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i);
|
| break;
|
| }
|
|
|
| @@ -4627,23 +4814,19 @@ case OP_RowSetAdd: { /* in2 */
|
| ** register P3. Or, if boolean index P1 is initially empty, leave P3
|
| ** unchanged and jump to instruction P2.
|
| */
|
| -case OP_RowSetRead: { /* jump, out3 */
|
| - Mem *pIdx;
|
| +case OP_RowSetRead: { /* jump, in1, out3 */
|
| i64 val;
|
| - assert( pOp->p1>0 && pOp->p1<=p->nMem );
|
| CHECK_FOR_INTERRUPT;
|
| - pIdx = &p->aMem[pOp->p1];
|
| - pOut = &p->aMem[pOp->p3];
|
| - if( (pIdx->flags & MEM_RowSet)==0
|
| - || sqlite3RowSetNext(pIdx->u.pRowSet, &val)==0
|
| + pIn1 = &aMem[pOp->p1];
|
| + if( (pIn1->flags & MEM_RowSet)==0
|
| + || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0
|
| ){
|
| /* The boolean index is empty */
|
| - sqlite3VdbeMemSetNull(pIdx);
|
| + sqlite3VdbeMemSetNull(pIn1);
|
| pc = pOp->p2 - 1;
|
| }else{
|
| /* A value was pulled from the index */
|
| - assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
| - sqlite3VdbeMemSetInt64(pOut, val);
|
| + sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val);
|
| }
|
| break;
|
| }
|
| @@ -4675,6 +4858,8 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
| int iSet;
|
| int exists;
|
|
|
| + pIn1 = &aMem[pOp->p1];
|
| + pIn3 = &aMem[pOp->p3];
|
| iSet = pOp->p4.i;
|
| assert( pIn3->flags&MEM_Int );
|
|
|
| @@ -4730,27 +4915,28 @@ case OP_Program: { /* jump */
|
| void *t; /* Token identifying trigger */
|
|
|
| pProgram = pOp->p4.pProgram;
|
| - pRt = &p->aMem[pOp->p3];
|
| + pRt = &aMem[pOp->p3];
|
| + assert( memIsValid(pRt) );
|
| assert( pProgram->nOp>0 );
|
|
|
| - /* If the SQLITE_RecTriggers flag is clear, then recursive invocation of
|
| - ** triggers is disabled for backwards compatibility (flag set/cleared by
|
| - ** the "PRAGMA recursive_triggers" command).
|
| + /* If the p5 flag is clear, then recursive invocation of triggers is
|
| + ** disabled for backwards compatibility (p5 is set if this sub-program
|
| + ** is really a trigger, not a foreign key action, and the flag set
|
| + ** and cleared by the "PRAGMA recursive_triggers" command is clear).
|
| **
|
| ** It is recursive invocation of triggers, at the SQL level, that is
|
| ** disabled. In some cases a single trigger may generate more than one
|
| ** SubProgram (if the trigger may be executed with more than one different
|
| ** ON CONFLICT algorithm). SubProgram structures associated with a
|
| ** single trigger all have the same value for the SubProgram.token
|
| - ** variable.
|
| - */
|
| - if( 0==(db->flags&SQLITE_RecTriggers) ){
|
| + ** variable. */
|
| + if( pOp->p5 ){
|
| t = pProgram->token;
|
| for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent);
|
| if( pFrame ) break;
|
| }
|
|
|
| - if( p->nFrame>db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
|
| + if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
|
| rc = SQLITE_ERROR;
|
| sqlite3SetString(&p->zErrMsg, db, "too many levels of trigger recursion");
|
| break;
|
| @@ -4808,11 +4994,11 @@ case OP_Program: { /* jump */
|
| pFrame->nChange = p->nChange;
|
| p->nChange = 0;
|
| p->pFrame = pFrame;
|
| - p->aMem = &VdbeFrameMem(pFrame)[-1];
|
| + p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
|
| p->nMem = pFrame->nChildMem;
|
| p->nCursor = (u16)pFrame->nChildCsr;
|
| - p->apCsr = (VdbeCursor **)&p->aMem[p->nMem+1];
|
| - p->aOp = pProgram->aOp;
|
| + p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
|
| + p->aOp = aOp = pProgram->aOp;
|
| p->nOp = pProgram->nOp;
|
| pc = -1;
|
|
|
| @@ -4842,6 +5028,44 @@ case OP_Param: { /* out2-prerelease */
|
|
|
| #endif /* #ifndef SQLITE_OMIT_TRIGGER */
|
|
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| +/* Opcode: FkCounter 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
|
| +** (deferred foreign key constraints). Otherwise, if P1 is zero, the
|
| +** statement counter is incremented (immediate foreign key constraints).
|
| +*/
|
| +case OP_FkCounter: {
|
| + if( pOp->p1 ){
|
| + db->nDeferredCons += pOp->p2;
|
| + }else{
|
| + p->nFkConstraint += pOp->p2;
|
| + }
|
| + break;
|
| +}
|
| +
|
| +/* Opcode: FkIfZero P1 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
|
| +** instruction.
|
| +**
|
| +** If P1 is non-zero, then the jump is taken if the database constraint-counter
|
| +** is zero (the one that counts deferred constraint violations). If P1 is
|
| +** zero, the jump is taken if the statement constraint-counter is zero
|
| +** (immediate foreign key constraint violations).
|
| +*/
|
| +case OP_FkIfZero: { /* jump */
|
| + if( pOp->p1 ){
|
| + if( db->nDeferredCons==0 ) pc = pOp->p2-1;
|
| + }else{
|
| + if( p->nFkConstraint==0 ) pc = pOp->p2-1;
|
| + }
|
| + break;
|
| +}
|
| +#endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */
|
| +
|
| #ifndef SQLITE_OMIT_AUTOINCREMENT
|
| /* Opcode: MemMax P1 P2 * * *
|
| **
|
| @@ -4860,9 +5084,11 @@ case OP_MemMax: { /* in2 */
|
| for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
|
| pIn1 = &pFrame->aMem[pOp->p1];
|
| }else{
|
| - pIn1 = &p->aMem[pOp->p1];
|
| + pIn1 = &aMem[pOp->p1];
|
| }
|
| + assert( memIsValid(pIn1) );
|
| sqlite3VdbeMemIntegerify(pIn1);
|
| + pIn2 = &aMem[pOp->p2];
|
| sqlite3VdbeMemIntegerify(pIn2);
|
| if( pIn1->u.i<pIn2->u.i){
|
| pIn1->u.i = pIn2->u.i;
|
| @@ -4879,6 +5105,7 @@ case OP_MemMax: { /* in2 */
|
| ** not contain an integer. An assertion fault will result if you try.
|
| */
|
| case OP_IfPos: { /* jump, in1 */
|
| + pIn1 = &aMem[pOp->p1];
|
| assert( pIn1->flags&MEM_Int );
|
| if( pIn1->u.i>0 ){
|
| pc = pOp->p2 - 1;
|
| @@ -4894,6 +5121,7 @@ case OP_IfPos: { /* jump, in1 */
|
| ** not contain an integer. An assertion fault will result if you try.
|
| */
|
| case OP_IfNeg: { /* jump, in1 */
|
| + pIn1 = &aMem[pOp->p1];
|
| assert( pIn1->flags&MEM_Int );
|
| if( pIn1->u.i<0 ){
|
| pc = pOp->p2 - 1;
|
| @@ -4901,15 +5129,18 @@ case OP_IfNeg: { /* jump, in1 */
|
| break;
|
| }
|
|
|
| -/* Opcode: IfZero P1 P2 * * *
|
| +/* Opcode: IfZero P1 P2 P3 * *
|
| **
|
| -** If the value of register P1 is exactly 0, jump to 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;
|
| if( pIn1->u.i==0 ){
|
| pc = pOp->p2 - 1;
|
| }
|
| @@ -4936,16 +5167,18 @@ case OP_AggStep: {
|
|
|
| n = pOp->p5;
|
| assert( n>=0 );
|
| - pRec = &p->aMem[pOp->p2];
|
| + pRec = &aMem[pOp->p2];
|
| apVal = p->apArg;
|
| assert( apVal || n==0 );
|
| for(i=0; i<n; i++, pRec++){
|
| + assert( memIsValid(pRec) );
|
| apVal[i] = pRec;
|
| - storeTypeInfo(pRec, encoding);
|
| + memAboutToChange(p, pRec);
|
| + sqlite3VdbeMemStoreType(pRec);
|
| }
|
| ctx.pFunc = pOp->p4.pFunc;
|
| assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
| - ctx.pMem = pMem = &p->aMem[pOp->p3];
|
| + ctx.pMem = pMem = &aMem[pOp->p3];
|
| pMem->n++;
|
| ctx.s.flags = MEM_Null;
|
| ctx.s.z = 0;
|
| @@ -4960,12 +5193,14 @@ case OP_AggStep: {
|
| assert( pOp[-1].opcode==OP_CollSeq );
|
| ctx.pColl = pOp[-1].p4.pColl;
|
| }
|
| - (ctx.pFunc->xStep)(&ctx, n, apVal);
|
| + (ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */
|
| if( ctx.isError ){
|
| sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s));
|
| rc = ctx.isError;
|
| }
|
| +
|
| sqlite3VdbeMemRelease(&ctx.s);
|
| +
|
| break;
|
| }
|
|
|
| @@ -4984,7 +5219,7 @@ case OP_AggStep: {
|
| case OP_AggFinal: {
|
| Mem *pMem;
|
| assert( pOp->p1>0 && pOp->p1<=p->nMem );
|
| - pMem = &p->aMem[pOp->p1];
|
| + pMem = &aMem[pOp->p1];
|
| assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
|
| rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
|
| if( rc ){
|
| @@ -4998,6 +5233,143 @@ case OP_AggFinal: {
|
| break;
|
| }
|
|
|
| +#ifndef SQLITE_OMIT_WAL
|
| +/* Opcode: Checkpoint P1 P2 P3 * *
|
| +**
|
| +** Checkpoint database P1. This is a no-op if P1 is not currently in
|
| +** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL
|
| +** or RESTART. Write 1 or 0 into mem[P3] if the checkpoint returns
|
| +** SQLITE_BUSY or not, respectively. Write the number of pages in the
|
| +** WAL after the checkpoint into mem[P3+1] and the number of pages
|
| +** in the WAL that have been checkpointed after the checkpoint
|
| +** completes into mem[P3+2]. However on an error, mem[P3+1] and
|
| +** mem[P3+2] are initialized to -1.
|
| +*/
|
| +case OP_Checkpoint: {
|
| + int i; /* Loop counter */
|
| + int aRes[3]; /* Results */
|
| + Mem *pMem; /* Write results here */
|
| +
|
| + aRes[0] = 0;
|
| + aRes[1] = aRes[2] = -1;
|
| + assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE
|
| + || pOp->p2==SQLITE_CHECKPOINT_FULL
|
| + || pOp->p2==SQLITE_CHECKPOINT_RESTART
|
| + );
|
| + rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]);
|
| + if( rc==SQLITE_BUSY ){
|
| + rc = SQLITE_OK;
|
| + aRes[0] = 1;
|
| + }
|
| + for(i=0, pMem = &aMem[pOp->p3]; i<3; i++, pMem++){
|
| + sqlite3VdbeMemSetInt64(pMem, (i64)aRes[i]);
|
| + }
|
| + break;
|
| +};
|
| +#endif
|
| +
|
| +#ifndef SQLITE_OMIT_PRAGMA
|
| +/* Opcode: JournalMode P1 P2 P3 * P5
|
| +**
|
| +** 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
|
| +** modes (delete, truncate, persist, off and memory), this is a simple
|
| +** operation. No IO is required.
|
| +**
|
| +** If changing into or out of WAL mode the procedure is more complicated.
|
| +**
|
| +** Write a string containing the final journal-mode to register P2.
|
| +*/
|
| +case OP_JournalMode: { /* out2-prerelease */
|
| + Btree *pBt; /* Btree to change journal mode of */
|
| + Pager *pPager; /* Pager associated with pBt */
|
| + int eNew; /* New journal mode */
|
| + int eOld; /* The old journal mode */
|
| + const char *zFilename; /* Name of database file for pPager */
|
| +
|
| + eNew = pOp->p3;
|
| + assert( eNew==PAGER_JOURNALMODE_DELETE
|
| + || eNew==PAGER_JOURNALMODE_TRUNCATE
|
| + || eNew==PAGER_JOURNALMODE_PERSIST
|
| + || eNew==PAGER_JOURNALMODE_OFF
|
| + || eNew==PAGER_JOURNALMODE_MEMORY
|
| + || eNew==PAGER_JOURNALMODE_WAL
|
| + || eNew==PAGER_JOURNALMODE_QUERY
|
| + );
|
| + assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
| +
|
| + pBt = db->aDb[pOp->p1].pBt;
|
| + pPager = sqlite3BtreePager(pBt);
|
| + eOld = sqlite3PagerGetJournalMode(pPager);
|
| + if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld;
|
| + if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld;
|
| +
|
| +#ifndef SQLITE_OMIT_WAL
|
| + zFilename = sqlite3PagerFilename(pPager);
|
| +
|
| + /* 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 */
|
| + || !sqlite3PagerWalSupported(pPager)) /* No shared-memory support */
|
| + ){
|
| + eNew = eOld;
|
| + }
|
| +
|
| + if( (eNew!=eOld)
|
| + && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL)
|
| + ){
|
| + if( !db->autoCommit || db->activeVdbeCnt>1 ){
|
| + rc = SQLITE_ERROR;
|
| + sqlite3SetString(&p->zErrMsg, db,
|
| + "cannot change %s wal mode from within a transaction",
|
| + (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
|
| + );
|
| + break;
|
| + }else{
|
| +
|
| + if( eOld==PAGER_JOURNALMODE_WAL ){
|
| + /* If leaving WAL mode, close the log file. If successful, the call
|
| + ** to PagerCloseWal() checkpoints and deletes the write-ahead-log
|
| + ** file. An EXCLUSIVE lock may still be held on the database file
|
| + ** after a successful return.
|
| + */
|
| + rc = sqlite3PagerCloseWal(pPager);
|
| + if( rc==SQLITE_OK ){
|
| + sqlite3PagerSetJournalMode(pPager, eNew);
|
| + }
|
| + }else if( eOld==PAGER_JOURNALMODE_MEMORY ){
|
| + /* Cannot transition directly from MEMORY to WAL. Use mode OFF
|
| + ** as an intermediate */
|
| + sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF);
|
| + }
|
| +
|
| + /* Open a transaction on the database file. Regardless of the journal
|
| + ** mode, this transaction always uses a rollback journal.
|
| + */
|
| + assert( sqlite3BtreeIsInTrans(pBt)==0 );
|
| + if( rc==SQLITE_OK ){
|
| + rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
|
| + }
|
| + }
|
| + }
|
| +#endif /* ifndef SQLITE_OMIT_WAL */
|
| +
|
| + if( rc ){
|
| + eNew = eOld;
|
| + }
|
| + eNew = sqlite3PagerSetJournalMode(pPager, eNew);
|
| +
|
| + pOut = &aMem[pOp->p2];
|
| + pOut->flags = MEM_Str|MEM_Static|MEM_Term;
|
| + pOut->z = (char *)sqlite3JournalModename(eNew);
|
| + pOut->n = sqlite3Strlen30(pOut->z);
|
| + pOut->enc = SQLITE_UTF8;
|
| + sqlite3VdbeChangeEncoding(pOut, encoding);
|
| + break;
|
| +};
|
| +#endif /* SQLITE_OMIT_PRAGMA */
|
|
|
| #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
| /* Opcode: Vacuum * * * * *
|
| @@ -5007,9 +5379,7 @@ case OP_AggFinal: {
|
| ** a transaction.
|
| */
|
| case OP_Vacuum: {
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| rc = sqlite3RunVacuum(&p->zErrMsg, db);
|
| - if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
| break;
|
| }
|
| #endif
|
| @@ -5025,7 +5395,7 @@ case OP_IncrVacuum: { /* jump */
|
| Btree *pBt;
|
|
|
| assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
| - assert( (p->btreeMask & (1<<pOp->p1))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
| pBt = db->aDb[pOp->p1].pBt;
|
| rc = sqlite3BtreeIncrVacuum(pBt);
|
| if( rc==SQLITE_DONE ){
|
| @@ -5074,7 +5444,7 @@ case OP_TableLock: {
|
| if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
|
| int p1 = pOp->p1;
|
| assert( p1>=0 && p1<db->nDb );
|
| - assert( (p->btreeMask & (1<<p1))!=0 );
|
| + assert( (p->btreeMask & (((yDbMask)1)<<p1))!=0 );
|
| assert( isWriteLock==0 || isWriteLock==1 );
|
| rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
|
| if( (rc&0xFF)==SQLITE_LOCKED ){
|
| @@ -5100,11 +5470,7 @@ case OP_VBegin: {
|
| VTable *pVTab;
|
| pVTab = pOp->p4.pVtab;
|
| rc = sqlite3VtabBegin(db, pVTab);
|
| - if( pVTab ){
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = pVTab->pVtab->zErrMsg;
|
| - pVTab->pVtab->zErrMsg = 0;
|
| - }
|
| + if( pVTab ) importVtabErrMsg(p, pVTab->pVtab);
|
| break;
|
| }
|
| #endif /* SQLITE_OMIT_VIRTUALTABLE */
|
| @@ -5153,12 +5519,8 @@ case OP_VOpen: {
|
| pVtab = pOp->p4.pVtab->pVtab;
|
| pModule = (sqlite3_module *)pVtab->pModule;
|
| assert(pVtab && pModule);
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| rc = pModule->xOpen(pVtab, &pVtabCursor);
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = pVtab->zErrMsg;
|
| - pVtab->zErrMsg = 0;
|
| - if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
| + importVtabErrMsg(p, pVtab);
|
| if( SQLITE_OK==rc ){
|
| /* Initialize sqlite3_vtab_cursor base class */
|
| pVtabCursor->pVtab = pVtab;
|
| @@ -5209,9 +5571,10 @@ case OP_VFilter: { /* jump */
|
| int i;
|
| Mem **apArg;
|
|
|
| - pQuery = &p->aMem[pOp->p3];
|
| + pQuery = &aMem[pOp->p3];
|
| pArgc = &pQuery[1];
|
| pCur = p->apCsr[pOp->p1];
|
| + assert( memIsValid(pQuery) );
|
| REGISTER_TRACE(pOp->p3, pQuery);
|
| assert( pCur->pVtabCursor );
|
| pVtabCursor = pCur->pVtabCursor;
|
| @@ -5229,20 +5592,16 @@ case OP_VFilter: { /* jump */
|
| apArg = p->apArg;
|
| for(i = 0; i<nArg; i++){
|
| apArg[i] = &pArgc[i+1];
|
| - storeTypeInfo(apArg[i], 0);
|
| + sqlite3VdbeMemStoreType(apArg[i]);
|
| }
|
|
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| p->inVtabMethod = 1;
|
| rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
| p->inVtabMethod = 0;
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = pVtab->zErrMsg;
|
| - pVtab->zErrMsg = 0;
|
| + importVtabErrMsg(p, pVtab);
|
| if( rc==SQLITE_OK ){
|
| res = pModule->xEof(pVtabCursor);
|
| }
|
| - if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
|
|
| if( res ){
|
| pc = pOp->p2 - 1;
|
| @@ -5270,7 +5629,8 @@ case OP_VColumn: {
|
| VdbeCursor *pCur = p->apCsr[pOp->p1];
|
| assert( pCur->pVtabCursor );
|
| assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
| - pDest = &p->aMem[pOp->p3];
|
| + pDest = &aMem[pOp->p3];
|
| + memAboutToChange(p, pDest);
|
| if( pCur->nullRow ){
|
| sqlite3VdbeMemSetNull(pDest);
|
| break;
|
| @@ -5288,11 +5648,8 @@ case OP_VColumn: {
|
| sqlite3VdbeMemMove(&sContext.s, pDest);
|
| MemSetTypeFlag(&sContext.s, MEM_Null);
|
|
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = pVtab->zErrMsg;
|
| - pVtab->zErrMsg = 0;
|
| + importVtabErrMsg(p, pVtab);
|
| if( sContext.isError ){
|
| rc = sContext.isError;
|
| }
|
| @@ -5302,13 +5659,10 @@ case OP_VColumn: {
|
| ** dynamic allocation in sContext.s (a Mem struct) is released.
|
| */
|
| sqlite3VdbeChangeEncoding(&sContext.s, encoding);
|
| - REGISTER_TRACE(pOp->p3, pDest);
|
| sqlite3VdbeMemMove(pDest, &sContext.s);
|
| + REGISTER_TRACE(pOp->p3, pDest);
|
| UPDATE_MAX_BLOBSIZE(pDest);
|
|
|
| - if( sqlite3SafetyOn(db) ){
|
| - goto abort_due_to_misuse;
|
| - }
|
| if( sqlite3VdbeMemTooBig(pDest) ){
|
| goto too_big;
|
| }
|
| @@ -5345,17 +5699,13 @@ case OP_VNext: { /* jump */
|
| ** data is available) and the error code returned when xColumn or
|
| ** some other method is next invoked on the save virtual table cursor.
|
| */
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| p->inVtabMethod = 1;
|
| rc = pModule->xNext(pCur->pVtabCursor);
|
| p->inVtabMethod = 0;
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = pVtab->zErrMsg;
|
| - pVtab->zErrMsg = 0;
|
| + importVtabErrMsg(p, pVtab);
|
| if( rc==SQLITE_OK ){
|
| res = pModule->xEof(pCur->pVtabCursor);
|
| }
|
| - if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
|
|
| if( !res ){
|
| /* If there is data, jump to P2 */
|
| @@ -5377,16 +5727,14 @@ case OP_VRename: {
|
| Mem *pName;
|
|
|
| pVtab = pOp->p4.pVtab->pVtab;
|
| - pName = &p->aMem[pOp->p1];
|
| + pName = &aMem[pOp->p1];
|
| assert( pVtab->pModule->xRename );
|
| + assert( memIsValid(pName) );
|
| REGISTER_TRACE(pOp->p1, pName);
|
| assert( pName->flags & MEM_Str );
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| rc = pVtab->pModule->xRename(pVtab, pName->z);
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = pVtab->zErrMsg;
|
| - pVtab->zErrMsg = 0;
|
| - if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
| + importVtabErrMsg(p, pVtab);
|
| + p->expired = 0;
|
|
|
| break;
|
| }
|
| @@ -5431,18 +5779,16 @@ case OP_VUpdate: {
|
| assert( pOp->p4type==P4_VTAB );
|
| if( ALWAYS(pModule->xUpdate) ){
|
| apArg = p->apArg;
|
| - pX = &p->aMem[pOp->p3];
|
| + pX = &aMem[pOp->p3];
|
| for(i=0; i<nArg; i++){
|
| - storeTypeInfo(pX, 0);
|
| + assert( memIsValid(pX) );
|
| + memAboutToChange(p, pX);
|
| + sqlite3VdbeMemStoreType(pX);
|
| apArg[i] = pX;
|
| pX++;
|
| }
|
| - if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
| rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = pVtab->zErrMsg;
|
| - pVtab->zErrMsg = 0;
|
| - if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
| + importVtabErrMsg(p, pVtab);
|
| if( rc==SQLITE_OK && pOp->p1 ){
|
| assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
| db->lastRowid = rowid;
|
| @@ -5459,24 +5805,37 @@ case OP_VUpdate: {
|
| ** Write the current number of pages in database P1 to memory cell P2.
|
| */
|
| case OP_Pagecount: { /* out2-prerelease */
|
| - int p1;
|
| - int nPage;
|
| - Pager *pPager;
|
| -
|
| - p1 = pOp->p1;
|
| - pPager = sqlite3BtreePager(db->aDb[p1].pBt);
|
| - rc = sqlite3PagerPagecount(pPager, &nPage);
|
| - /* OP_Pagecount is always called from within a read transaction. The
|
| - ** page count has already been successfully read and cached. So the
|
| - ** sqlite3PagerPagecount() call above cannot fail. */
|
| - if( ALWAYS(rc==SQLITE_OK) ){
|
| - pOut->flags = MEM_Int;
|
| - pOut->u.i = nPage;
|
| + pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
|
| + break;
|
| +}
|
| +#endif
|
| +
|
| +
|
| +#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
| +/* Opcode: MaxPgcnt P1 P2 P3 * *
|
| +**
|
| +** Try to set the maximum page count for database P1 to the value in P3.
|
| +** Do not let the maximum page count fall below the current page count and
|
| +** do not change the maximum page count value if P3==0.
|
| +**
|
| +** Store the maximum page count after the change in register P2.
|
| +*/
|
| +case OP_MaxPgcnt: { /* out2-prerelease */
|
| + unsigned int newMax;
|
| + Btree *pBt;
|
| +
|
| + pBt = db->aDb[pOp->p1].pBt;
|
| + newMax = 0;
|
| + if( pOp->p3 ){
|
| + newMax = sqlite3BtreeLastPage(pBt);
|
| + if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3;
|
| }
|
| + pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax);
|
| break;
|
| }
|
| #endif
|
|
|
| +
|
| #ifndef SQLITE_OMIT_TRACE
|
| /* Opcode: Trace * * * P4 *
|
| **
|
| @@ -5489,7 +5848,9 @@ case OP_Trace: {
|
| zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
|
| if( zTrace ){
|
| if( db->xTrace ){
|
| - db->xTrace(db->pTraceArg, zTrace);
|
| + char *z = sqlite3VdbeExpandSql(p, zTrace);
|
| + db->xTrace(db->pTraceArg, z);
|
| + sqlite3DbFree(db, z);
|
| }
|
| #ifdef SQLITE_DEBUG
|
| if( (db->flags & SQLITE_SqlTrace)!=0 ){
|
| @@ -5514,6 +5875,7 @@ case OP_Trace: {
|
| ** the same as a no-op. This opcodesnever appears in a real VM program.
|
| */
|
| default: { /* This is really OP_Noop and OP_Explain */
|
| + assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
|
| break;
|
| }
|
|
|
| @@ -5532,7 +5894,7 @@ default: { /* This is really OP_Noop and OP_Explain */
|
| pOp->cnt++;
|
| #if 0
|
| fprintf(stdout, "%10llu ", elapsed);
|
| - sqlite3VdbePrintOp(stdout, origPc, &p->aOp[origPc]);
|
| + sqlite3VdbePrintOp(stdout, origPc, &aOp[origPc]);
|
| #endif
|
| }
|
| #endif
|
| @@ -5548,11 +5910,11 @@ default: { /* This is really OP_Noop and OP_Explain */
|
| #ifdef SQLITE_DEBUG
|
| if( p->trace ){
|
| if( rc!=0 ) fprintf(p->trace,"rc=%d\n",rc);
|
| - if( opProperty & OPFLG_OUT2_PRERELEASE ){
|
| - registerTrace(p->trace, pOp->p2, pOut);
|
| + if( pOp->opflags & (OPFLG_OUT2_PRERELEASE|OPFLG_OUT2) ){
|
| + registerTrace(p->trace, pOp->p2, &aMem[pOp->p2]);
|
| }
|
| - if( opProperty & OPFLG_OUT3 ){
|
| - registerTrace(p->trace, pOp->p3, pOut);
|
| + if( pOp->opflags & OPFLG_OUT3 ){
|
| + registerTrace(p->trace, pOp->p3, &aMem[pOp->p3]);
|
| }
|
| }
|
| #endif /* SQLITE_DEBUG */
|
| @@ -5565,15 +5927,21 @@ default: { /* This is really OP_Noop and OP_Explain */
|
| vdbe_error_halt:
|
| assert( rc );
|
| p->rc = rc;
|
| + testcase( sqlite3GlobalConfig.xLog!=0 );
|
| + sqlite3_log(rc, "statement aborts at %d: [%s] %s",
|
| + pc, p->zSql, p->zErrMsg);
|
| sqlite3VdbeHalt(p);
|
| if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
|
| rc = SQLITE_ERROR;
|
| + if( resetSchemaOnFault>0 ){
|
| + sqlite3ResetInternalSchema(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:
|
| - sqlite3BtreeMutexArrayLeave(&p->aMutex);
|
| + sqlite3VdbeLeave(p);
|
| return rc;
|
|
|
| /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH
|
| @@ -5592,12 +5960,6 @@ no_mem:
|
| rc = SQLITE_NOMEM;
|
| goto vdbe_error_halt;
|
|
|
| - /* Jump to here for an SQLITE_MISUSE error.
|
| - */
|
| -abort_due_to_misuse:
|
| - rc = SQLITE_MISUSE;
|
| - /* Fall thru into abort_due_to_error */
|
| -
|
| /* Jump to here for any other kind of fatal error. The "rc" variable
|
| ** should hold the error number.
|
| */
|
|
|