mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
:-) (CVS 104)
FossilOrigin-Name: e1bf96a467b739373191bf75e6a097fc0f24bffc
This commit is contained in:
326
src/vdbe.c
326
src/vdbe.c
@@ -41,7 +41,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.33 2000/06/11 23:50:13 drh Exp $
|
||||
** $Id: vdbe.c,v 1.34 2000/06/21 13:59:13 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <unistd.h>
|
||||
@@ -54,15 +54,21 @@
|
||||
typedef struct VdbeOp Op;
|
||||
|
||||
/*
|
||||
** Every table that the virtual machine has open is represented by an
|
||||
** A cursor is a pointer into a database file. The database file
|
||||
** can represent either an SQL table or an SQL index. Each file is
|
||||
** a bag of key/data pairs. The cursor can loop over all key/data
|
||||
** pairs (in an arbitrary order) or it can retrieve a particular
|
||||
** key/data pair given a copy of the key.
|
||||
**
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
*/
|
||||
struct VdbeTable {
|
||||
DbbeTable *pTable; /* The table structure of the backend */
|
||||
struct Cursor {
|
||||
DbbeCursor *pCursor; /* The cursor structure of the backend */
|
||||
int index; /* The next index to extract */
|
||||
int keyAsData; /* The OP_Field command works on key instead of data */
|
||||
};
|
||||
typedef struct VdbeTable VdbeTable;
|
||||
typedef struct Cursor Cursor;
|
||||
|
||||
/*
|
||||
** A sorter builds a list of elements to be sorted. Each element of
|
||||
@@ -117,7 +123,7 @@ typedef struct Mem Mem;
|
||||
#define STK_Dyn 0x0010 /* Need to call sqliteFree() on zStack[*] */
|
||||
|
||||
/*
|
||||
** An Agg structure describes and Aggregator. Each Agg consists of
|
||||
** An Agg structure describes an Aggregator. Each Agg consists of
|
||||
** zero or more Aggregator elements (AggElem). Each AggElem contains
|
||||
** a key and one or more values. The values are used in processing
|
||||
** aggregate functions in a SELECT. The key is used to implement
|
||||
@@ -130,7 +136,7 @@ struct Agg {
|
||||
AggElem *pCurrent; /* The AggElem currently in focus */
|
||||
int nElem; /* The number of AggElems */
|
||||
int nHash; /* Number of slots in apHash[] */
|
||||
AggElem **apHash; /* A hash table for looking up AggElems by zKey */
|
||||
AggElem **apHash; /* A hash array for looking up AggElems by zKey */
|
||||
AggElem *pFirst; /* A list of all AggElems */
|
||||
};
|
||||
struct AggElem {
|
||||
@@ -150,7 +156,7 @@ typedef struct Set Set;
|
||||
typedef struct SetElem SetElem;
|
||||
struct Set {
|
||||
SetElem *pAll; /* All elements of this set */
|
||||
SetElem *apHash[41]; /* A hash table for all elements in this set */
|
||||
SetElem *apHash[41]; /* A hash array for all elements in this set */
|
||||
};
|
||||
struct SetElem {
|
||||
SetElem *pHash; /* Next element with the same hash on zKey */
|
||||
@@ -175,8 +181,8 @@ struct Vdbe {
|
||||
Stack *aStack; /* The operand stack, except string values */
|
||||
char **zStack; /* Text or binary values of the stack */
|
||||
char **azColName; /* Becomes the 4th parameter to callbacks */
|
||||
int nTable; /* Number of slots in aTab[] */
|
||||
VdbeTable *aTab; /* On element of this array for each open table */
|
||||
int nCursor; /* Number of slots in aCsr[] */
|
||||
Cursor *aCsr; /* On element of this array for each open cursor */
|
||||
int nList; /* Number of slots in apList[] */
|
||||
FILE **apList; /* An open file for each list */
|
||||
int nSort; /* Number of slots in apSort[] */
|
||||
@@ -394,7 +400,7 @@ static void AggReset(Agg *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the given AggElem to the hash table
|
||||
** Add the given AggElem to the hash array
|
||||
*/
|
||||
static void AggEnhash(Agg *p, AggElem *pElem){
|
||||
int h = sqliteHashNoCase(pElem->zKey, 0) % p->nHash;
|
||||
@@ -403,7 +409,7 @@ static void AggEnhash(Agg *p, AggElem *pElem){
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the size of the hash table to the amount given.
|
||||
** Change the size of the hash array to the amount given.
|
||||
*/
|
||||
static void AggRehash(Agg *p, int nHash){
|
||||
int size;
|
||||
@@ -634,7 +640,7 @@ static int hardNeedStack(Vdbe *p, int N){
|
||||
/*
|
||||
** Clean up the VM after execution.
|
||||
**
|
||||
** This routine will automatically close any tables, list, and/or
|
||||
** This routine will automatically close any cursors, list, and/or
|
||||
** sorters that were left open.
|
||||
*/
|
||||
static void Cleanup(Vdbe *p){
|
||||
@@ -642,15 +648,15 @@ static void Cleanup(Vdbe *p){
|
||||
PopStack(p, p->tos+1);
|
||||
sqliteFree(p->azColName);
|
||||
p->azColName = 0;
|
||||
for(i=0; i<p->nTable; i++){
|
||||
if( p->aTab[i].pTable ){
|
||||
sqliteDbbeCloseTable(p->aTab[i].pTable);
|
||||
p->aTab[i].pTable = 0;
|
||||
for(i=0; i<p->nCursor; i++){
|
||||
if( p->aCsr[i].pCursor ){
|
||||
sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
|
||||
p->aCsr[i].pCursor = 0;
|
||||
}
|
||||
}
|
||||
sqliteFree(p->aTab);
|
||||
p->aTab = 0;
|
||||
p->nTable = 0;
|
||||
sqliteFree(p->aCsr);
|
||||
p->aCsr = 0;
|
||||
p->nCursor = 0;
|
||||
for(i=0; i<p->nMem; i++){
|
||||
if( p->aMem[i].s.flags & STK_Dyn ){
|
||||
sqliteFree(p->aMem[i].z);
|
||||
@@ -786,7 +792,7 @@ int sqliteVdbeList(
|
||||
char **pzErrMsg /* Error msg written here */
|
||||
){
|
||||
int i, rc;
|
||||
char *azField[6];
|
||||
char *azValue[6];
|
||||
char zAddr[20];
|
||||
char zP1[20];
|
||||
char zP2[20];
|
||||
@@ -795,19 +801,19 @@ int sqliteVdbeList(
|
||||
};
|
||||
|
||||
if( xCallback==0 ) return 0;
|
||||
azField[0] = zAddr;
|
||||
azField[2] = zP1;
|
||||
azField[3] = zP2;
|
||||
azField[5] = 0;
|
||||
azValue[0] = zAddr;
|
||||
azValue[2] = zP1;
|
||||
azValue[3] = zP2;
|
||||
azValue[5] = 0;
|
||||
rc = SQLITE_OK;
|
||||
/* if( pzErrMsg ){ *pzErrMsg = 0; } */
|
||||
for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
|
||||
sprintf(zAddr,"%d",i);
|
||||
sprintf(zP1,"%d", p->aOp[i].p1);
|
||||
sprintf(zP2,"%d", p->aOp[i].p2);
|
||||
azField[4] = p->aOp[i].p3;
|
||||
azField[1] = zOpName[p->aOp[i].opcode];
|
||||
if( xCallback(pArg, 5, azField, azColumnNames) ){
|
||||
azValue[4] = p->aOp[i].p3;
|
||||
azValue[1] = zOpName[p->aOp[i].opcode];
|
||||
if( xCallback(pArg, 5, azValue, azColumnNames) ){
|
||||
rc = SQLITE_ABORT;
|
||||
}
|
||||
}
|
||||
@@ -1492,7 +1498,7 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: Not * * *
|
||||
**
|
||||
** Treat the top of the stack as a boolean value. Replace it
|
||||
** Interpret the top of the stack as a boolean value. Replace it
|
||||
** with its complement.
|
||||
*/
|
||||
case OP_Not: {
|
||||
@@ -1676,33 +1682,34 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: Open P1 P2 P3
|
||||
**
|
||||
** Open a new cursor for the database table named P3. Give the
|
||||
** cursor an identifier P1.
|
||||
** Open readonly if P2==0 and for reading and writing if P2!=0.
|
||||
** The table is created if it does not already exist and P2!=0.
|
||||
** If there is already another cursor opened with identifier P1,
|
||||
** then the old cursor is closed first.
|
||||
** All cursors are automatically closed when
|
||||
** the VDBE finishes execution. The P1 values need not be
|
||||
** Open a new cursor for the database file named P3. Give the
|
||||
** cursor an identifier P1. The P1 values need not be
|
||||
** contiguous but all P1 values should be small integers. It is
|
||||
** an error for P1 to be negative.
|
||||
**
|
||||
** If P3 is null or an empty string, a temporary table created.
|
||||
** This table is automatically deleted when the cursor is closed.
|
||||
** Open readonly if P2==0 and for reading and writing if P2!=0.
|
||||
** The file is created if it does not already exist and P2!=0.
|
||||
** If there is already another cursor opened with identifier P1,
|
||||
** then the old cursor is closed first. All cursors are
|
||||
** automatically closed when the VDBE finishes execution.
|
||||
**
|
||||
** If P3 is null or an empty string, a temporary database file
|
||||
** is created. This temporary database file is automatically
|
||||
** deleted when the cursor is closed.
|
||||
*/
|
||||
case OP_Open: {
|
||||
int i = pOp->p1;
|
||||
if( i<0 ) goto bad_instruction;
|
||||
if( i>=p->nTable ){
|
||||
if( i>=p->nCursor ){
|
||||
int j;
|
||||
p->aTab = sqliteRealloc( p->aTab, (i+1)*sizeof(VdbeTable) );
|
||||
if( p->aTab==0 ){ p->nTable = 0; goto no_mem; }
|
||||
for(j=p->nTable; j<=i; j++) p->aTab[j].pTable = 0;
|
||||
p->nTable = i+1;
|
||||
}else if( p->aTab[i].pTable ){
|
||||
sqliteDbbeCloseTable(p->aTab[i].pTable);
|
||||
p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
|
||||
if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; }
|
||||
for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0;
|
||||
p->nCursor = i+1;
|
||||
}else if( p->aCsr[i].pCursor ){
|
||||
sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
|
||||
}
|
||||
rc = sqliteDbbeOpenTable(p->pBe, pOp->p3, pOp->p2, &p->aTab[i].pTable);
|
||||
rc = sqliteDbbeOpenCursor(p->pBe, pOp->p3, pOp->p2,&p->aCsr[i].pCursor);
|
||||
switch( rc ){
|
||||
case SQLITE_BUSY: {
|
||||
sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0);
|
||||
@@ -1722,21 +1729,21 @@ int sqliteVdbeExec(
|
||||
goto no_mem;
|
||||
}
|
||||
}
|
||||
p->aTab[i].index = 0;
|
||||
p->aTab[i].keyAsData = 0;
|
||||
p->aCsr[i].index = 0;
|
||||
p->aCsr[i].keyAsData = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Close P1 * *
|
||||
**
|
||||
** Close a database table previously opened as P1. If P1 is not
|
||||
** Close a cursor previously opened as P1. If P1 is not
|
||||
** currently open, this instruction is a no-op.
|
||||
*/
|
||||
case OP_Close: {
|
||||
int i = pOp->p1;
|
||||
if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
|
||||
sqliteDbbeCloseTable(p->aTab[i].pTable);
|
||||
p->aTab[i].pTable = 0;
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
|
||||
sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
|
||||
p->aCsr[i].pCursor = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1744,21 +1751,20 @@ int sqliteVdbeExec(
|
||||
/* Opcode: Fetch P1 * *
|
||||
**
|
||||
** Pop the top of the stack and use its value as a key to fetch
|
||||
** a record from database table or index P1. The data is held
|
||||
** in the P1 cursor until needed. The data is not pushed onto the
|
||||
** stack.
|
||||
** a record from cursor P1. The key/data pair is held
|
||||
** in the P1 cursor until needed.
|
||||
*/
|
||||
case OP_Fetch: {
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
if( tos<0 ) goto not_enough_stack;
|
||||
if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
|
||||
if( p->aStack[tos].flags & STK_Int ){
|
||||
sqliteDbbeFetch(p->aTab[i].pTable, sizeof(int),
|
||||
sqliteDbbeFetch(p->aCsr[i].pCursor, sizeof(int),
|
||||
(char*)&p->aStack[tos].i);
|
||||
}else{
|
||||
if( Stringify(p, tos) ) goto no_mem;
|
||||
sqliteDbbeFetch(p->aTab[i].pTable, p->aStack[tos].n,
|
||||
sqliteDbbeFetch(p->aCsr[i].pCursor, p->aStack[tos].n,
|
||||
p->zStack[tos]);
|
||||
}
|
||||
p->nFetch++;
|
||||
@@ -1787,7 +1793,7 @@ int sqliteVdbeExec(
|
||||
/* Opcode: Distinct P1 P2 *
|
||||
**
|
||||
** Use the top of the stack as a key. If a record with that key
|
||||
** does not exist in table P1, then jump to P2. If the record
|
||||
** does not exist in file P1, then jump to P2. If the record
|
||||
** does already exist, then fall thru. The record is not retrieved.
|
||||
** The key is not popped from the stack.
|
||||
**
|
||||
@@ -1797,14 +1803,14 @@ int sqliteVdbeExec(
|
||||
/* Opcode: Found P1 P2 *
|
||||
**
|
||||
** Use the top of the stack as a key. If a record with that key
|
||||
** does exist in table P1, then jump to P2. If the record
|
||||
** does exist in file P1, then jump to P2. If the record
|
||||
** does not exist, then fall thru. The record is not retrieved.
|
||||
** The key is popped from the stack.
|
||||
*/
|
||||
/* Opcode: NotFound P1 P2 *
|
||||
**
|
||||
** Use the top of the stack as a key. If a record with that key
|
||||
** does not exist in table P1, then jump to P2. If the record
|
||||
** does not exist in file P1, then jump to P2. If the record
|
||||
** does exist, then fall thru. The record is not retrieved.
|
||||
** The key is popped from the stack.
|
||||
**
|
||||
@@ -1818,13 +1824,13 @@ int sqliteVdbeExec(
|
||||
int tos = p->tos;
|
||||
int alreadyExists = 0;
|
||||
if( tos<0 ) goto not_enough_stack;
|
||||
if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
|
||||
if( p->aStack[tos].flags & STK_Int ){
|
||||
alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, sizeof(int),
|
||||
alreadyExists = sqliteDbbeTest(p->aCsr[i].pCursor, sizeof(int),
|
||||
(char*)&p->aStack[tos].i);
|
||||
}else{
|
||||
if( Stringify(p, tos) ) goto no_mem;
|
||||
alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, p->aStack[tos].n,
|
||||
alreadyExists = sqliteDbbeTest(p->aCsr[i].pCursor,p->aStack[tos].n,
|
||||
p->zStack[tos]);
|
||||
}
|
||||
}
|
||||
@@ -1841,16 +1847,16 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: New P1 * *
|
||||
**
|
||||
** Get a new integer key not previous used by table P1 and
|
||||
** push it onto the stack.
|
||||
** Get a new integer key not previous used by the database file
|
||||
** associated with cursor P1 and push it onto the stack.
|
||||
*/
|
||||
case OP_New: {
|
||||
int i = pOp->p1;
|
||||
int v;
|
||||
if( i<0 || i>=p->nTable || p->aTab[i].pTable==0 ){
|
||||
if( i<0 || i>=p->nCursor || p->aCsr[i].pCursor==0 ){
|
||||
v = 0;
|
||||
}else{
|
||||
v = sqliteDbbeNew(p->aTab[i].pTable);
|
||||
v = sqliteDbbeNew(p->aCsr[i].pCursor);
|
||||
}
|
||||
NeedStack(p, p->tos+1);
|
||||
p->tos++;
|
||||
@@ -1861,7 +1867,7 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: Put P1 * *
|
||||
**
|
||||
** Write an entry into the database table P1. A new entry is
|
||||
** Write an entry into the database file P1. A new entry is
|
||||
** created if it doesn't already exist, or the data for an existing
|
||||
** entry is overwritten. The data is the value on the top of the
|
||||
** stack. The key is the next value down on the stack. The stack
|
||||
@@ -1872,7 +1878,7 @@ int sqliteVdbeExec(
|
||||
int nos = p->tos-1;
|
||||
int i = pOp->p1;
|
||||
if( nos<0 ) goto not_enough_stack;
|
||||
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
|
||||
char *zKey;
|
||||
int nKey;
|
||||
if( (p->aStack[nos].flags & STK_Int)==0 ){
|
||||
@@ -1883,7 +1889,7 @@ int sqliteVdbeExec(
|
||||
nKey = sizeof(int);
|
||||
zKey = (char*)&p->aStack[nos].i;
|
||||
}
|
||||
sqliteDbbePut(p->aTab[i].pTable, nKey, zKey,
|
||||
sqliteDbbePut(p->aCsr[i].pCursor, nKey, zKey,
|
||||
p->aStack[tos].n, p->zStack[tos]);
|
||||
}
|
||||
PopStack(p, 2);
|
||||
@@ -1893,13 +1899,13 @@ int sqliteVdbeExec(
|
||||
/* Opcode: Delete P1 * *
|
||||
**
|
||||
** The top of the stack is a key. Remove this key and its data
|
||||
** from database table P1. Then pop the stack to discard the key.
|
||||
** from database file P1. Then pop the stack to discard the key.
|
||||
*/
|
||||
case OP_Delete: {
|
||||
int tos = p->tos;
|
||||
int i = pOp->p1;
|
||||
if( tos<0 ) goto not_enough_stack;
|
||||
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
|
||||
char *zKey;
|
||||
int nKey;
|
||||
if( p->aStack[tos].flags & STK_Int ){
|
||||
@@ -1910,7 +1916,7 @@ int sqliteVdbeExec(
|
||||
nKey = p->aStack[tos].n;
|
||||
zKey = p->zStack[tos];
|
||||
}
|
||||
sqliteDbbeDelete(p->aTab[i].pTable, nKey, zKey);
|
||||
sqliteDbbeDelete(p->aCsr[i].pCursor, nKey, zKey);
|
||||
}
|
||||
PopStack(p, 1);
|
||||
break;
|
||||
@@ -1925,16 +1931,18 @@ int sqliteVdbeExec(
|
||||
*/
|
||||
case OP_KeyAsData: {
|
||||
int i = pOp->p1;
|
||||
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
|
||||
p->aTab[i].keyAsData = pOp->p2;
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
|
||||
p->aCsr[i].keyAsData = pOp->p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Field P1 P2 *
|
||||
**
|
||||
** Push onto the stack the value of the P2-th field from the
|
||||
** most recent Fetch from table P1.
|
||||
** Interpret the data in the most recent fetch from cursor P1
|
||||
** is a structure built using the MakeRecord instruction.
|
||||
** Push onto the stack the value of the P2-th field of that
|
||||
** structure.
|
||||
**
|
||||
** The value pushed is just a pointer to the data in the cursor.
|
||||
** The value will go away the next time a record is fetched from P1,
|
||||
@@ -1944,6 +1952,11 @@ int sqliteVdbeExec(
|
||||
** If the KeyAsData opcode has previously executed on this cursor,
|
||||
** then the field might be extracted from the key rather than the
|
||||
** data.
|
||||
**
|
||||
** Viewed from a higher level, this instruction retrieves the
|
||||
** data from a single column in a particular row of an SQL table
|
||||
** file. Perhaps the name of this instruction should be
|
||||
** "Column" instead of "Field"...
|
||||
*/
|
||||
case OP_Field: {
|
||||
int *pAddr;
|
||||
@@ -1951,35 +1964,35 @@ int sqliteVdbeExec(
|
||||
int i = pOp->p1;
|
||||
int p2 = pOp->p2;
|
||||
int tos = ++p->tos;
|
||||
DbbeTable *pTab;
|
||||
DbbeCursor *pCrsr;
|
||||
char *z;
|
||||
|
||||
if( NeedStack(p, tos) ) goto no_mem;
|
||||
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
|
||||
if( p->aTab[i].keyAsData ){
|
||||
amt = sqliteDbbeKeyLength(pTab);
|
||||
if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
if( p->aCsr[i].keyAsData ){
|
||||
amt = sqliteDbbeKeyLength(pCrsr);
|
||||
if( amt<=sizeof(int)*(p2+1) ){
|
||||
p->aStack[tos].flags = STK_Null;
|
||||
break;
|
||||
}
|
||||
pAddr = (int*)sqliteDbbeReadKey(pTab, sizeof(int)*p2);
|
||||
pAddr = (int*)sqliteDbbeReadKey(pCrsr, sizeof(int)*p2);
|
||||
if( *pAddr==0 ){
|
||||
p->aStack[tos].flags = STK_Null;
|
||||
break;
|
||||
}
|
||||
z = sqliteDbbeReadKey(pTab, *pAddr);
|
||||
z = sqliteDbbeReadKey(pCrsr, *pAddr);
|
||||
}else{
|
||||
amt = sqliteDbbeDataLength(pTab);
|
||||
amt = sqliteDbbeDataLength(pCrsr);
|
||||
if( amt<=sizeof(int)*(p2+1) ){
|
||||
p->aStack[tos].flags = STK_Null;
|
||||
break;
|
||||
}
|
||||
pAddr = (int*)sqliteDbbeReadData(pTab, sizeof(int)*p2);
|
||||
pAddr = (int*)sqliteDbbeReadData(pCrsr, sizeof(int)*p2);
|
||||
if( *pAddr==0 ){
|
||||
p->aStack[tos].flags = STK_Null;
|
||||
break;
|
||||
}
|
||||
z = sqliteDbbeReadData(pTab, *pAddr);
|
||||
z = sqliteDbbeReadData(pCrsr, *pAddr);
|
||||
}
|
||||
p->zStack[tos] = z;
|
||||
p->aStack[tos].n = strlen(z) + 1;
|
||||
@@ -1991,21 +2004,22 @@ int sqliteVdbeExec(
|
||||
/* Opcode: Key P1 * *
|
||||
**
|
||||
** Push onto the stack an integer which is the first 4 bytes of the
|
||||
** the key to the current entry in a sequential scan of the table P1.
|
||||
** A sequential scan is started using the Next opcode.
|
||||
** the key to the current entry in a sequential scan of the database
|
||||
** file P1. The sequential scan should have been started using the
|
||||
** Next opcode.
|
||||
*/
|
||||
case OP_Key: {
|
||||
int i = pOp->p1;
|
||||
int tos = ++p->tos;
|
||||
DbbeTable *pTab;
|
||||
DbbeCursor *pCrsr;
|
||||
|
||||
if( NeedStack(p, p->tos) ) goto no_mem;
|
||||
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
|
||||
char *z = sqliteDbbeReadKey(pTab, 0);
|
||||
if( p->aTab[i].keyAsData ){
|
||||
if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
char *z = sqliteDbbeReadKey(pCrsr, 0);
|
||||
if( p->aCsr[i].keyAsData ){
|
||||
p->zStack[tos] = z;
|
||||
p->aStack[tos].flags = STK_Str;
|
||||
p->aStack[tos].n = sqliteDbbeKeyLength(pTab);
|
||||
p->aStack[tos].n = sqliteDbbeKeyLength(pCrsr);
|
||||
}else{
|
||||
memcpy(&p->aStack[tos].i, z, sizeof(int));
|
||||
p->aStack[tos].flags = STK_Int;
|
||||
@@ -2017,25 +2031,25 @@ int sqliteVdbeExec(
|
||||
/* Opcode: Rewind P1 * *
|
||||
**
|
||||
** The next use of the Key or Field or Next instruction for P1
|
||||
** will refer to the first entry in the table.
|
||||
** will refer to the first entry in the database file.
|
||||
*/
|
||||
case OP_Rewind: {
|
||||
int i = pOp->p1;
|
||||
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
|
||||
sqliteDbbeRewind(p->aTab[i].pTable);
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
|
||||
sqliteDbbeRewind(p->aCsr[i].pCursor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Next P1 P2 *
|
||||
**
|
||||
** Advance P1 to the next entry in the table. Or, if there are no
|
||||
** more entries, rewind P1 and jump to location P2.
|
||||
** Advance P1 to the next key/data pair in the file. Or, if there are no
|
||||
** more key/data pairs, rewind P1 and jump to location P2.
|
||||
*/
|
||||
case OP_Next: {
|
||||
int i = pOp->p1;
|
||||
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
|
||||
if( sqliteDbbeNextKey(p->aTab[i].pTable)==0 ){
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
|
||||
if( sqliteDbbeNextKey(p->aCsr[i].pCursor)==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}else{
|
||||
p->nFetch++;
|
||||
@@ -2046,37 +2060,48 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: ResetIdx P1 * *
|
||||
**
|
||||
** Begin treating the current row of table P1 as an index. The next
|
||||
** NextIdx instruction will refer to the first index in the table.
|
||||
** Begin treating the current data in cursor P1 as a bunch of integer
|
||||
** keys to records of a (separate) SQL table file. This instruction
|
||||
** causes the new NextIdx instruction push the first integer table
|
||||
** key in the data.
|
||||
*/
|
||||
case OP_ResetIdx: {
|
||||
int i = pOp->p1;
|
||||
if( i>=0 && i<p->nTable ){
|
||||
p->aTab[i].index = 0;
|
||||
if( i>=0 && i<p->nCursor ){
|
||||
p->aCsr[i].index = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: NextIdx P1 P2 *
|
||||
**
|
||||
** Push the next index from the current entry of table P1 onto the
|
||||
** stack and advance the pointer. If there are no more indices, then
|
||||
** reset the table entry and jump to P2
|
||||
** The P1 cursor points to an SQL index. The data from the most
|
||||
** recent fetch on that cursor consists of a bunch of integers where
|
||||
** each integer is the key to a record in an SQL table file.
|
||||
** This instruction grabs the next integer table key from the data
|
||||
** of P1 and pushes that integer onto the stack. The first time
|
||||
** this instruction is executed after a fetch, the first integer
|
||||
** table key is pushed. Subsequent integer table keys are pushed
|
||||
** in each subsequent execution of this instruction.
|
||||
**
|
||||
** If there are no more integer table keys in the data of P1
|
||||
** when this instruction is executed, then nothing gets pushed and
|
||||
** there is an immediate jump to instruction P2.
|
||||
*/
|
||||
case OP_NextIdx: {
|
||||
int i = pOp->p1;
|
||||
int tos = ++p->tos;
|
||||
DbbeTable *pTab;
|
||||
DbbeCursor *pCrsr;
|
||||
|
||||
if( NeedStack(p, p->tos) ) goto no_mem;
|
||||
p->zStack[tos] = 0;
|
||||
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
|
||||
if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int *aIdx;
|
||||
int nIdx;
|
||||
int j;
|
||||
nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
|
||||
aIdx = (int*)sqliteDbbeReadData(pTab, 0);
|
||||
for(j=p->aTab[i].index; j<nIdx; j++){
|
||||
nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
|
||||
aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);
|
||||
for(j=p->aCsr[i].index; j<nIdx; j++){
|
||||
if( aIdx[j]!=0 ){
|
||||
p->aStack[tos].i = aIdx[j];
|
||||
p->aStack[tos].flags = STK_Int;
|
||||
@@ -2088,47 +2113,47 @@ int sqliteVdbeExec(
|
||||
pc = pOp->p2 - 1;
|
||||
PopStack(p, 1);
|
||||
}
|
||||
p->aTab[i].index = j+1;
|
||||
p->aCsr[i].index = j+1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: PutIdx P1 * *
|
||||
**
|
||||
** The top of the stack hold an index key (probably made using the
|
||||
** MakeKey instruction) and next on stack holds an index value for
|
||||
** a table. Locate the record in the index P1 that has the key
|
||||
** and insert the index value into its
|
||||
** data. Write the results back to the index.
|
||||
** If the key doesn't exist it is created.
|
||||
** The top of the stack hold an SQL index key (probably made using the
|
||||
** MakeKey instruction) and next on stack holds an integer which
|
||||
** the key to an SQL table entry. Locate the record in cursor P1
|
||||
** that has the same key as on the TOS. Create a new record if
|
||||
** necessary. Then append the integer table key to the data for that
|
||||
** record and write it back to the P1 file.
|
||||
*/
|
||||
case OP_PutIdx: {
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
int nos = tos - 1;
|
||||
DbbeTable *pTab;
|
||||
DbbeCursor *pCrsr;
|
||||
if( nos<0 ) goto not_enough_stack;
|
||||
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
|
||||
if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int r;
|
||||
int newVal;
|
||||
Integerify(p, nos);
|
||||
newVal = p->aStack[nos].i;
|
||||
if( Stringify(p, tos) ) goto no_mem;
|
||||
r = sqliteDbbeFetch(pTab, p->aStack[tos].n, p->zStack[tos]);
|
||||
r = sqliteDbbeFetch(pCrsr, p->aStack[tos].n, p->zStack[tos]);
|
||||
if( r==0 ){
|
||||
/* Create a new record for this index */
|
||||
sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos],
|
||||
sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
|
||||
sizeof(int), (char*)&newVal);
|
||||
}else{
|
||||
/* Extend the existing record */
|
||||
int nIdx;
|
||||
int *aIdx;
|
||||
nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
|
||||
nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
|
||||
aIdx = sqliteMalloc( sizeof(int)*(nIdx+1) );
|
||||
if( aIdx==0 ) goto no_mem;
|
||||
sqliteDbbeCopyData(pTab, 0, nIdx*sizeof(int), (char*)aIdx);
|
||||
sqliteDbbeCopyData(pCrsr, 0, nIdx*sizeof(int), (char*)aIdx);
|
||||
aIdx[nIdx] = newVal;
|
||||
sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos],
|
||||
sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
|
||||
sizeof(int)*(nIdx+1), (char*)aIdx);
|
||||
sqliteFree(aIdx);
|
||||
}
|
||||
@@ -2139,20 +2164,24 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: DeleteIdx P1 * *
|
||||
**
|
||||
** The top of the stack is a key and next on stack is an index value.
|
||||
** Locate the record
|
||||
** in index P1 that has the key and remove the index value from its
|
||||
** data. Write the results back to the table. If after removing
|
||||
** the index value no more indices remain in the record, then the
|
||||
** record is removed from the table.
|
||||
** The top of the stack is a key and next on stack is integer
|
||||
** which is the key to a record in an SQL table.
|
||||
** Locate the record in the cursor P1 (P1 represents an SQL index)
|
||||
** that has the same key as the top of stack. Then look through
|
||||
** the integer table-keys contained in the data of the P1 record.
|
||||
** Remove the integer table-key that matches the NOS and write the
|
||||
** revised data back to P1 with the same key.
|
||||
**
|
||||
** If this routine removes the very last integer table-key from
|
||||
** the P1 data, then the corresponding P1 record is deleted.
|
||||
*/
|
||||
case OP_DeleteIdx: {
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
int nos = tos - 1;
|
||||
DbbeTable *pTab;
|
||||
DbbeCursor *pCrsr;
|
||||
if( nos<0 ) goto not_enough_stack;
|
||||
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
|
||||
if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int *aIdx;
|
||||
int nIdx;
|
||||
int j;
|
||||
@@ -2161,17 +2190,17 @@ int sqliteVdbeExec(
|
||||
Integerify(p, nos);
|
||||
oldVal = p->aStack[nos].i;
|
||||
if( Stringify(p, tos) ) goto no_mem;
|
||||
r = sqliteDbbeFetch(pTab, p->aStack[tos].n, p->zStack[tos]);
|
||||
r = sqliteDbbeFetch(pCrsr, p->aStack[tos].n, p->zStack[tos]);
|
||||
if( r==0 ) break;
|
||||
nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
|
||||
aIdx = (int*)sqliteDbbeReadData(pTab, 0);
|
||||
nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
|
||||
aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);
|
||||
for(j=0; j<nIdx && aIdx[j]!=oldVal; j++){}
|
||||
if( j>=nIdx ) break;
|
||||
aIdx[j] = aIdx[nIdx-1];
|
||||
if( nIdx==1 ){
|
||||
sqliteDbbeDelete(pTab, p->aStack[tos].n, p->zStack[tos]);
|
||||
sqliteDbbeDelete(pCrsr, p->aStack[tos].n, p->zStack[tos]);
|
||||
}else{
|
||||
sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos],
|
||||
sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
|
||||
sizeof(int)*(nIdx-1), (char*)aIdx);
|
||||
}
|
||||
}
|
||||
@@ -2181,8 +2210,9 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: Destroy * * P3
|
||||
**
|
||||
** Drop the table whose name is P3. The file that holds this table
|
||||
** is removed from the disk drive.
|
||||
** Drop the disk file whose name is P3. All key/data pairs in
|
||||
** the file are deleted and the file itself is removed
|
||||
** from the disk.
|
||||
*/
|
||||
case OP_Destroy: {
|
||||
sqliteDbbeDropTable(p->pBe, pOp->p3);
|
||||
@@ -2200,7 +2230,7 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: ListOpen P1 * *
|
||||
**
|
||||
** Open a file used for temporary storage of index numbers. P1
|
||||
** Open a file used for temporary storage of integer table keys. P1
|
||||
** will server as a handle to this temporary file for future
|
||||
** interactions. If another temporary file with the P1 handle is
|
||||
** already opened, the prior file is closed and a new one opened
|
||||
@@ -2260,7 +2290,7 @@ int sqliteVdbeExec(
|
||||
/* Opcode: ListRead P1 P2 *
|
||||
**
|
||||
** Attempt to read an integer from temporary storage buffer P1
|
||||
** and push it onto the stack. If the storage buffer is empty
|
||||
** and push it onto the stack. If the storage buffer is empty,
|
||||
** push nothing but instead jump to P2.
|
||||
*/
|
||||
case OP_ListRead: {
|
||||
@@ -2693,7 +2723,7 @@ int sqliteVdbeExec(
|
||||
/* Opcode: FileField P1 * *
|
||||
**
|
||||
** Push onto the stack the P1-th field of the most recently read line
|
||||
** from the file.
|
||||
** from the input file.
|
||||
*/
|
||||
case OP_FileField: {
|
||||
int i = pOp->p1;
|
||||
@@ -2828,8 +2858,8 @@ int sqliteVdbeExec(
|
||||
|
||||
/* Opcode: AggIncr P1 P2 *
|
||||
**
|
||||
** Increment the P2-th field of the aggregate element current
|
||||
** in focus by an amount P1.
|
||||
** Increase the integer value in the P2-th field of the aggregate
|
||||
** element current in focus by an amount P1.
|
||||
*/
|
||||
case OP_AggIncr: {
|
||||
AggElem *pFocus = AggInFocus(p->agg);
|
||||
|
Reference in New Issue
Block a user