diff options
Diffstat (limited to 'ext/sqlite/libsqlite/src/vdbe.c')
-rw-r--r-- | ext/sqlite/libsqlite/src/vdbe.c | 133 |
1 files changed, 84 insertions, 49 deletions
diff --git a/ext/sqlite/libsqlite/src/vdbe.c b/ext/sqlite/libsqlite/src/vdbe.c index bd080f37d3..b0dd210049 100644 --- a/ext/sqlite/libsqlite/src/vdbe.c +++ b/ext/sqlite/libsqlite/src/vdbe.c @@ -363,42 +363,6 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){ } /* -** Convert an integer in between the native integer format and -** the bigEndian format used as the record number for tables. -** -** The bigEndian format (most significant byte first) is used for -** record numbers so that records will sort into the correct order -** even though memcmp() is used to compare the keys. On machines -** whose native integer format is little endian (ex: i486) the -** order of bytes is reversed. On native big-endian machines -** (ex: Alpha, Sparc, Motorola) the byte order is the same. -** -** This function is its own inverse. In other words -** -** X == byteSwap(byteSwap(X)) -*/ -static int byteSwap(int x){ - union { - char zBuf[sizeof(int)]; - int i; - } ux; - ux.zBuf[3] = x&0xff; - ux.zBuf[2] = (x>>8)&0xff; - ux.zBuf[1] = (x>>16)&0xff; - ux.zBuf[0] = (x>>24)&0xff; - return ux.i; -} - -/* -** When converting from the native format to the key format and back -** again, in addition to changing the byte order we invert the high-order -** bit of the most significant byte. This causes negative numbers to -** sort before positive numbers in the memcmp() function. -*/ -#define keyToInt(X) (byteSwap(X) ^ 0x80000000) -#define intToKey(X) (byteSwap((X) ^ 0x80000000)) - -/* ** Code contained within the VERIFY() macro is not needed for correct ** execution. It is there only to catch errors. So when we compile ** with NDEBUG=1, the VERIFY() code is omitted. @@ -1157,7 +1121,9 @@ case OP_Function: { ctx.z = 0; ctx.isError = 0; ctx.isStep = 0; + if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; (*ctx.pFunc->xFunc)(&ctx, n, (const char**)&zStack[p->tos-n+1]); + if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; sqliteVdbePopStack(p, n); p->tos++; aStack[p->tos] = ctx.s; @@ -1831,8 +1797,8 @@ case OP_IfNot: { /* Opcode: IsNull P1 P2 * ** ** If any of the top abs(P1) values on the stack are NULL, then jump -** to P2. The stack is popped P1 times if P1>0. If P1<0 then all values -** are left unchanged on the stack. +** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack +** unchanged. */ case OP_IsNull: { int i, cnt; @@ -1851,14 +1817,18 @@ case OP_IsNull: { /* Opcode: NotNull P1 P2 * ** -** Jump to P2 if the top value on the stack is not NULL. Pop the -** stack if P1 is greater than zero. If P1 is less than or equal to -** zero then leave the value on the stack. +** Jump to P2 if the top P1 values on the stack are all not NULL. Pop the +** stack if P1 times if P1 is greater than zero. If P1 is less than +** zero then leave the stack unchanged. */ case OP_NotNull: { - VERIFY( if( p->tos<0 ) goto not_enough_stack; ) - if( (aStack[p->tos].flags & STK_Null)==0 ) pc = pOp->p2-1; - if( pOp->p1>0 ){ POPSTACK; } + int i, cnt; + cnt = pOp->p1; + if( cnt<0 ) cnt = -cnt; + VERIFY( if( p->tos+1-cnt<0 ) goto not_enough_stack; ) + for(i=0; i<cnt && (aStack[p->tos-i].flags & STK_Null)==0; i++){} + if( i>=cnt ) pc = pOp->p2-1; + if( pOp->p1>0 ) sqliteVdbePopStack(p, cnt); break; } @@ -2597,8 +2567,15 @@ case OP_MoveTo: { pC = &p->aCsr[i]; if( pC->pCursor!=0 ){ int res, oc; + pC->nullRow = 0; if( aStack[tos].flags & STK_Int ){ int iKey = intToKey(aStack[tos].i); + if( pOp->p2==0 && pOp->opcode==OP_MoveTo ){ + pC->movetoTarget = iKey; + pC->deferredMoveto = 1; + POPSTACK; + break; + } sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res); pC->lastRecno = aStack[tos].i; pC->recnoIsValid = res==0; @@ -2607,7 +2584,7 @@ case OP_MoveTo: { sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); pC->recnoIsValid = 0; } - pC->nullRow = 0; + pC->deferredMoveto = 0; sqlite_search_count++; oc = pOp->opcode; if( oc==OP_MoveTo && res<0 ){ @@ -2682,6 +2659,7 @@ case OP_Found: { Stringify(p, tos); rx = sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); alreadyExists = rx==SQLITE_OK && res==0; + pC->deferredMoveto = 0; } if( pOp->opcode==OP_Found ){ if( alreadyExists ) pc = pOp->p2 - 1; @@ -2743,6 +2721,7 @@ case OP_IsUnique: { /* Search for an entry in P1 where all but the last four bytes match K. ** If there is no such entry, jump immediately to P2. */ + assert( p->aCsr[i].deferredMoveto==0 ); rc = sqliteBtreeMoveto(pCrsr, zKey, nKey-4, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res<0 ){ @@ -2911,6 +2890,7 @@ case OP_NewRecno: { } } pC->recnoIsValid = 0; + pC->deferredMoveto = 0; } p->tos++; aStack[p->tos].i = v; @@ -2993,6 +2973,7 @@ case OP_PutStrKey: { zStack[tos], aStack[tos].n); } pC->recnoIsValid = 0; + pC->deferredMoveto = 0; } POPSTACK; POPSTACK; @@ -3019,6 +3000,7 @@ case OP_Delete: { assert( i>=0 && i<p->nCursor ); pC = &p->aCsr[i]; if( pC->pCursor!=0 ){ + sqliteVdbeCursorMoveto(pC); rc = sqliteBtreeDelete(pC->pCursor); pC->nextRowidValid = 0; } @@ -3049,6 +3031,16 @@ case OP_KeyAsData: { ** If the cursor is not pointing to a valid row, a NULL is pushed ** onto the stack. */ +/* Opcode: RowKey P1 * * +** +** Push onto the stack the complete row key for cursor P1. +** There is no interpretation of the key. It is just copied +** onto the stack exactly as it is found in the database file. +** +** If the cursor is not pointing to a valid row, a NULL is pushed +** onto the stack. +*/ +case OP_RowKey: case OP_RowData: { int i = pOp->p1; int tos = ++p->tos; @@ -3061,10 +3053,11 @@ case OP_RowData: { aStack[tos].flags = STK_Null; }else if( pC->pCursor!=0 ){ BtCursor *pCrsr = pC->pCursor; + sqliteVdbeCursorMoveto(pC); if( pC->nullRow ){ aStack[tos].flags = STK_Null; break; - }else if( pC->keyAsData ){ + }else if( pC->keyAsData || pOp->opcode==OP_RowKey ){ sqliteBtreeKeySize(pCrsr, &n); }else{ sqliteBtreeDataSize(pCrsr, &n); @@ -3079,7 +3072,7 @@ case OP_RowData: { aStack[tos].flags = STK_Str | STK_Dyn; zStack[tos] = z; } - if( pC->keyAsData ){ + if( pC->keyAsData || pOp->opcode==OP_RowKey ){ sqliteBtreeKey(pCrsr, 0, n, zStack[tos]); }else{ sqliteBtreeData(pCrsr, 0, n, zStack[tos]); @@ -3131,6 +3124,7 @@ case OP_Column: { zRec = zStack[tos+i]; payloadSize = aStack[tos+i].n; }else if( (pC = &p->aCsr[i])->pCursor!=0 ){ + sqliteVdbeCursorMoveto(pC); zRec = 0; pCrsr = pC->pCursor; if( pC->nullRow ){ @@ -3237,7 +3231,9 @@ case OP_Recno: { int v; assert( i>=0 && i<p->nCursor ); - if( (pC = &p->aCsr[i])->recnoIsValid ){ + pC = &p->aCsr[i]; + sqliteVdbeCursorMoveto(pC); + if( pC->recnoIsValid ){ v = pC->lastRecno; }else if( pC->pseudoTable ){ v = keyToInt(pC->iKey); @@ -3276,6 +3272,7 @@ case OP_FullKey: { int amt; char *z; + sqliteVdbeCursorMoveto(&p->aCsr[i]); sqliteBtreeKeySize(pCrsr, &amt); if( amt<=0 ){ rc = SQLITE_CORRUPT; @@ -3329,7 +3326,8 @@ case OP_Last: { if( (pCrsr = pC->pCursor)!=0 ){ int res; rc = sqliteBtreeLast(pCrsr, &res); - p->aCsr[i].nullRow = res; + pC->nullRow = res; + pC->deferredMoveto = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } @@ -3359,6 +3357,7 @@ case OP_Rewind: { rc = sqliteBtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->nullRow = res; + pC->deferredMoveto = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } @@ -3397,6 +3396,7 @@ case OP_Next: { if( pC->nullRow ){ res = 1; }else{ + assert( pC->deferredMoveto==0 ); rc = pOp->opcode==OP_Next ? sqliteBtreeNext(pCrsr, &res) : sqliteBtreePrevious(pCrsr, &res); pC->nullRow = res; @@ -3458,6 +3458,7 @@ case OP_IdxPut: { } } rc = sqliteBtreeInsert(pCrsr, zKey, nKey, "", 0); + assert( p->aCsr[i].deferredMoveto==0 ); } POPSTACK; break; @@ -3479,6 +3480,7 @@ case OP_IdxDelete: { if( rx==SQLITE_OK && res==0 ){ rc = sqliteBtreeDelete(pCrsr); } + assert( p->aCsr[i].deferredMoveto==0 ); } POPSTACK; break; @@ -3501,6 +3503,7 @@ case OP_IdxRecno: { if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int v; int sz; + assert( p->aCsr[i].deferredMoveto==0 ); sqliteBtreeKeySize(pCrsr, &sz); if( sz<sizeof(u32) ){ aStack[tos].flags = STK_Null; @@ -3550,6 +3553,7 @@ case OP_IdxGE: { int res, rc; Stringify(p, tos); + assert( p->aCsr[i].deferredMoveto==0 ); rc = sqliteBtreeKeyCompare(pCrsr, zStack[tos], aStack[tos].n, 4, &res); if( rc!=SQLITE_OK ){ break; @@ -3567,6 +3571,37 @@ case OP_IdxGE: { break; } +/* Opcode: IdxIsNull P1 P2 * +** +** The top of the stack contains an index entry such as might be generated +** by the MakeIdxKey opcode. This routine looks at the first P1 fields of +** that key. If any of the first P1 fields are NULL, then a jump is made +** to address P2. Otherwise we fall straight through. +** +** The index entry is always popped from the stack. +*/ +case OP_IdxIsNull: { + int i = pOp->p1; + int tos = p->tos; + int k, n; + const char *z; + + assert( tos>=0 ); + assert( aStack[tos].flags & STK_Str ); + z = zStack[tos]; + n = aStack[tos].n; + for(k=0; k<n && i>0; i--){ + if( z[k]=='a' ){ + pc = pOp->p2-1; + break; + } + while( k<n && z[k] ){ k++; } + k++; + } + POPSTACK; + break; +} + /* Opcode: Destroy P1 P2 * ** ** Delete an entire database table or index whose root page in the database |