1
0
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:
drh
2001-11-07 14:22:00 +00:00
parent 17e24df621
commit 8721ce4ae7
11 changed files with 336 additions and 225 deletions

View File

@@ -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;
}