| Index: third_party/sqlite/sqlite-src-3100200/src/vdbeaux.c
|
| diff --git a/third_party/sqlite/src/src/vdbeaux.c b/third_party/sqlite/sqlite-src-3100200/src/vdbeaux.c
|
| similarity index 85%
|
| copy from third_party/sqlite/src/src/vdbeaux.c
|
| copy to third_party/sqlite/sqlite-src-3100200/src/vdbeaux.c
|
| index c0018bb71cae5d486e5e94f90963d3ce509dc16e..dbbb2a6ccb1c0e75f0f2b9f3b1298fb1e78b6971 100644
|
| --- a/third_party/sqlite/src/src/vdbeaux.c
|
| +++ b/third_party/sqlite/sqlite-src-3100200/src/vdbeaux.c
|
| @@ -35,10 +35,22 @@ Vdbe *sqlite3VdbeCreate(Parse *pParse){
|
| assert( pParse->aLabel==0 );
|
| assert( pParse->nLabel==0 );
|
| assert( pParse->nOpAlloc==0 );
|
| + assert( pParse->szOpAlloc==0 );
|
| return p;
|
| }
|
|
|
| /*
|
| +** Change the error string stored in Vdbe.zErrMsg
|
| +*/
|
| +void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){
|
| + va_list ap;
|
| + sqlite3DbFree(p->db, p->zErrMsg);
|
| + va_start(ap, zFormat);
|
| + p->zErrMsg = sqlite3VMPrintf(p->db, zFormat, ap);
|
| + va_end(ap);
|
| +}
|
| +
|
| +/*
|
| ** Remember the SQL string for a prepared statement.
|
| */
|
| void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
| @@ -57,7 +69,7 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
| */
|
| const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
| Vdbe *p = (Vdbe *)pStmt;
|
| - return (p && p->isPrepareV2) ? p->zSql : 0;
|
| + return p ? p->zSql : 0;
|
| }
|
|
|
| /*
|
| @@ -113,7 +125,8 @@ static int growOpArray(Vdbe *v, int nOp){
|
| assert( nNew>=(p->nOpAlloc+nOp) );
|
| pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
|
| if( pNew ){
|
| - p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op);
|
| + p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew);
|
| + p->nOpAlloc = p->szOpAlloc/sizeof(Op);
|
| v->aOp = pNew;
|
| }
|
| return (pNew ? SQLITE_OK : SQLITE_NOMEM);
|
| @@ -146,6 +159,12 @@ static void test_addop_breakpoint(void){
|
| ** the sqlite3VdbeChangeP4() function to change the value of the P4
|
| ** operand.
|
| */
|
| +static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
| + assert( p->pParse->nOpAlloc<=p->nOp );
|
| + if( growOpArray(p, 1) ) return 1;
|
| + assert( p->pParse->nOpAlloc>p->nOp );
|
| + return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
|
| +}
|
| int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
| int i;
|
| VdbeOp *pOp;
|
| @@ -154,9 +173,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
| assert( p->magic==VDBE_MAGIC_INIT );
|
| assert( op>0 && op<0xff );
|
| if( p->pParse->nOpAlloc<=i ){
|
| - if( growOpArray(p, 1) ){
|
| - return 1;
|
| - }
|
| + return growOp3(p, op, p1, p2, p3);
|
| }
|
| p->nOp++;
|
| pOp = &p->aOp[i];
|
| @@ -204,6 +221,44 @@ int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
|
| return sqlite3VdbeAddOp3(p, op, p1, p2, 0);
|
| }
|
|
|
| +/* Generate code for an unconditional jump to instruction iDest
|
| +*/
|
| +int sqlite3VdbeGoto(Vdbe *p, int iDest){
|
| + return sqlite3VdbeAddOp3(p, OP_Goto, 0, iDest, 0);
|
| +}
|
| +
|
| +/* Generate code to cause the string zStr to be loaded into
|
| +** register iDest
|
| +*/
|
| +int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){
|
| + return sqlite3VdbeAddOp4(p, OP_String8, 0, iDest, 0, zStr, 0);
|
| +}
|
| +
|
| +/*
|
| +** Generate code that initializes multiple registers to string or integer
|
| +** constants. The registers begin with iDest and increase consecutively.
|
| +** One register is initialized for each characgter in zTypes[]. For each
|
| +** "s" character in zTypes[], the register is a string if the argument is
|
| +** not NULL, or OP_Null if the value is a null pointer. For each "i" character
|
| +** in zTypes[], the register is initialized to an integer.
|
| +*/
|
| +void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){
|
| + va_list ap;
|
| + int i;
|
| + char c;
|
| + va_start(ap, zTypes);
|
| + for(i=0; (c = zTypes[i])!=0; i++){
|
| + if( c=='s' ){
|
| + const char *z = va_arg(ap, const char*);
|
| + int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++);
|
| + if( z ) sqlite3VdbeChangeP4(p, addr, z, 0);
|
| + }else{
|
| + assert( c=='i' );
|
| + sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
|
| + }
|
| + }
|
| + va_end(ap);
|
| +}
|
|
|
| /*
|
| ** Add an opcode that includes the p4 value as a pointer.
|
| @@ -223,6 +278,24 @@ int sqlite3VdbeAddOp4(
|
| }
|
|
|
| /*
|
| +** Add an opcode that includes the p4 value with a P4_INT64 or
|
| +** P4_REAL type.
|
| +*/
|
| +int sqlite3VdbeAddOp4Dup8(
|
| + Vdbe *p, /* Add the opcode to this VM */
|
| + int op, /* The new opcode */
|
| + int p1, /* The P1 operand */
|
| + int p2, /* The P2 operand */
|
| + int p3, /* The P3 operand */
|
| + const u8 *zP4, /* The P4 operand */
|
| + int p4type /* P4 operand type */
|
| +){
|
| + char *p4copy = sqlite3DbMallocRaw(sqlite3VdbeDb(p), 8);
|
| + if( p4copy ) memcpy(p4copy, zP4, 8);
|
| + return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type);
|
| +}
|
| +
|
| +/*
|
| ** Add an OP_ParseSchema opcode. This routine is broken out from
|
| ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
|
| ** as having been used.
|
| @@ -278,7 +351,7 @@ int sqlite3VdbeMakeLabel(Vdbe *v){
|
| if( p->aLabel ){
|
| p->aLabel[i] = -1;
|
| }
|
| - return -1-i;
|
| + return ADDR(i);
|
| }
|
|
|
| /*
|
| @@ -288,10 +361,11 @@ int sqlite3VdbeMakeLabel(Vdbe *v){
|
| */
|
| void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
| Parse *p = v->pParse;
|
| - int j = -1-x;
|
| + int j = ADDR(x);
|
| assert( v->magic==VDBE_MAGIC_INIT );
|
| assert( j<p->nLabel );
|
| - if( ALWAYS(j>=0) && p->aLabel ){
|
| + assert( j>=0 );
|
| + if( p->aLabel ){
|
| p->aLabel[j] = v->nOp;
|
| }
|
| p->iFixedOp = v->nOp - 1;
|
| @@ -386,6 +460,7 @@ static Op *opIterNext(VdbeOpIter *p){
|
| ** * OP_VUpdate
|
| ** * OP_VRename
|
| ** * OP_FkCounter with P2==0 (immediate foreign key constraint)
|
| +** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
|
| **
|
| ** Then check that the value of Parse.mayAbort is true if an
|
| ** ABORT may be thrown, or false otherwise. Return true if it does
|
| @@ -396,6 +471,9 @@ static Op *opIterNext(VdbeOpIter *p){
|
| */
|
| int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
| int hasAbort = 0;
|
| + int hasFkCounter = 0;
|
| + int hasCreateTable = 0;
|
| + int hasInitCoroutine = 0;
|
| Op *pOp;
|
| VdbeOpIter sIter;
|
| memset(&sIter, 0, sizeof(sIter));
|
| @@ -404,15 +482,19 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
| while( (pOp = opIterNext(&sIter))!=0 ){
|
| int opcode = pOp->opcode;
|
| if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|
| -#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| - || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
|
| -#endif
|
| || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
|
| && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
|
| ){
|
| hasAbort = 1;
|
| break;
|
| }
|
| + if( opcode==OP_CreateTable ) hasCreateTable = 1;
|
| + if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| + if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
|
| + hasFkCounter = 1;
|
| + }
|
| +#endif
|
| }
|
| sqlite3DbFree(v->db, sIter.apSub);
|
|
|
| @@ -421,22 +503,27 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
| ** through all opcodes and hasAbort may be set incorrectly. Return
|
| ** true for this case to prevent the assert() in the callers frame
|
| ** from failing. */
|
| - return ( v->db->mallocFailed || hasAbort==mayAbort );
|
| + return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter
|
| + || (hasCreateTable && hasInitCoroutine) );
|
| }
|
| #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
|
|
|
| /*
|
| -** Loop through the program looking for P2 values that are negative
|
| -** on jump instructions. Each such value is a label. Resolve the
|
| -** label by setting the P2 value to its correct non-zero value.
|
| +** This routine is called after all opcodes have been inserted. It loops
|
| +** through all the opcodes and fixes up some details.
|
| **
|
| -** This routine is called once after all opcodes have been inserted.
|
| +** (1) For each jump instruction with a negative P2 value (a label)
|
| +** resolve the P2 value to an actual address.
|
| **
|
| -** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
|
| -** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by
|
| -** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
|
| +** (2) Compute the maximum number of arguments used by any SQL function
|
| +** and store that value in *pMaxFuncArgs.
|
| **
|
| -** The Op.opflags field is set on all opcodes.
|
| +** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately
|
| +** indicate what the prepared statement actually does.
|
| +**
|
| +** (4) Initialize the p4.xAdvance pointer on opcodes that use it.
|
| +**
|
| +** (5) Reclaim the memory allocated for storing labels.
|
| */
|
| static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
| int i;
|
| @@ -452,11 +539,6 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
| /* NOTE: Be sure to update mkopcodeh.awk when adding or removing
|
| ** cases from this switch! */
|
| switch( opcode ){
|
| - case OP_Function:
|
| - case OP_AggStep: {
|
| - if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
|
| - break;
|
| - }
|
| case OP_Transaction: {
|
| if( pOp->p2!=0 ) p->readOnly = 0;
|
| /* fall thru */
|
| @@ -506,8 +588,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
|
|
| pOp->opflags = sqlite3OpcodeProperty[opcode];
|
| if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
|
| - assert( -1-pOp->p2<pParse->nLabel );
|
| - pOp->p2 = aLabel[-1-pOp->p2];
|
| + assert( ADDR(pOp->p2)<pParse->nLabel );
|
| + pOp->p2 = aLabel[ADDR(pOp->p2)];
|
| }
|
| }
|
| sqlite3DbFree(p->db, pParse->aLabel);
|
| @@ -554,93 +636,88 @@ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
|
| ** address of the first operation added.
|
| */
|
| int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
|
| - int addr;
|
| + int addr, i;
|
| + VdbeOp *pOut;
|
| + assert( nOp>0 );
|
| assert( p->magic==VDBE_MAGIC_INIT );
|
| if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
|
| return 0;
|
| }
|
| addr = p->nOp;
|
| - if( ALWAYS(nOp>0) ){
|
| - int i;
|
| - VdbeOpList const *pIn = aOp;
|
| - for(i=0; i<nOp; i++, pIn++){
|
| - int p2 = pIn->p2;
|
| - VdbeOp *pOut = &p->aOp[i+addr];
|
| - pOut->opcode = pIn->opcode;
|
| - pOut->p1 = pIn->p1;
|
| - if( p2<0 ){
|
| - assert( sqlite3OpcodeProperty[pOut->opcode] & OPFLG_JUMP );
|
| - pOut->p2 = addr + ADDR(p2);
|
| - }else{
|
| - pOut->p2 = p2;
|
| - }
|
| - pOut->p3 = pIn->p3;
|
| - pOut->p4type = P4_NOTUSED;
|
| - pOut->p4.p = 0;
|
| - pOut->p5 = 0;
|
| + pOut = &p->aOp[addr];
|
| + for(i=0; i<nOp; i++, aOp++, pOut++){
|
| + pOut->opcode = aOp->opcode;
|
| + pOut->p1 = aOp->p1;
|
| + pOut->p2 = aOp->p2;
|
| + assert( aOp->p2>=0 );
|
| + pOut->p3 = aOp->p3;
|
| + pOut->p4type = P4_NOTUSED;
|
| + pOut->p4.p = 0;
|
| + pOut->p5 = 0;
|
| #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
| - pOut->zComment = 0;
|
| + pOut->zComment = 0;
|
| #endif
|
| #ifdef SQLITE_VDBE_COVERAGE
|
| - pOut->iSrcLine = iLineno+i;
|
| + pOut->iSrcLine = iLineno+i;
|
| #else
|
| - (void)iLineno;
|
| + (void)iLineno;
|
| #endif
|
| #ifdef SQLITE_DEBUG
|
| - if( p->db->flags & SQLITE_VdbeAddopTrace ){
|
| - sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
|
| - }
|
| -#endif
|
| + if( p->db->flags & SQLITE_VdbeAddopTrace ){
|
| + sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
|
| }
|
| - p->nOp += nOp;
|
| +#endif
|
| }
|
| + p->nOp += nOp;
|
| return addr;
|
| }
|
|
|
| +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
|
| /*
|
| -** Change the value of the P1 operand for a specific instruction.
|
| -** This routine is useful when a large program is loaded from a
|
| -** static array using sqlite3VdbeAddOpList but we want to make a
|
| -** few minor changes to the program.
|
| +** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus().
|
| */
|
| -void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){
|
| - assert( p!=0 );
|
| - if( ((u32)p->nOp)>addr ){
|
| - p->aOp[addr].p1 = val;
|
| +void sqlite3VdbeScanStatus(
|
| + Vdbe *p, /* VM to add scanstatus() to */
|
| + int addrExplain, /* Address of OP_Explain (or 0) */
|
| + int addrLoop, /* Address of loop counter */
|
| + int addrVisit, /* Address of rows visited counter */
|
| + LogEst nEst, /* Estimated number of output rows */
|
| + const char *zName /* Name of table or index being scanned */
|
| +){
|
| + int nByte = (p->nScan+1) * sizeof(ScanStatus);
|
| + ScanStatus *aNew;
|
| + aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
|
| + if( aNew ){
|
| + ScanStatus *pNew = &aNew[p->nScan++];
|
| + pNew->addrExplain = addrExplain;
|
| + pNew->addrLoop = addrLoop;
|
| + pNew->addrVisit = addrVisit;
|
| + pNew->nEst = nEst;
|
| + pNew->zName = sqlite3DbStrDup(p->db, zName);
|
| + p->aScan = aNew;
|
| }
|
| }
|
| +#endif
|
| +
|
|
|
| /*
|
| -** Change the value of the P2 operand for a specific instruction.
|
| -** This routine is useful for setting a jump destination.
|
| +** Change the value of the opcode, or P1, P2, P3, or P5 operands
|
| +** for a specific instruction.
|
| */
|
| +void sqlite3VdbeChangeOpcode(Vdbe *p, u32 addr, u8 iNewOpcode){
|
| + sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
|
| +}
|
| +void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){
|
| + sqlite3VdbeGetOp(p,addr)->p1 = val;
|
| +}
|
| void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
|
| - assert( p!=0 );
|
| - if( ((u32)p->nOp)>addr ){
|
| - p->aOp[addr].p2 = val;
|
| - }
|
| + sqlite3VdbeGetOp(p,addr)->p2 = val;
|
| }
|
| -
|
| -/*
|
| -** Change the value of the P3 operand for a specific instruction.
|
| -*/
|
| void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
|
| - assert( p!=0 );
|
| - if( ((u32)p->nOp)>addr ){
|
| - p->aOp[addr].p3 = val;
|
| - }
|
| + sqlite3VdbeGetOp(p,addr)->p3 = val;
|
| }
|
| -
|
| -/*
|
| -** Change the value of the P5 operand for the most recently
|
| -** added operation.
|
| -*/
|
| -void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
|
| - assert( p!=0 );
|
| - if( p->aOp ){
|
| - assert( p->nOp>0 );
|
| - p->aOp[p->nOp-1].p5 = val;
|
| - }
|
| +void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
|
| + sqlite3VdbeGetOp(p,-1)->p5 = p5;
|
| }
|
|
|
| /*
|
| @@ -648,8 +725,8 @@ void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
|
| ** the address of the next instruction to be coded.
|
| */
|
| void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
| - sqlite3VdbeChangeP2(p, addr, p->nOp);
|
| p->pParse->iFixedOp = p->nOp - 1;
|
| + sqlite3VdbeChangeP2(p, addr, p->nOp);
|
| }
|
|
|
|
|
| @@ -672,6 +749,10 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
| if( p4 ){
|
| assert( db );
|
| switch( p4type ){
|
| + case P4_FUNCCTX: {
|
| + freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc);
|
| + /* Fall through into the next case */
|
| + }
|
| case P4_REAL:
|
| case P4_INT64:
|
| case P4_DYNAMIC:
|
| @@ -683,6 +764,12 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
| if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
|
| break;
|
| }
|
| +#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
| + case P4_EXPR: {
|
| + sqlite3ExprDelete(db, (Expr*)p4);
|
| + break;
|
| + }
|
| +#endif
|
| case P4_MPRINTF: {
|
| if( db->pnBytesFreed==0 ) sqlite3_free(p4);
|
| break;
|
| @@ -747,7 +834,6 @@ void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
|
| freeP4(db, pOp->p4type, pOp->p4.p);
|
| memset(pOp, 0, sizeof(pOp[0]));
|
| pOp->opcode = OP_Noop;
|
| - if( addr==p->nOp-1 ) p->nOp--;
|
| }
|
| }
|
|
|
| @@ -815,6 +901,15 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
| }else if( n==P4_KEYINFO ){
|
| pOp->p4.p = (void*)zP4;
|
| pOp->p4type = P4_KEYINFO;
|
| +#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
| + }else if( n==P4_EXPR ){
|
| + /* Responsibility for deleting the Expr tree is handed over to the
|
| + ** VDBE by this operation. The caller should have already invoked
|
| + ** sqlite3ExprDup() or whatever other routine is needed to make a
|
| + ** private copy of the tree. */
|
| + pOp->p4.pExpr = (Expr*)zP4;
|
| + pOp->p4type = P4_EXPR;
|
| +#endif
|
| }else if( n==P4_VTAB ){
|
| pOp->p4.p = (void*)zP4;
|
| pOp->p4type = P4_VTAB;
|
| @@ -1005,9 +1100,84 @@ static int displayComment(
|
| }
|
| #endif /* SQLITE_DEBUG */
|
|
|
| +#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
|
| +/*
|
| +** Translate the P4.pExpr value for an OP_CursorHint opcode into text
|
| +** that can be displayed in the P4 column of EXPLAIN output.
|
| +*/
|
| +static int displayP4Expr(int nTemp, char *zTemp, Expr *pExpr){
|
| + const char *zOp = 0;
|
| + int n;
|
| + switch( pExpr->op ){
|
| + case TK_STRING:
|
| + sqlite3_snprintf(nTemp, zTemp, "%Q", pExpr->u.zToken);
|
| + break;
|
| + case TK_INTEGER:
|
| + sqlite3_snprintf(nTemp, zTemp, "%d", pExpr->u.iValue);
|
| + break;
|
| + case TK_NULL:
|
| + sqlite3_snprintf(nTemp, zTemp, "NULL");
|
| + break;
|
| + case TK_REGISTER: {
|
| + sqlite3_snprintf(nTemp, zTemp, "r[%d]", pExpr->iTable);
|
| + break;
|
| + }
|
| + case TK_COLUMN: {
|
| + if( pExpr->iColumn<0 ){
|
| + sqlite3_snprintf(nTemp, zTemp, "rowid");
|
| + }else{
|
| + sqlite3_snprintf(nTemp, zTemp, "c%d", (int)pExpr->iColumn);
|
| + }
|
| + break;
|
| + }
|
| + case TK_LT: zOp = "LT"; break;
|
| + case TK_LE: zOp = "LE"; break;
|
| + case TK_GT: zOp = "GT"; break;
|
| + case TK_GE: zOp = "GE"; break;
|
| + case TK_NE: zOp = "NE"; break;
|
| + case TK_EQ: zOp = "EQ"; break;
|
| + case TK_IS: zOp = "IS"; break;
|
| + case TK_ISNOT: zOp = "ISNOT"; break;
|
| + case TK_AND: zOp = "AND"; break;
|
| + case TK_OR: zOp = "OR"; break;
|
| + case TK_PLUS: zOp = "ADD"; break;
|
| + case TK_STAR: zOp = "MUL"; break;
|
| + case TK_MINUS: zOp = "SUB"; break;
|
| + case TK_REM: zOp = "REM"; break;
|
| + case TK_BITAND: zOp = "BITAND"; break;
|
| + case TK_BITOR: zOp = "BITOR"; break;
|
| + case TK_SLASH: zOp = "DIV"; break;
|
| + case TK_LSHIFT: zOp = "LSHIFT"; break;
|
| + case TK_RSHIFT: zOp = "RSHIFT"; break;
|
| + case TK_CONCAT: zOp = "CONCAT"; break;
|
| + case TK_UMINUS: zOp = "MINUS"; break;
|
| + case TK_UPLUS: zOp = "PLUS"; break;
|
| + case TK_BITNOT: zOp = "BITNOT"; break;
|
| + case TK_NOT: zOp = "NOT"; break;
|
| + case TK_ISNULL: zOp = "ISNULL"; break;
|
| + case TK_NOTNULL: zOp = "NOTNULL"; break;
|
| +
|
| + default:
|
| + sqlite3_snprintf(nTemp, zTemp, "%s", "expr");
|
| + break;
|
| + }
|
|
|
| -#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|
| - || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
| + if( zOp ){
|
| + sqlite3_snprintf(nTemp, zTemp, "%s(", zOp);
|
| + n = sqlite3Strlen30(zTemp);
|
| + n += displayP4Expr(nTemp-n, zTemp+n, pExpr->pLeft);
|
| + if( n<nTemp-1 && pExpr->pRight ){
|
| + zTemp[n++] = ',';
|
| + n += displayP4Expr(nTemp-n, zTemp+n, pExpr->pRight);
|
| + }
|
| + sqlite3_snprintf(nTemp-n, zTemp+n, ")");
|
| + }
|
| + return sqlite3Strlen30(zTemp);
|
| +}
|
| +#endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */
|
| +
|
| +
|
| +#if VDBE_DISPLAY_P4
|
| /*
|
| ** Compute a string that describes the P4 parameter for an opcode.
|
| ** Use zTemp for any required temporary buffer space.
|
| @@ -1030,8 +1200,9 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
| zColl = "B";
|
| n = 1;
|
| }
|
| - if( i+n>nTemp-6 ){
|
| + if( i+n>nTemp-7 ){
|
| memcpy(&zTemp[i],",...",4);
|
| + i += 4;
|
| break;
|
| }
|
| zTemp[i++] = ',';
|
| @@ -1046,6 +1217,12 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
| assert( i<nTemp );
|
| break;
|
| }
|
| +#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
| + case P4_EXPR: {
|
| + displayP4Expr(nTemp, zTemp, pOp->p4.pExpr);
|
| + break;
|
| + }
|
| +#endif
|
| case P4_COLLSEQ: {
|
| CollSeq *pColl = pOp->p4.pColl;
|
| sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName);
|
| @@ -1056,6 +1233,13 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
| sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
|
| break;
|
| }
|
| +#ifdef SQLITE_DEBUG
|
| + case P4_FUNCCTX: {
|
| + FuncDef *pDef = pOp->p4.pCtx->pFunc;
|
| + sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
|
| + break;
|
| + }
|
| +#endif
|
| case P4_INT64: {
|
| sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64);
|
| break;
|
| @@ -1087,7 +1271,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| case P4_VTAB: {
|
| sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
|
| - sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
|
| + sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab);
|
| break;
|
| }
|
| #endif
|
| @@ -1114,7 +1298,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
| assert( zP4!=0 );
|
| return zP4;
|
| }
|
| -#endif
|
| +#endif /* VDBE_DISPLAY_P4 */
|
|
|
| /*
|
| ** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
|
| @@ -1176,12 +1360,11 @@ void sqlite3VdbeEnter(Vdbe *p){
|
| /*
|
| ** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
|
| */
|
| -void sqlite3VdbeLeave(Vdbe *p){
|
| +static SQLITE_NOINLINE void vdbeLeave(Vdbe *p){
|
| int i;
|
| sqlite3 *db;
|
| Db *aDb;
|
| int nDb;
|
| - if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
|
| db = p->db;
|
| aDb = db->aDb;
|
| nDb = db->nDb;
|
| @@ -1191,6 +1374,10 @@ void sqlite3VdbeLeave(Vdbe *p){
|
| }
|
| }
|
| }
|
| +void sqlite3VdbeLeave(Vdbe *p){
|
| + if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
|
| + vdbeLeave(p);
|
| +}
|
| #endif
|
|
|
| #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
| @@ -1363,7 +1550,7 @@ int sqlite3VdbeList(
|
| }else if( db->u1.isInterrupted ){
|
| p->rc = SQLITE_INTERRUPT;
|
| rc = SQLITE_ERROR;
|
| - sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(p->rc));
|
| + sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
|
| }else{
|
| char *zP4;
|
| Op *pOp;
|
| @@ -1425,12 +1612,12 @@ int sqlite3VdbeList(
|
| pMem->u.i = pOp->p3; /* P3 */
|
| pMem++;
|
|
|
| - if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */
|
| + if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
|
| assert( p->db->mallocFailed );
|
| return SQLITE_ERROR;
|
| }
|
| pMem->flags = MEM_Str|MEM_Term;
|
| - zP4 = displayP4(pOp, pMem->z, 32);
|
| + zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
|
| if( zP4!=pMem->z ){
|
| sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
|
| }else{
|
| @@ -1535,30 +1722,31 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
|
| **
|
| ** nByte is the number of bytes of space needed.
|
| **
|
| -** *ppFrom points to available space and pEnd points to the end of the
|
| -** available space. When space is allocated, *ppFrom is advanced past
|
| -** the end of the allocated space.
|
| +** pFrom points to *pnFrom bytes of available space. New space is allocated
|
| +** from the end of the pFrom buffer and *pnFrom is decremented.
|
| **
|
| -** *pnByte is a counter of the number of bytes of space that have failed
|
| -** to allocate. If there is insufficient space in *ppFrom to satisfy the
|
| -** request, then increment *pnByte by the amount of the request.
|
| +** *pnNeeded is a counter of the number of bytes of space that have failed
|
| +** to allocate. If there is insufficient space in pFrom to satisfy the
|
| +** request, then increment *pnNeeded by the amount of the request.
|
| */
|
| static void *allocSpace(
|
| void *pBuf, /* Where return pointer will be stored */
|
| int nByte, /* Number of bytes to allocate */
|
| - u8 **ppFrom, /* IN/OUT: Allocate from *ppFrom */
|
| - u8 *pEnd, /* Pointer to 1 byte past the end of *ppFrom buffer */
|
| - int *pnByte /* If allocation cannot be made, increment *pnByte */
|
| + u8 *pFrom, /* Memory available for allocation */
|
| + int *pnFrom, /* IN/OUT: Space available at pFrom */
|
| + int *pnNeeded /* If allocation cannot be made, increment *pnByte */
|
| ){
|
| - assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) );
|
| - if( pBuf ) return pBuf;
|
| - nByte = ROUND8(nByte);
|
| - if( &(*ppFrom)[nByte] <= pEnd ){
|
| - pBuf = (void*)*ppFrom;
|
| - *ppFrom += nByte;
|
| - }else{
|
| - *pnByte += nByte;
|
| + assert( EIGHT_BYTE_ALIGNMENT(pFrom) );
|
| + if( pBuf==0 ){
|
| + nByte = ROUND8(nByte);
|
| + if( nByte <= *pnFrom ){
|
| + *pnFrom -= nByte;
|
| + pBuf = &pFrom[*pnFrom];
|
| + }else{
|
| + *pnNeeded += nByte;
|
| + }
|
| }
|
| + assert( EIGHT_BYTE_ALIGNMENT(pBuf) );
|
| return pBuf;
|
| }
|
|
|
| @@ -1631,8 +1819,8 @@ void sqlite3VdbeMakeReady(
|
| int nArg; /* Number of arguments in subprograms */
|
| int nOnce; /* Number of OP_Once instructions */
|
| int n; /* Loop counter */
|
| + int nFree; /* Available free space */
|
| u8 *zCsr; /* Memory available for allocation */
|
| - u8 *zEnd; /* First byte past allocated memory */
|
| int nByte; /* How much extra memory is needed */
|
|
|
| assert( p!=0 );
|
| @@ -1660,20 +1848,27 @@ void sqlite3VdbeMakeReady(
|
| */
|
| nMem += nCursor;
|
|
|
| - /* Allocate space for memory registers, SQL variables, VDBE cursors and
|
| - ** an array to marshal SQL function arguments in.
|
| + /* zCsr will initially point to nFree bytes of unused space at the
|
| + ** end of the opcode array, p->aOp. The computation of nFree is
|
| + ** conservative - it might be smaller than the true number of free
|
| + ** bytes, but never larger. nFree must be a multiple of 8 - it is
|
| + ** rounded down if is not.
|
| */
|
| - zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */
|
| - zEnd = (u8*)&p->aOp[pParse->nOpAlloc]; /* First byte past end of zCsr[] */
|
| + n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode space used */
|
| + zCsr = &((u8*)p->aOp)[n]; /* Unused opcode space */
|
| + assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
|
| + nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused space */
|
| + assert( nFree>=0 );
|
| + if( nFree>0 ){
|
| + memset(zCsr, 0, nFree);
|
| + assert( EIGHT_BYTE_ALIGNMENT(&zCsr[nFree]) );
|
| + }
|
|
|
| resolveP2Values(p, &nArg);
|
| p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
|
| if( pParse->explain && nMem<10 ){
|
| nMem = 10;
|
| }
|
| - memset(zCsr, 0, zEnd-zCsr);
|
| - zCsr += (zCsr - (u8*)0)&7;
|
| - assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
|
| p->expired = 0;
|
|
|
| /* Memory for registers, parameters, cursor, etc, is allocated in two
|
| @@ -1688,18 +1883,21 @@ void sqlite3VdbeMakeReady(
|
| */
|
| do {
|
| nByte = 0;
|
| - p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
|
| - p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
|
| - p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
|
| - p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
| + p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte);
|
| + p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte);
|
| + p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte);
|
| + p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), zCsr, &nFree, &nByte);
|
| p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
|
| - &zCsr, zEnd, &nByte);
|
| - p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
|
| + zCsr, &nFree, &nByte);
|
| + p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte);
|
| +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
| + p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte);
|
| +#endif
|
| if( nByte ){
|
| p->pFree = sqlite3DbMallocZero(db, nByte);
|
| }
|
| zCsr = p->pFree;
|
| - zEnd = &zCsr[nByte];
|
| + nFree = nByte;
|
| }while( nByte && !db->mallocFailed );
|
|
|
| p->nCursor = nCursor;
|
| @@ -1711,7 +1909,7 @@ void sqlite3VdbeMakeReady(
|
| p->aVar[n].db = db;
|
| }
|
| }
|
| - if( p->azVar ){
|
| + if( p->azVar && pParse->nzVar>0 ){
|
| p->nzVar = pParse->nzVar;
|
| memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
|
| memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
|
| @@ -1736,23 +1934,50 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
| if( pCx==0 ){
|
| return;
|
| }
|
| - sqlite3VdbeSorterClose(p->db, pCx);
|
| - if( pCx->pBt ){
|
| - sqlite3BtreeClose(pCx->pBt);
|
| - /* The pCx->pCursor will be close automatically, if it exists, by
|
| - ** the call above. */
|
| - }else if( pCx->pCursor ){
|
| - sqlite3BtreeCloseCursor(pCx->pCursor);
|
| - }
|
| + assert( pCx->pBt==0 || pCx->eCurType==CURTYPE_BTREE );
|
| + switch( pCx->eCurType ){
|
| + case CURTYPE_SORTER: {
|
| + sqlite3VdbeSorterClose(p->db, pCx);
|
| + break;
|
| + }
|
| + case CURTYPE_BTREE: {
|
| + if( pCx->pBt ){
|
| + sqlite3BtreeClose(pCx->pBt);
|
| + /* The pCx->pCursor will be close automatically, if it exists, by
|
| + ** the call above. */
|
| + }else{
|
| + assert( pCx->uc.pCursor!=0 );
|
| + sqlite3BtreeCloseCursor(pCx->uc.pCursor);
|
| + }
|
| + break;
|
| + }
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| - else if( pCx->pVtabCursor ){
|
| - sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
|
| - const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
|
| - p->inVtabMethod = 1;
|
| - pModule->xClose(pVtabCursor);
|
| - p->inVtabMethod = 0;
|
| - }
|
| + case CURTYPE_VTAB: {
|
| + sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
|
| + const sqlite3_module *pModule = pVCur->pVtab->pModule;
|
| + assert( pVCur->pVtab->nRef>0 );
|
| + pVCur->pVtab->nRef--;
|
| + pModule->xClose(pVCur);
|
| + break;
|
| + }
|
| #endif
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Close all cursors in the current frame.
|
| +*/
|
| +static void closeCursorsInFrame(Vdbe *p){
|
| + if( p->apCsr ){
|
| + int i;
|
| + for(i=0; i<p->nCursor; i++){
|
| + VdbeCursor *pC = p->apCsr[i];
|
| + if( pC ){
|
| + sqlite3VdbeFreeCursor(p, pC);
|
| + p->apCsr[i] = 0;
|
| + }
|
| + }
|
| + }
|
| }
|
|
|
| /*
|
| @@ -1762,6 +1987,10 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
| */
|
| int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
| Vdbe *v = pFrame->v;
|
| + closeCursorsInFrame(v);
|
| +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
| + v->anExec = pFrame->anExec;
|
| +#endif
|
| v->aOnceFlag = pFrame->aOnceFlag;
|
| v->nOnceFlag = pFrame->nOnceFlag;
|
| v->aOp = pFrame->aOp;
|
| @@ -1772,6 +2001,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
| v->nCursor = pFrame->nCursor;
|
| v->db->lastRowid = pFrame->lastRowid;
|
| v->nChange = pFrame->nChange;
|
| + v->db->nChange = pFrame->nDbChange;
|
| return pFrame->pc;
|
| }
|
|
|
| @@ -1792,17 +2022,7 @@ static void closeAllCursors(Vdbe *p){
|
| p->nFrame = 0;
|
| }
|
| assert( p->nFrame==0 );
|
| -
|
| - if( p->apCsr ){
|
| - int i;
|
| - for(i=0; i<p->nCursor; i++){
|
| - VdbeCursor *pC = p->apCsr[i];
|
| - if( pC ){
|
| - sqlite3VdbeFreeCursor(p, pC);
|
| - p->apCsr[i] = 0;
|
| - }
|
| - }
|
| - }
|
| + closeCursorsInFrame(p);
|
| if( p->aMem ){
|
| releaseMemArray(&p->aMem[1], p->nMem);
|
| }
|
| @@ -2105,7 +2325,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
| ** doing this the directory is synced again before any individual
|
| ** transaction files are deleted.
|
| */
|
| - rc = sqlite3OsDelete(pVfs, zMaster, 1);
|
| + rc = sqlite3OsDelete(pVfs, zMaster, needSync);
|
| sqlite3DbFree(db, zMaster);
|
| zMaster = 0;
|
| if( rc ){
|
| @@ -2252,7 +2472,7 @@ int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
|
| ){
|
| p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
|
| p->errorAction = OE_Abort;
|
| - sqlite3SetString(&p->zErrMsg, db, "FOREIGN KEY constraint failed");
|
| + sqlite3VdbeError(p, "FOREIGN KEY constraint failed");
|
| return SQLITE_ERROR;
|
| }
|
| return SQLITE_OK;
|
| @@ -2339,6 +2559,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
|
| sqlite3CloseSavepoints(db);
|
| db->autoCommit = 1;
|
| + p->nChange = 0;
|
| }
|
| }
|
| }
|
| @@ -2379,6 +2600,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| }else if( rc!=SQLITE_OK ){
|
| p->rc = rc;
|
| sqlite3RollbackAll(db, SQLITE_OK);
|
| + p->nChange = 0;
|
| }else{
|
| db->nDeferredCons = 0;
|
| db->nDeferredImmCons = 0;
|
| @@ -2387,6 +2609,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| }
|
| }else{
|
| sqlite3RollbackAll(db, SQLITE_OK);
|
| + p->nChange = 0;
|
| }
|
| db->nStatement = 0;
|
| }else if( eStatementOp==0 ){
|
| @@ -2398,6 +2621,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
|
| sqlite3CloseSavepoints(db);
|
| db->autoCommit = 1;
|
| + p->nChange = 0;
|
| }
|
| }
|
|
|
| @@ -2418,6 +2642,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
|
| sqlite3CloseSavepoints(db);
|
| db->autoCommit = 1;
|
| + p->nChange = 0;
|
| }
|
| }
|
|
|
| @@ -2679,6 +2904,12 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
|
| sqlite3DbFree(db, p->aColName);
|
| sqlite3DbFree(db, p->zSql);
|
| sqlite3DbFree(db, p->pFree);
|
| +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
| + for(i=0; i<p->nScan; i++){
|
| + sqlite3DbFree(db, p->aScan[i].zName);
|
| + }
|
| + sqlite3DbFree(db, p->aScan);
|
| +#endif
|
| }
|
|
|
| /*
|
| @@ -2717,7 +2948,8 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
|
| #endif
|
| assert( p->deferredMoveto );
|
| assert( p->isTable );
|
| - rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
|
| + assert( p->eCurType==CURTYPE_BTREE );
|
| + rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res);
|
| if( rc ) return rc;
|
| if( res!=0 ) return SQLITE_CORRUPT_BKPT;
|
| #ifdef SQLITE_TEST
|
| @@ -2737,9 +2969,10 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
|
| */
|
| static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
|
| int isDifferentRow, rc;
|
| - assert( p->pCursor!=0 );
|
| - assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
|
| - rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
|
| + assert( p->eCurType==CURTYPE_BTREE );
|
| + assert( p->uc.pCursor!=0 );
|
| + assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) );
|
| + rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow);
|
| p->cacheStatus = CACHE_STALE;
|
| if( isDifferentRow ) p->nullRow = 1;
|
| return rc;
|
| @@ -2750,7 +2983,8 @@ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
|
| ** if need be. Return any I/O error from the restore operation.
|
| */
|
| int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
| - if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
|
| + assert( p->eCurType==CURTYPE_BTREE );
|
| + if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
| return handleMovedCursor(p);
|
| }
|
| return SQLITE_OK;
|
| @@ -2770,11 +3004,13 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
| ** not been deleted out from under the cursor, then this routine is a no-op.
|
| */
|
| int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
| - if( p->deferredMoveto ){
|
| - return handleDeferredMoveto(p);
|
| - }
|
| - if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){
|
| - return handleMovedCursor(p);
|
| + if( p->eCurType==CURTYPE_BTREE ){
|
| + if( p->deferredMoveto ){
|
| + return handleDeferredMoveto(p);
|
| + }
|
| + if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
| + return handleMovedCursor(p);
|
| + }
|
| }
|
| return SQLITE_OK;
|
| }
|
| @@ -2824,11 +3060,13 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
| /*
|
| ** Return the serial-type for the value stored in pMem.
|
| */
|
| -u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
| +u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
|
| int flags = pMem->flags;
|
| u32 n;
|
|
|
| + assert( pLen!=0 );
|
| if( flags&MEM_Null ){
|
| + *pLen = 0;
|
| return 0;
|
| }
|
| if( flags&MEM_Int ){
|
| @@ -2837,22 +3075,28 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
| i64 i = pMem->u.i;
|
| u64 u;
|
| if( i<0 ){
|
| - if( i<(-MAX_6BYTE) ) return 6;
|
| - /* Previous test prevents: u = -(-9223372036854775808) */
|
| - u = -i;
|
| + u = ~i;
|
| }else{
|
| u = i;
|
| }
|
| if( u<=127 ){
|
| - return ((i&1)==i && file_format>=4) ? 8+(u32)u : 1;
|
| + if( (i&1)==i && file_format>=4 ){
|
| + *pLen = 0;
|
| + return 8+(u32)u;
|
| + }else{
|
| + *pLen = 1;
|
| + return 1;
|
| + }
|
| }
|
| - if( u<=32767 ) return 2;
|
| - if( u<=8388607 ) return 3;
|
| - if( u<=2147483647 ) return 4;
|
| - if( u<=MAX_6BYTE ) return 5;
|
| + if( u<=32767 ){ *pLen = 2; return 2; }
|
| + if( u<=8388607 ){ *pLen = 3; return 3; }
|
| + if( u<=2147483647 ){ *pLen = 4; return 4; }
|
| + if( u<=MAX_6BYTE ){ *pLen = 6; return 5; }
|
| + *pLen = 8;
|
| return 6;
|
| }
|
| if( flags&MEM_Real ){
|
| + *pLen = 8;
|
| return 7;
|
| }
|
| assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) );
|
| @@ -2861,20 +3105,46 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
| if( flags & MEM_Zero ){
|
| n += pMem->u.nZero;
|
| }
|
| + *pLen = n;
|
| return ((n*2) + 12 + ((flags&MEM_Str)!=0));
|
| }
|
|
|
| /*
|
| +** The sizes for serial types less than 128
|
| +*/
|
| +static const u8 sqlite3SmallTypeSizes[] = {
|
| + /* 0 1 2 3 4 5 6 7 8 9 */
|
| +/* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0,
|
| +/* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
|
| +/* 20 */ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
| +/* 30 */ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
|
| +/* 40 */ 14, 14, 15, 15, 16, 16, 17, 17, 18, 18,
|
| +/* 50 */ 19, 19, 20, 20, 21, 21, 22, 22, 23, 23,
|
| +/* 60 */ 24, 24, 25, 25, 26, 26, 27, 27, 28, 28,
|
| +/* 70 */ 29, 29, 30, 30, 31, 31, 32, 32, 33, 33,
|
| +/* 80 */ 34, 34, 35, 35, 36, 36, 37, 37, 38, 38,
|
| +/* 90 */ 39, 39, 40, 40, 41, 41, 42, 42, 43, 43,
|
| +/* 100 */ 44, 44, 45, 45, 46, 46, 47, 47, 48, 48,
|
| +/* 110 */ 49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
|
| +/* 120 */ 54, 54, 55, 55, 56, 56, 57, 57
|
| +};
|
| +
|
| +/*
|
| ** Return the length of the data corresponding to the supplied serial-type.
|
| */
|
| u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
|
| - if( serial_type>=12 ){
|
| + if( serial_type>=128 ){
|
| return (serial_type-12)/2;
|
| }else{
|
| - static const u8 aSize[] = { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, 0, 0 };
|
| - return aSize[serial_type];
|
| + assert( serial_type<12
|
| + || sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 );
|
| + return sqlite3SmallTypeSizes[serial_type];
|
| }
|
| }
|
| +u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
|
| + assert( serial_type<128 );
|
| + return sqlite3SmallTypeSizes[serial_type];
|
| +}
|
|
|
| /*
|
| ** If we are on an architecture with mixed-endian floating
|
| @@ -2956,7 +3226,7 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
|
| }else{
|
| v = pMem->u.i;
|
| }
|
| - len = i = sqlite3VdbeSerialTypeLen(serial_type);
|
| + len = i = sqlite3SmallTypeSizes[serial_type];
|
| assert( i>0 );
|
| do{
|
| buf[--i] = (u8)(v&0xFF);
|
| @@ -2970,7 +3240,7 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
|
| assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
|
| == (int)sqlite3VdbeSerialTypeLen(serial_type) );
|
| len = pMem->n;
|
| - memcpy(buf, pMem->z, len);
|
| + if( len>0 ) memcpy(buf, pMem->z, len);
|
| return len;
|
| }
|
|
|
| @@ -3005,10 +3275,14 @@ static u32 SQLITE_NOINLINE serialGet(
|
| u32 y = FOUR_BYTE_UINT(buf+4);
|
| x = (x<<32) + y;
|
| if( serial_type==6 ){
|
| + /* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit
|
| + ** twos-complement integer. */
|
| pMem->u.i = *(i64*)&x;
|
| pMem->flags = MEM_Int;
|
| testcase( pMem->u.i<0 );
|
| }else{
|
| + /* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit
|
| + ** floating point number. */
|
| #if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
|
| /* Verify that integers and floating point values use the same
|
| ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
|
| @@ -3036,35 +3310,50 @@ u32 sqlite3VdbeSerialGet(
|
| switch( serial_type ){
|
| case 10: /* Reserved for future use */
|
| case 11: /* Reserved for future use */
|
| - case 0: { /* NULL */
|
| + case 0: { /* Null */
|
| + /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
|
| pMem->flags = MEM_Null;
|
| break;
|
| }
|
| - case 1: { /* 1-byte signed integer */
|
| + case 1: {
|
| + /* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement
|
| + ** integer. */
|
| pMem->u.i = ONE_BYTE_INT(buf);
|
| pMem->flags = MEM_Int;
|
| testcase( pMem->u.i<0 );
|
| return 1;
|
| }
|
| case 2: { /* 2-byte signed integer */
|
| + /* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit
|
| + ** twos-complement integer. */
|
| pMem->u.i = TWO_BYTE_INT(buf);
|
| pMem->flags = MEM_Int;
|
| testcase( pMem->u.i<0 );
|
| return 2;
|
| }
|
| case 3: { /* 3-byte signed integer */
|
| + /* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit
|
| + ** twos-complement integer. */
|
| pMem->u.i = THREE_BYTE_INT(buf);
|
| pMem->flags = MEM_Int;
|
| testcase( pMem->u.i<0 );
|
| return 3;
|
| }
|
| case 4: { /* 4-byte signed integer */
|
| + /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
|
| + ** twos-complement integer. */
|
| pMem->u.i = FOUR_BYTE_INT(buf);
|
| +#ifdef __HP_cc
|
| + /* Work around a sign-extension bug in the HP compiler for HP/UX */
|
| + if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL;
|
| +#endif
|
| pMem->flags = MEM_Int;
|
| testcase( pMem->u.i<0 );
|
| return 4;
|
| }
|
| case 5: { /* 6-byte signed integer */
|
| + /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit
|
| + ** twos-complement integer. */
|
| pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf);
|
| pMem->flags = MEM_Int;
|
| testcase( pMem->u.i<0 );
|
| @@ -3078,11 +3367,17 @@ u32 sqlite3VdbeSerialGet(
|
| }
|
| case 8: /* Integer 0 */
|
| case 9: { /* Integer 1 */
|
| + /* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */
|
| + /* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */
|
| pMem->u.i = serial_type-8;
|
| pMem->flags = MEM_Int;
|
| return 0;
|
| }
|
| default: {
|
| + /* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in
|
| + ** length.
|
| + ** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and
|
| + ** (N-13)/2 bytes in length. */
|
| static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem };
|
| pMem->z = (char *)buf;
|
| pMem->n = (serial_type-12)/2;
|
| @@ -3220,6 +3515,7 @@ static int vdbeRecordCompareDebug(
|
| /* mem1.u.i = 0; // not needed, here to silence compiler warning */
|
|
|
| idx1 = getVarint32(aKey1, szHdr1);
|
| + if( szHdr1>98307 ) return SQLITE_CORRUPT;
|
| d1 = szHdr1;
|
| assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
|
| assert( pKeyInfo->aSortOrder!=0 );
|
| @@ -3281,6 +3577,42 @@ debugCompareEnd:
|
| }
|
| #endif
|
|
|
| +#if SQLITE_DEBUG
|
| +/*
|
| +** Count the number of fields (a.k.a. columns) in the record given by
|
| +** pKey,nKey. The verify that this count is less than or equal to the
|
| +** limit given by pKeyInfo->nField + pKeyInfo->nXField.
|
| +**
|
| +** If this constraint is not satisfied, it means that the high-speed
|
| +** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
|
| +** not work correctly. If this assert() ever fires, it probably means
|
| +** that the KeyInfo.nField or KeyInfo.nXField values were computed
|
| +** incorrectly.
|
| +*/
|
| +static void vdbeAssertFieldCountWithinLimits(
|
| + int nKey, const void *pKey, /* The record to verify */
|
| + const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */
|
| +){
|
| + int nField = 0;
|
| + u32 szHdr;
|
| + u32 idx;
|
| + u32 notUsed;
|
| + const unsigned char *aKey = (const unsigned char*)pKey;
|
| +
|
| + if( CORRUPT_DB ) return;
|
| + idx = getVarint32(aKey, szHdr);
|
| + assert( nKey>=0 );
|
| + assert( szHdr<=(u32)nKey );
|
| + while( idx<szHdr ){
|
| + idx += getVarint32(aKey+idx, notUsed);
|
| + nField++;
|
| + }
|
| + assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
|
| +}
|
| +#else
|
| +# define vdbeAssertFieldCountWithinLimits(A,B,C)
|
| +#endif
|
| +
|
| /*
|
| ** Both *pMem1 and *pMem2 contain string values. Compare the two values
|
| ** using the collation sequence pColl. As usual, return a negative , zero
|
| @@ -3330,6 +3662,34 @@ static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
|
| return pB1->n - pB2->n;
|
| }
|
|
|
| +/*
|
| +** Do a comparison between a 64-bit signed integer and a 64-bit floating-point
|
| +** number. Return negative, zero, or positive if the first (i64) is less than,
|
| +** equal to, or greater than the second (double).
|
| +*/
|
| +static int sqlite3IntFloatCompare(i64 i, double r){
|
| + if( sizeof(LONGDOUBLE_TYPE)>8 ){
|
| + LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
|
| + if( x<r ) return -1;
|
| + if( x>r ) return +1;
|
| + return 0;
|
| + }else{
|
| + i64 y;
|
| + double s;
|
| + if( r<-9223372036854775808.0 ) return +1;
|
| + if( r>9223372036854775807.0 ) return -1;
|
| + y = (i64)r;
|
| + if( i<y ) return -1;
|
| + if( i>y ){
|
| + if( y==SMALLEST_INT64 && r>0.0 ) return -1;
|
| + return +1;
|
| + }
|
| + s = (double)i;
|
| + if( s<r ) return -1;
|
| + if( s>r ) return +1;
|
| + return 0;
|
| + }
|
| +}
|
|
|
| /*
|
| ** Compare the values contained by the two memory cells, returning
|
| @@ -3356,34 +3716,34 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
| return (f2&MEM_Null) - (f1&MEM_Null);
|
| }
|
|
|
| - /* If one value is a number and the other is not, the number is less.
|
| - ** If both are numbers, compare as reals if one is a real, or as integers
|
| - ** if both values are integers.
|
| + /* At least one of the two values is a number
|
| */
|
| if( combined_flags&(MEM_Int|MEM_Real) ){
|
| - double r1, r2;
|
| if( (f1 & f2 & MEM_Int)!=0 ){
|
| if( pMem1->u.i < pMem2->u.i ) return -1;
|
| - if( pMem1->u.i > pMem2->u.i ) return 1;
|
| + if( pMem1->u.i > pMem2->u.i ) return +1;
|
| return 0;
|
| }
|
| - if( (f1&MEM_Real)!=0 ){
|
| - r1 = pMem1->u.r;
|
| - }else if( (f1&MEM_Int)!=0 ){
|
| - r1 = (double)pMem1->u.i;
|
| - }else{
|
| - return 1;
|
| + if( (f1 & f2 & MEM_Real)!=0 ){
|
| + if( pMem1->u.r < pMem2->u.r ) return -1;
|
| + if( pMem1->u.r > pMem2->u.r ) return +1;
|
| + return 0;
|
| }
|
| - if( (f2&MEM_Real)!=0 ){
|
| - r2 = pMem2->u.r;
|
| - }else if( (f2&MEM_Int)!=0 ){
|
| - r2 = (double)pMem2->u.i;
|
| - }else{
|
| - return -1;
|
| + if( (f1&MEM_Int)!=0 ){
|
| + if( (f2&MEM_Real)!=0 ){
|
| + return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r);
|
| + }else{
|
| + return -1;
|
| + }
|
| }
|
| - if( r1<r2 ) return -1;
|
| - if( r1>r2 ) return 1;
|
| - return 0;
|
| + if( (f1&MEM_Real)!=0 ){
|
| + if( (f2&MEM_Int)!=0 ){
|
| + return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r);
|
| + }else{
|
| + return -1;
|
| + }
|
| + }
|
| + return +1;
|
| }
|
|
|
| /* If one value is a string and the other is a blob, the string is less.
|
| @@ -3397,7 +3757,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
| return -1;
|
| }
|
|
|
| - assert( pMem1->enc==pMem2->enc );
|
| + assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed );
|
| assert( pMem1->enc==SQLITE_UTF8 ||
|
| pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
|
|
|
| @@ -3481,7 +3841,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
| ** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
|
| ** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
|
| */
|
| -static int vdbeRecordCompareWithSkip(
|
| +int sqlite3VdbeRecordCompareWithSkip(
|
| int nKey1, const void *pKey1, /* Left key */
|
| UnpackedRecord *pPKey2, /* Right key */
|
| int bSkip /* If true, skip the first field */
|
| @@ -3529,18 +3889,13 @@ static int vdbeRecordCompareWithSkip(
|
| if( pRhs->flags & MEM_Int ){
|
| serial_type = aKey1[idx1];
|
| testcase( serial_type==12 );
|
| - if( serial_type>=12 ){
|
| + if( serial_type>=10 ){
|
| rc = +1;
|
| }else if( serial_type==0 ){
|
| rc = -1;
|
| }else if( serial_type==7 ){
|
| - double rhs = (double)pRhs->u.i;
|
| sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
| - if( mem1.u.r<rhs ){
|
| - rc = -1;
|
| - }else if( mem1.u.r>rhs ){
|
| - rc = +1;
|
| - }
|
| + rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
|
| }else{
|
| i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
|
| i64 rhs = pRhs->u.i;
|
| @@ -3555,23 +3910,24 @@ static int vdbeRecordCompareWithSkip(
|
| /* RHS is real */
|
| else if( pRhs->flags & MEM_Real ){
|
| serial_type = aKey1[idx1];
|
| - if( serial_type>=12 ){
|
| + if( serial_type>=10 ){
|
| + /* Serial types 12 or greater are strings and blobs (greater than
|
| + ** numbers). Types 10 and 11 are currently "reserved for future
|
| + ** use", so it doesn't really matter what the results of comparing
|
| + ** them to numberic values are. */
|
| rc = +1;
|
| }else if( serial_type==0 ){
|
| rc = -1;
|
| }else{
|
| - double rhs = pRhs->u.r;
|
| - double lhs;
|
| sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
| if( serial_type==7 ){
|
| - lhs = mem1.u.r;
|
| + if( mem1.u.r<pRhs->u.r ){
|
| + rc = -1;
|
| + }else if( mem1.u.r>pRhs->u.r ){
|
| + rc = +1;
|
| + }
|
| }else{
|
| - lhs = (double)mem1.u.i;
|
| - }
|
| - if( lhs<rhs ){
|
| - rc = -1;
|
| - }else if( lhs>rhs ){
|
| - rc = +1;
|
| + rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
|
| }
|
| }
|
| }
|
| @@ -3661,13 +4017,14 @@ static int vdbeRecordCompareWithSkip(
|
| || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
|
| || pKeyInfo->db->mallocFailed
|
| );
|
| + pPKey2->eqSeen = 1;
|
| return pPKey2->default_rc;
|
| }
|
| int sqlite3VdbeRecordCompare(
|
| int nKey1, const void *pKey1, /* Left key */
|
| UnpackedRecord *pPKey2 /* Right key */
|
| ){
|
| - return vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
|
| + return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
|
| }
|
|
|
|
|
| @@ -3692,6 +4049,7 @@ static int vdbeRecordCompareInt(
|
| i64 v = pPKey2->aMem[0].u.i;
|
| i64 lhs;
|
|
|
| + vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
|
| assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
|
| switch( serial_type ){
|
| case 1: { /* 1-byte signed integer */
|
| @@ -3754,11 +4112,12 @@ static int vdbeRecordCompareInt(
|
| }else if( pPKey2->nField>1 ){
|
| /* The first fields of the two keys are equal. Compare the trailing
|
| ** fields. */
|
| - res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
| + res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
| }else{
|
| /* The first fields of the two keys are equal and there are no trailing
|
| ** fields. Return pPKey2->default_rc in this case. */
|
| res = pPKey2->default_rc;
|
| + pPKey2->eqSeen = 1;
|
| }
|
|
|
| assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
|
| @@ -3779,6 +4138,8 @@ static int vdbeRecordCompareString(
|
| int serial_type;
|
| int res;
|
|
|
| + assert( pPKey2->aMem[0].flags & MEM_Str );
|
| + vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
|
| getVarint32(&aKey1[1], serial_type);
|
| if( serial_type<12 ){
|
| res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
|
| @@ -3801,9 +4162,10 @@ static int vdbeRecordCompareString(
|
| res = nStr - pPKey2->aMem[0].n;
|
| if( res==0 ){
|
| if( pPKey2->nField>1 ){
|
| - res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
| + res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
| }else{
|
| res = pPKey2->default_rc;
|
| + pPKey2->eqSeen = 1;
|
| }
|
| }else if( res>0 ){
|
| res = pPKey2->r2;
|
| @@ -3922,7 +4284,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
| if( unlikely(typeRowid<1 || typeRowid>9 || typeRowid==7) ){
|
| goto idx_rowid_corruption;
|
| }
|
| - lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
|
| + lenRowid = sqlite3SmallTypeSizes[typeRowid];
|
| testcase( (u32)m.n==szHdr+lenRowid );
|
| if( unlikely((u32)m.n<szHdr+lenRowid) ){
|
| goto idx_rowid_corruption;
|
| @@ -3961,9 +4323,11 @@ int sqlite3VdbeIdxKeyCompare(
|
| ){
|
| i64 nCellKey = 0;
|
| int rc;
|
| - BtCursor *pCur = pC->pCursor;
|
| + BtCursor *pCur;
|
| Mem m;
|
|
|
| + assert( pC->eCurType==CURTYPE_BTREE );
|
| + pCur = pC->uc.pCursor;
|
| assert( sqlite3BtreeCursorIsValid(pCur) );
|
| VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
|
| assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
|
| @@ -3974,7 +4338,7 @@ int sqlite3VdbeIdxKeyCompare(
|
| return SQLITE_CORRUPT_BKPT;
|
| }
|
| sqlite3VdbeMemInit(&m, db, 0);
|
| - rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
|
| + rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
|
| if( rc ){
|
| return rc;
|
| }
|
|
|