mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Incremental update. We are in the middle of modifying the index system
to support range queries without doing a complete table scan. (CVS 303) FossilOrigin-Name: e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0
This commit is contained in:
238
src/vdbe.c
238
src/vdbe.c
@@ -30,7 +30,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.93 2001/11/06 04:00:19 drh Exp $
|
||||
** $Id: vdbe.c,v 1.94 2001/11/07 14:22:00 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -843,28 +843,29 @@ static char *zOpName[] = { 0,
|
||||
"MoveTo", "Fcnt", "NewRecno", "Put",
|
||||
"Distinct", "Found", "NotFound", "Delete",
|
||||
"Column", "KeyAsData", "Recno", "FullKey",
|
||||
"Rewind", "Next", "Destroy", "Clear",
|
||||
"CreateIndex", "CreateTable", "Reorganize", "BeginIdx",
|
||||
"NextIdx", "PutIdx", "DeleteIdx", "MemLoad",
|
||||
"Rewind", "Next", "NextN", "Destroy",
|
||||
"Clear", "CreateIndex", "CreateTable", "Reorganize",
|
||||
"BeginIdx", "NextIdx", "IdxPut", "IdxDelete",
|
||||
"IdxRecno", "IdxGT", "IdxGE", "MemLoad",
|
||||
"MemStore", "ListWrite", "ListRewind", "ListRead",
|
||||
"ListReset", "SortPut", "SortMakeRec", "SortMakeKey",
|
||||
"Sort", "SortNext", "SortCallback", "SortReset",
|
||||
"FileOpen", "FileRead", "FileColumn", "AggReset",
|
||||
"AggFocus", "AggIncr", "AggNext", "AggSet",
|
||||
"AggGet", "SetInsert", "SetFound", "SetNotFound",
|
||||
"MakeRecord", "MakeKey", "MakeIdxKey", "Goto",
|
||||
"If", "Halt", "ColumnCount", "ColumnName",
|
||||
"Callback", "NullCallback", "Integer", "String",
|
||||
"Pop", "Dup", "Pull", "Add",
|
||||
"AddImm", "Subtract", "Multiply", "Divide",
|
||||
"Remainder", "BitAnd", "BitOr", "BitNot",
|
||||
"ShiftLeft", "ShiftRight", "AbsValue", "Precision",
|
||||
"Min", "Max", "Like", "Glob",
|
||||
"Eq", "Ne", "Lt", "Le",
|
||||
"Gt", "Ge", "IsNull", "NotNull",
|
||||
"Negative", "And", "Or", "Not",
|
||||
"Concat", "Noop", "Strlen", "Substr",
|
||||
"Limit",
|
||||
"MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey",
|
||||
"Goto", "If", "Halt", "ColumnCount",
|
||||
"ColumnName", "Callback", "NullCallback", "Integer",
|
||||
"String", "Pop", "Dup", "Pull",
|
||||
"Add", "AddImm", "Subtract", "Multiply",
|
||||
"Divide", "Remainder", "BitAnd", "BitOr",
|
||||
"BitNot", "ShiftLeft", "ShiftRight", "AbsValue",
|
||||
"Precision", "Min", "Max", "Like",
|
||||
"Glob", "Eq", "Ne", "Lt",
|
||||
"Le", "Gt", "Ge", "IsNull",
|
||||
"NotNull", "Negative", "And", "Or",
|
||||
"Not", "Concat", "Noop", "Strlen",
|
||||
"Substr", "Limit",
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2156,6 +2157,29 @@ case OP_MakeKey: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IncrKey * * *
|
||||
**
|
||||
** The top of the stack should contain an index key generated by
|
||||
** The MakeKey opcode. This routine increases the least significant
|
||||
** byte of that key by one. This is used so that the MoveTo opcode
|
||||
** will move to the first entry greater than the key rather than to
|
||||
** the key itself.
|
||||
*/
|
||||
case OP_IncrKey: {
|
||||
int tos = p->tos;
|
||||
|
||||
VERIFY( if( tos<0 ) goto bad_instruction );
|
||||
if( Stringify(p, tos) ) goto no_mem;
|
||||
if( aStack[tos].flags & STK_Static ){
|
||||
char *zNew = sqliteMalloc( aStack[tos].n );
|
||||
memcpy(zNew, zStack[tos], aStack[tos].n);
|
||||
zStack[tos] = zNew;
|
||||
aStack[tos].flags = STK_Str | STK_Dyn;
|
||||
}
|
||||
zStack[tos][aStack[tos].n-1]++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Transaction * * *
|
||||
**
|
||||
** Begin a transaction. The transaction ends when a Commit or Rollback
|
||||
@@ -2473,12 +2497,14 @@ case OP_Close: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: MoveTo P1 * *
|
||||
/* Opcode: MoveTo P1 P2 *
|
||||
**
|
||||
** Pop the top of the stack and use its value as a key. Reposition
|
||||
** cursor P1 so that it points to an entry with a matching key. If
|
||||
** the table contains no record with a matching key, then the cursor
|
||||
** is left pointing at a nearby record.
|
||||
** is left pointing at the first record that is greater than the key.
|
||||
** If there are no records greater than the key and P2 is not zero,
|
||||
** then an immediate jump to P2 is made.
|
||||
**
|
||||
** See also: Found, NotFound, Distinct
|
||||
*/
|
||||
@@ -2501,6 +2527,13 @@ case OP_MoveTo: {
|
||||
pC->recnoIsValid = 0;
|
||||
}
|
||||
p->nFetch++;
|
||||
if( res<0 ){
|
||||
sqliteBtreeNext(pC->pCursor, &res);
|
||||
pC->recnoIsValid = 0;
|
||||
if( res && pOp->p2>0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
POPSTACK;
|
||||
break;
|
||||
@@ -2870,10 +2903,13 @@ case OP_FullKey: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Rewind P1 * *
|
||||
/* Opcode: Rewind P1 P2 *
|
||||
**
|
||||
** The next use of the Recno or Column or Next instruction for P1
|
||||
** will refer to the first entry in the database file.
|
||||
** will refer to the first entry in the database table or index.
|
||||
** If the table or index is empty and P2>0, then jump immediately to P2.
|
||||
** If P2 is 0 or if the table or index is not empty, fall through
|
||||
** to the following instruction.
|
||||
*/
|
||||
case OP_Rewind: {
|
||||
int i = pOp->p1;
|
||||
@@ -2883,6 +2919,9 @@ case OP_Rewind: {
|
||||
int res;
|
||||
sqliteBtreeFirst(pCrsr, &res);
|
||||
p->aCsr[i].atFirst = res==0;
|
||||
if( res && pOp->p2>0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2912,6 +2951,29 @@ case OP_Next: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: NextN P1 P2 *
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
** table or index. If there are no more key/value pairs then fall through
|
||||
** to the following instruction. But if the cursor advance was successful,
|
||||
** jump immediately to P2.
|
||||
*/
|
||||
case OP_NextN: {
|
||||
int i = pOp->p1;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int res;
|
||||
rc = sqliteBtreeNext(pCrsr, &res);
|
||||
if( res==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
p->nFetch++;
|
||||
}
|
||||
p->aCsr[i].recnoIsValid = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: BeginIdx P1 * *
|
||||
**
|
||||
** Begin searching an index for records with the key found on the
|
||||
@@ -2981,8 +3043,8 @@ case OP_NextIdx: {
|
||||
}
|
||||
sqliteBtreeKeySize(pCur, &size);
|
||||
if( res>0 || size!=pCrsr->nKey+sizeof(u32) ||
|
||||
sqliteBtreeKeyCompare(pCur, pCrsr->zKey, pCrsr->nKey, &res)!=SQLITE_OK ||
|
||||
res!=0
|
||||
sqliteBtreeKeyCompare(pCur, pCrsr->zKey, pCrsr->nKey, 4, &res)!=SQLITE_OK
|
||||
|| res!=0
|
||||
){
|
||||
pc = pOp->p2 - 1;
|
||||
POPSTACK;
|
||||
@@ -2998,7 +3060,7 @@ case OP_NextIdx: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: PutIdx P1 P2 P3
|
||||
/* Opcode: IdxPut P1 P2 P3
|
||||
**
|
||||
** The top of the stack hold an SQL index key made using the
|
||||
** MakeIdxKey instruction. This opcode writes that key into the
|
||||
@@ -3009,7 +3071,7 @@ case OP_NextIdx: {
|
||||
** is rolled back. If P3 is not null, then it because part of the
|
||||
** error message returned with the SQLITE_CONSTRAINT.
|
||||
*/
|
||||
case OP_PutIdx: {
|
||||
case OP_IdxPut: {
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
BtCursor *pCrsr;
|
||||
@@ -3026,7 +3088,7 @@ case OP_PutIdx: {
|
||||
int c;
|
||||
sqliteBtreeKeySize(pCrsr, &n);
|
||||
if( n==nKey
|
||||
&& sqliteBtreeKeyCompare(pCrsr, zKey, nKey-4, &c)==SQLITE_OK
|
||||
&& sqliteBtreeKeyCompare(pCrsr, zKey, nKey-4, 4, &c)==SQLITE_OK
|
||||
&& c==0
|
||||
){
|
||||
rc = SQLITE_CONSTRAINT;
|
||||
@@ -3049,12 +3111,12 @@ case OP_PutIdx: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: DeleteIdx P1 * *
|
||||
/* Opcode: IdxDelete P1 * *
|
||||
**
|
||||
** The top of the stack is an index key built using the MakeIdxKey opcode.
|
||||
** This opcode removes that entry from the index.
|
||||
*/
|
||||
case OP_DeleteIdx: {
|
||||
case OP_IdxDelete: {
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
BtCursor *pCrsr;
|
||||
@@ -3070,6 +3132,74 @@ case OP_DeleteIdx: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IdxRecno P1 * *
|
||||
**
|
||||
** Push onto the stack an integer which is the last 4 bytes of the
|
||||
** the key to the current entry in index P1. These 4 bytes should
|
||||
** be the record number of the table entry to which this index entry
|
||||
** points.
|
||||
**
|
||||
** See also: Recno, MakeIdxKey.
|
||||
*/
|
||||
case OP_IdxRecno: {
|
||||
int i = pOp->p1;
|
||||
int tos = ++p->tos;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int v;
|
||||
int sz;
|
||||
sqliteBtreeKeySize(pCrsr, &sz);
|
||||
sqliteBtreeKey(pCrsr, sz - sizeof(u32), sizeof(u32), (char*)&v);
|
||||
v = bigEndian(v);
|
||||
aStack[tos].i = v;
|
||||
aStack[tos].flags = STK_Int;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IdxGT P1 P2 *
|
||||
**
|
||||
** Compare the top of the stack against the key on the index entry that
|
||||
** cursor P1 is currently pointing to. Ignore the last 4 bytes of the
|
||||
** index entry. If the index entry is greater than the top of the stack
|
||||
** then jump to P2. Otherwise fall through to the next instruction.
|
||||
** In either case, the stack is popped once.
|
||||
*/
|
||||
/* Opcode: IdxGE P1 P2 *
|
||||
**
|
||||
** Compare the top of the stack against the key on the index entry that
|
||||
** cursor P1 is currently pointing to. Ignore the last 4 bytes of the
|
||||
** index entry. If the index entry is greater than or equal to
|
||||
** the top of the stack
|
||||
** then jump to P2. Otherwise fall through to the next instruction.
|
||||
** In either case, the stack is popped once.
|
||||
*/
|
||||
case OP_IdxGT:
|
||||
case OP_IdxGE: {
|
||||
int i= pOp->p1;
|
||||
int tos = p->tos;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int res, rc;
|
||||
|
||||
if( Stringify(p, tos) ) goto no_mem;
|
||||
rc = sqliteBtreeKeyCompare(pCrsr, zStack[tos], aStack[tos].n, 4, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
break;
|
||||
}
|
||||
if( pOp->opcode==OP_IdxGE ){
|
||||
res++;
|
||||
}
|
||||
if( res>0 ){
|
||||
pc = pOp->p2 - 1 ;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Destroy P1 P2 *
|
||||
**
|
||||
** Delete an entire database table or index whose root page in the database
|
||||
@@ -3613,11 +3743,15 @@ case OP_FileColumn: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: MemStore P1 * *
|
||||
/* Opcode: MemStore P1 P2 *
|
||||
**
|
||||
** Pop a single value of the stack and store that value into memory
|
||||
** location P1. P1 should be a small integer since space is allocated
|
||||
** Write the top of the stack into memory location P1.
|
||||
** P1 should be a small integer since space is allocated
|
||||
** for all memory locations between 0 and P1 inclusive.
|
||||
**
|
||||
** After the data is stored in the memory location, the
|
||||
** stack is popped once if P2 is 1. If P2 is zero, then
|
||||
** the original data remains on the stack.
|
||||
*/
|
||||
case OP_MemStore: {
|
||||
int i = pOp->p1;
|
||||
@@ -3644,41 +3778,43 @@ case OP_MemStore: {
|
||||
}
|
||||
pMem->s = aStack[tos];
|
||||
if( pMem->s.flags & (STK_Static|STK_Dyn) ){
|
||||
pMem->z = zStack[tos];
|
||||
if( pOp->p2==0 && (pMem->s.flags & STK_Dyn)!=0 ){
|
||||
pMem->z = sqliteMalloc( pMem->s.n );
|
||||
if( pMem->z ) goto no_mem;
|
||||
memcpy(pMem->z, zStack[tos], pMem->s.n);
|
||||
}else{
|
||||
pMem->z = zStack[tos];
|
||||
}
|
||||
}else{
|
||||
pMem->z = pMem->s.z;
|
||||
}
|
||||
if( zOld ) sqliteFree(zOld);
|
||||
zStack[tos] = 0;
|
||||
aStack[tos].flags = 0;
|
||||
POPSTACK;
|
||||
if( pOp->p2 ){
|
||||
zStack[tos] = 0;
|
||||
aStack[tos].flags = 0;
|
||||
POPSTACK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: MemLoad P1 * *
|
||||
**
|
||||
** Push a copy of the value in memory location P1 onto the stack.
|
||||
**
|
||||
** If the value is a string, then the value pushed is a pointer to
|
||||
** the string that is stored in the memory location. If the memory
|
||||
** location is subsequently changed (using OP_MemStore) then the
|
||||
** value pushed onto the stack will change too.
|
||||
*/
|
||||
case OP_MemLoad: {
|
||||
int tos = ++p->tos;
|
||||
int i = pOp->p1;
|
||||
VERIFY( if( NeedStack(p, tos) ) goto no_mem; )
|
||||
if( i<0 || i>=p->nMem ){
|
||||
aStack[tos].flags = STK_Null;
|
||||
zStack[tos] = 0;
|
||||
}else{
|
||||
aStack[tos] = p->aMem[i].s;
|
||||
if( aStack[tos].flags & STK_Dyn ){
|
||||
char *z = sqliteMalloc(aStack[tos].n);
|
||||
if( z==0 ) goto no_mem;
|
||||
memcpy(z, p->aMem[i].z, aStack[tos].n);
|
||||
zStack[tos] = z;
|
||||
aStack[tos].flags |= STK_Dyn;
|
||||
}else if( aStack[tos].flags & STK_Static ){
|
||||
zStack[tos] = p->aMem[i].z;
|
||||
}else if( aStack[tos].flags & STK_Str ){
|
||||
zStack[tos] = aStack[tos].z;
|
||||
}
|
||||
VERIFY( if( i<0 || i>=p->nMem ) goto bad_instruction; )
|
||||
memcpy(&aStack[tos], &p->aMem[i].s, sizeof(aStack[tos])-NBFS);;
|
||||
if( aStack[tos].flags & STK_Str ){
|
||||
zStack[tos] = p->aMem[i].z;
|
||||
aStack[tos].flags = STK_Str | STK_Static;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user