:-) (CVS 52)
FossilOrigin-Name: c02268bdf4c28edc2542ce0ca1ba24fd6b5058fa
diff --git a/src/build.c b/src/build.c
index 5144f13..d88e57c 100644
--- a/src/build.c
+++ b/src/build.c
@@ -33,7 +33,7 @@
** COPY
** VACUUM
**
-** $Id: build.c,v 1.14 2000/06/03 18:06:52 drh Exp $
+** $Id: build.c,v 1.15 2000/06/05 18:54:46 drh Exp $
*/
#include "sqliteInt.h"
@@ -108,6 +108,8 @@
if( p==0 ) return;
if( p->pLeft ) sqliteExprDelete(p->pLeft);
if( p->pRight ) sqliteExprDelete(p->pRight);
+ if( p->pList ) sqliteExprListDelete(p->pList);
+ if( p->pSelect ) sqliteSelectDelete(p->pSelect);
sqliteFree(p);
}
diff --git a/src/expr.c b/src/expr.c
index a993834..5fd5bbb 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -23,7 +23,7 @@
*************************************************************************
** This file contains C code routines used for processing expressions
**
-** $Id: expr.c,v 1.5 2000/06/04 12:58:37 drh Exp $
+** $Id: expr.c,v 1.6 2000/06/05 18:54:46 drh Exp $
*/
#include "sqliteInt.h"
@@ -32,8 +32,13 @@
** table fields. Nodes of the form ID.ID or ID resolve into an
** index to the table in the table list and a field offset. The opcode
** for such nodes is changed to TK_FIELD. The iTable value is changed
-** to the index of the referenced table in pTabList, and the iField value
-** is changed to the index of the field of the referenced table.
+** to the index of the referenced table in pTabList plus the pParse->nTab
+** value. The iField value is changed to the index of the field of the
+** referenced table.
+**
+** This routine also looks for SELECTs that are part of an expression.
+** If it finds any, it generates code to write the value of that select
+** into a memory cell.
**
** Unknown fields or tables provoke an error. The function returns
** the number of errors seen and leaves an error message on pParse->zErrMsg.
@@ -54,7 +59,7 @@
for(j=0; j<pTab->nCol; j++){
if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
cnt++;
- pExpr->iTable = i;
+ pExpr->iTable = i + pParse->nTab;
pExpr->iField = j;
}
}
@@ -104,7 +109,7 @@
for(j=0; j<pTab->nCol; j++){
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
cnt++;
- pExpr->iTable = i;
+ pExpr->iTable = i + pParse->nTab;
pExpr->iField = j;
}
}
@@ -132,6 +137,14 @@
break;
}
+ case TK_SELECT: {
+ pExpr->iField = pParse->nMem++;
+ if( sqliteSelect(pParse, pExpr->pSelect, -1, pExpr->iField) ){
+ return 1;
+ }
+ break;
+ }
+
/* For all else, just recursively walk the tree */
default: {
if( pExpr->pLeft
@@ -385,6 +398,10 @@
}
break;
}
+ case TK_SELECT: {
+ sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iField, 0, 0, 0);
+ break;
+ }
}
return;
}
diff --git a/src/insert.c b/src/insert.c
index 24fcff6..112ba33 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements.
**
-** $Id: insert.c,v 1.5 2000/06/04 12:58:38 drh Exp $
+** $Id: insert.c,v 1.6 2000/06/05 18:54:46 drh Exp $
*/
#include "sqliteInt.h"
@@ -101,7 +101,10 @@
}
}
}
- v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+ v = pParse->pVdbe;
+ if( v==0 ){
+ v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+ }
if( v ){
Index *pIdx;
sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
diff --git a/src/parse.y b/src/parse.y
index 001b03d..125a140 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -26,7 +26,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.9 2000/06/05 16:01:39 drh Exp $
+** @(#) $Id: parse.y,v 1.10 2000/06/05 18:54:46 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -133,7 +133,7 @@
// The select statement
//
cmd ::= select(X). {
- sqliteSelect(pParse, X, 0, 0);
+ sqliteSelect(pParse, X, -1, -1);
sqliteSelectDelete(X);
}
@@ -311,6 +311,10 @@
expr(A) ::= NOT expr(X). {A = sqliteExpr(TK_NOT, X, 0, 0);}
expr(A) ::= MINUS expr(X). [UMINUS] {A = sqliteExpr(TK_UMINUS, X, 0, 0);}
expr(A) ::= PLUS expr(X). [UMINUS] {A = X;}
+expr(A) ::= LP select(X) RP. {
+ A = sqliteExpr(TK_SELECT, 0, 0, 0);
+ A->pSelect = X;
+}
%type exprlist {ExprList*}
%destructor exprlist {sqliteExprListDelete($$);}
diff --git a/src/select.c b/src/select.c
index e1f9489..5317452 100644
--- a/src/select.c
+++ b/src/select.c
@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
-** $Id: select.c,v 1.7 2000/06/05 16:01:39 drh Exp $
+** $Id: select.c,v 1.8 2000/06/05 18:54:46 drh Exp $
*/
#include "sqliteInt.h"
@@ -71,11 +71,12 @@
/*
** Generate code for the given SELECT statement.
**
-** If pDest==0 and iMem<0, then the results of the query are sent to
-** the callback function. If pDest!=0 then the results are written to
-** the single table specified. If pDest==0 and iMem>=0 then the result
-** should be a single value which is then stored in memory location iMem
-** of the virtual machine.
+** If iDest<0 and iMem<0, then the results of the query are sent to
+** the callback function. If iDest>=0 then the results are written to
+** an open cursor with the index iDest. The calling function is
+** responsible for having that cursor open. If iDest<0 and iMem>=0
+** then the result should be a single value which is then stored in
+** memory location iMem of the virtual machine.
**
** This routine returns the number of errors. If any errors are
** encountered, then an appropriate error message is left in
@@ -87,7 +88,7 @@
int sqliteSelect(
Parse *pParse, /* The parser context */
Select *p, /* The SELECT statement being coded. */
- Table *pDest, /* Write results here, if not NULL */
+ int iDest, /* Write results to this cursor */
int iMem /* Save result in this memory location, if >=0 */
){
int i, j;
@@ -98,14 +99,14 @@
IdList *pTabList; /* List of tables to select from */
Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
- int distinct; /* If true, only output distinct results */
-
+ int isDistinct; /* True if the DISTINCT keyword is present */
+ int distinct; /* Table to use for the distinct set */
pEList = p->pEList;
pTabList = p->pSrc;
pWhere = p->pWhere;
pOrderBy = p->pOrderBy;
- distinct = p->isDistinct;
+ isDistinct = p->isDistinct;
/*
** Do not even attempt to generate any code if we have already seen
@@ -125,6 +126,13 @@
}
}
+ /* Allocate a temporary table to use for the DISTINCT set, if
+ ** necessary.
+ */
+ if( isDistinct ){
+ distinct = pParse->nTab++;
+ }
+
/* If the list of fields to retrieve is "*" then replace it with
** a list of all fields from all tables.
*/
@@ -133,13 +141,22 @@
Table *pTab = pTabList->a[i].pTab;
for(j=0; j<pTab->nCol; j++){
Expr *pExpr = sqliteExpr(TK_FIELD, 0, 0, 0);
- pExpr->iTable = i;
+ pExpr->iTable = i + pParse->nTab;
pExpr->iField = j;
pEList = sqliteExprListAppend(pEList, pExpr, 0);
}
}
}
+ /* If writing to memory, only a single column may be output.
+ */
+ if( iMem>=0 && pEList->nExpr>1 ){
+ sqliteSetString(&pParse->zErrMsg, "only a single result allowed for "
+ "a SELECT that is part of an expression", 0);
+ pParse->nErr++;
+ return 1;
+ }
+
/* Resolve the field names and do a semantics check on all the expressions.
*/
for(i=0; i<pEList->nExpr; i++){
@@ -180,17 +197,25 @@
}
}
- /* ORDER BY is ignored if this is an aggregate query like count(*)
- ** since only one row will be returned.
+ /* ORDER BY is ignored if
+ **
+ ** (1) this is an aggregate query like count(*)
+ ** since only one row will be returned.
+ **
+ ** (2) We are writing the result to another table, since the
+ ** order will get scrambled again after inserting.
+ **
+ ** (3) We are writing to a memory cell, since there is only
+ ** one result.
*/
- if( isAgg && pOrderBy ){
+ if( isAgg || iDest>=0 || iMem>=0 ){
pOrderBy = 0;
}
- /* Turn off distinct if this is an aggregate
+ /* Turn off distinct if this is an aggregate or writing to memory.
*/
- if( isAgg ){
- distinct = 0;
+ if( isAgg || iMem>=0 ){
+ isDistinct = 0;
}
/* Begin generating code.
@@ -208,38 +233,42 @@
sqliteVdbeAddOp(v, OP_SortOpen, 0, 0, 0, 0);
}
- /* Identify column names
+ /* Identify column names if we will be using a callback. This
+ ** step is skipped if the output is going to a table or a memory cell.
*/
- sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0, 0, 0);
- for(i=0; i<pEList->nExpr; i++){
- Expr *p;
- if( pEList->a[i].zName ){
- char *zName = pEList->a[i].zName;
- int addr = sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
- if( zName[0]=='\'' || zName[0]=='"' ){
- sqliteVdbeDequoteP3(v, addr);
+ if( iDest<0 && iMem<0 ){
+ sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0, 0, 0);
+ for(i=0; i<pEList->nExpr; i++){
+ Expr *p;
+ if( pEList->a[i].zName ){
+ char *zName = pEList->a[i].zName;
+ int addr = sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+ if( zName[0]=='\'' || zName[0]=='"' ){
+ sqliteVdbeDequoteP3(v, addr);
+ }
+ continue;
}
- continue;
- }
- p = pEList->a[i].pExpr;
- if( p->op!=TK_FIELD ){
- char zName[30];
- sprintf(zName, "field%d", i+1);
- sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
- }else{
- if( pTabList->nId>1 ){
- char *zName = 0;
- Table *pTab = pTabList->a[p->iTable].pTab;
- char *zTab;
-
- zTab = pTabList->a[p->iTable].zAlias;
- if( zTab==0 ) zTab = pTab->zName;
- sqliteSetString(&zName, zTab, ".", pTab->aCol[p->iField].zName, 0);
+ p = pEList->a[i].pExpr;
+ if( p->op!=TK_FIELD ){
+ char zName[30];
+ sprintf(zName, "field%d", i+1);
sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
- sqliteFree(zName);
}else{
- Table *pTab = pTabList->a[0].pTab;
- sqliteVdbeAddOp(v, OP_ColumnName, i, 0, pTab->aCol[p->iField].zName, 0);
+ if( pTabList->nId>1 ){
+ char *zName = 0;
+ Table *pTab = pTabList->a[p->iTable].pTab;
+ char *zTab;
+
+ zTab = pTabList->a[p->iTable].zAlias;
+ if( zTab==0 ) zTab = pTab->zName;
+ sqliteSetString(&zName, zTab, ".", pTab->aCol[p->iField].zName, 0);
+ sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+ sqliteFree(zName);
+ }else{
+ Table *pTab = pTabList->a[0].pTab;
+ char *zName = pTab->aCol[p->iField].zName;
+ sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+ }
}
}
}
@@ -263,10 +292,16 @@
}
}
+ /* Initialize the memory cell to NULL
+ */
+ if( iMem>=0 ){
+ sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_MemStore, iMem, 0, 0, 0);
+ }
+
/* Begin the database scan
*/
- if( distinct ){
- distinct = pTabList->nId*2+1;
+ if( isDistinct ){
sqliteVdbeAddOp(v, OP_Open, distinct, 1, 0, 0);
}
pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
@@ -283,13 +318,13 @@
/* If the current result is not distinct, script the remainder
** of this processing.
*/
- if( distinct ){
- int isDistinct = sqliteVdbeMakeLabel(v);
+ if( isDistinct ){
+ int lbl = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1, 0, 0);
- sqliteVdbeAddOp(v, OP_Distinct, distinct, isDistinct, 0, 0);
+ sqliteVdbeAddOp(v, OP_Distinct, distinct, lbl, 0, 0);
sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue, 0, 0);
- sqliteVdbeAddOp(v, OP_String, 0, 0, "", isDistinct);
+ sqliteVdbeAddOp(v, OP_String, 0, 0, "", lbl);
sqliteVdbeAddOp(v, OP_Put, distinct, 0, 0, 0);
}
@@ -330,6 +365,14 @@
}
sqliteVdbeAddOp(v, op, p1, 0, 0, 0);
}
+ }else if( iDest>=0 ){
+ sqliteVdbeAddOp(v, OP_MakeRecord, pEList->nExpr, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_New, iDest, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Pull, 1, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Put, iDest, 0, 0, 0);
+ }else if( iMem>=0 ){
+ sqliteVdbeAddOp(v, OP_MemStore, iMem, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iBreak, 0, 0);
}else{
sqliteVdbeAddOp(v, OP_Callback, pEList->nExpr, 0, 0, 0);
}
@@ -348,14 +391,23 @@
addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end, 0, 0);
sqliteVdbeAddOp(v, OP_SortCallback, pEList->nExpr, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
- sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, end);
+ sqliteVdbeAddOp(v, OP_SortClose, 0, 0, 0, end);
}
/* If this is an aggregate, then we need to invoke the callback
** exactly once.
*/
if( isAgg ){
- sqliteVdbeAddOp(v, OP_Callback, pEList->nExpr, 0, 0, 0);
+ if( iDest>=0 ){
+ sqliteVdbeAddOp(v, OP_MakeRecord, pEList->nExpr, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_New, iDest, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Pull, 1, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Put, iDest, 0, 0, 0);
+ }else if( iMem>=0 ){
+ sqliteVdbeAddOp(v, OP_MemStore, iMem, 0, 0, 0);
+ }else{
+ sqliteVdbeAddOp(v, OP_Callback, pEList->nExpr, 0, 0, 0);
+ }
}
return 0;
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index a0a6f31..eca54c4 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -23,7 +23,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.14 2000/06/05 16:01:39 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.15 2000/06/05 18:54:46 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
@@ -162,6 +162,7 @@
Token token; /* An operand token */
int iTable, iField; /* When op==TK_FIELD, then this node means the
** iField-th field of the iTable-th table */
+ Select *pSelect; /* When the expression is a sub-select */
};
/*
@@ -191,7 +192,7 @@
char *zName; /* Text of the identifier. */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* Table corresponding to zName */
- int idx; /* Index of a field name in the table */
+ int idx; /* Index of a field named zName in a table */
} *a; /* One entry for each identifier on the list */
};
@@ -204,9 +205,11 @@
*/
struct WhereInfo {
Parse *pParse;
- IdList *pTabList;
- int iContinue;
- int iBreak;
+ IdList *pTabList; /* List of tables in the join */
+ int iContinue; /* Jump here to continue with next record */
+ int iBreak; /* Jump here to break out of the loop */
+ int base; /* Index of first Open opcode */
+ Index *aIdx[32]; /* Indices used for each table */
};
/*
@@ -239,6 +242,8 @@
int explain; /* True if the EXPLAIN flag is found on the query */
int initFlag; /* True if reparsing CREATE TABLEs */
int nErr; /* Number of errors seen */
+ int nTab; /* Number of previously allocated cursors */
+ int nMem; /* Number of memory cells used so far */
};
/*
@@ -281,7 +286,7 @@
void sqliteIdListDelete(IdList*);
void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, Token*, Token*);
void sqliteDropIndex(Parse*, Token*);
-int sqliteSelect(Parse*, Select*, Table*, int);
+int sqliteSelect(Parse*, Select*, int, int);
Select *sqliteSelectNew(ExprList*,IdList*,Expr*,ExprList*,Expr*,ExprList*,int);
void sqliteSelectDelete(Select*);
void sqliteDeleteFrom(Parse*, Token*, Expr*);
diff --git a/src/vdbe.c b/src/vdbe.c
index d302a03..1b836bb 100644
--- a/src/vdbe.c
+++ b/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.15 2000/06/05 16:01:39 drh Exp $
+** $Id: vdbe.c,v 1.16 2000/06/05 18:54:47 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
@@ -92,11 +92,21 @@
int i; /* Integer value */
int n; /* Number of characters in string value, including '\0' */
int flags; /* Some combination of STK_Null, STK_Str, STK_Dyn, etc. */
- double r; /* Real value */
+ double r; /* Real value */
};
typedef struct Stack Stack;
/*
+** Memory cells use the same structure as the stack except that space
+** for an arbitrary string is added.
+*/
+struct Mem {
+ Stack s; /* All values of the memory cell besides string */
+ char *z; /* String value for this memory cell */
+};
+typedef struct Mem Mem;
+
+/*
** Allowed values for Stack.flags
*/
#define STK_Null 0x0001 /* Value is NULL */
@@ -133,6 +143,8 @@
char **azField; /* Data for each file field */
char *zLine; /* A single line from the input file */
int nLineAlloc; /* Number of spaces allocated for zLine */
+ int nMem; /* Number of memory locations currently allocated */
+ Mem *aMem; /* The memory locations */
};
/*
@@ -464,6 +476,14 @@
sqliteFree(p->aTab);
p->aTab = 0;
p->nTable = 0;
+ for(i=0; i<p->nMem; i++){
+ if( p->aMem[i].s.flags & STK_Dyn ){
+ sqliteFree(p->aMem[i].z);
+ }
+ }
+ sqliteFree(p->aMem);
+ p->aMem = 0;
+ p->nMem = 0;
for(i=0; i<p->nList; i++){
if( p->apList[i] ){
sqliteDbbeCloseTempFile(p->pBe, p->apList[i]);
@@ -536,20 +556,21 @@
"Put", "Distinct", "Delete", "Field",
"Key", "Rewind", "Next", "Destroy",
"Reorganize", "ResetIdx", "NextIdx", "PutIdx",
- "DeleteIdx", "ListOpen", "ListWrite", "ListRewind",
- "ListRead", "ListClose", "SortOpen", "SortPut",
- "SortMakeRec", "SortMakeKey", "Sort", "SortNext",
- "SortKey", "SortCallback", "SortClose", "FileOpen",
- "FileRead", "FileField", "FileClose", "MakeRecord",
- "MakeKey", "Goto", "If", "Halt",
- "ColumnCount", "ColumnName", "Callback", "Integer",
- "String", "Null", "Pop", "Dup",
- "Pull", "Add", "AddImm", "Subtract",
- "Multiply", "Divide", "Min", "Max",
- "Like", "Glob", "Eq", "Ne",
- "Lt", "Le", "Gt", "Ge",
- "IsNull", "NotNull", "Negative", "And",
- "Or", "Not", "Concat", "Noop",
+ "DeleteIdx", "MemLoad", "MemStore", "ListOpen",
+ "ListWrite", "ListRewind", "ListRead", "ListClose",
+ "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey",
+ "Sort", "SortNext", "SortKey", "SortCallback",
+ "SortClose", "FileOpen", "FileRead", "FileField",
+ "FileClose", "MakeRecord", "MakeKey", "Goto",
+ "If", "Halt", "ColumnCount", "ColumnName",
+ "Callback", "Integer", "String", "Null",
+ "Pop", "Dup", "Pull", "Add",
+ "AddImm", "Subtract", "Multiply", "Divide",
+ "Min", "Max", "Like", "Glob",
+ "Eq", "Ne", "Lt", "Le",
+ "Gt", "Ge", "IsNull", "NotNull",
+ "Negative", "And", "Or", "Not",
+ "Concat", "Noop",
};
/*
@@ -2402,6 +2423,64 @@
break;
}
+ /* Opcode: MemStore P1 * *
+ **
+ ** 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
+ ** for all memory locations between 0 and P1 inclusive.
+ */
+ case OP_MemStore: {
+ int i = pOp->p1;
+ int tos = p->tos;
+ Mem *pMem;
+ if( tos<0 ) goto not_enough_stack;
+ if( i>=p->nMem ){
+ int nOld = p->nMem;
+ p->nMem = i + 5;
+ p->aMem = sqliteRealloc(p->aMem, p->nMem*sizeof(p->aMem[0]));
+ if( p->aMem==0 ) goto no_mem;
+ if( nOld<p->nMem ){
+ memset(&p->aMem[nOld], 0, sizeof(p->aMem[0])*(p->nMem-nOld));
+ }
+ }
+ pMem = &p->aMem[i];
+ if( pMem->s.flags & STK_Dyn ){
+ sqliteFree(pMem->z);
+ }
+ pMem->s = p->aStack[tos];
+ if( pMem->s.flags & STK_Str ){
+ pMem->z = 0;
+ sqliteSetString(&pMem->z, p->zStack[tos], 0);
+ pMem->s.flags |= STK_Dyn;
+ }
+ PopStack(p, 1);
+ break;
+ }
+
+ /* Opcode: MemLoad P1 * *
+ **
+ ** Push a copy of the value in memory location P1 onto the stack.
+ */
+ case OP_MemLoad: {
+ int tos = ++p->tos;
+ int i = pOp->p1;
+ if( NeedStack(p, tos) ) goto no_mem;
+ if( i<0 || i>=p->nMem ){
+ p->aStack[tos].flags = STK_Null;
+ p->zStack[tos] = 0;
+ }else{
+ p->aStack[tos] = p->aMem[i].s;
+ if( p->aStack[tos].flags & STK_Str ){
+ char *z = sqliteMalloc(p->aStack[tos].n);
+ if( z==0 ) goto no_mem;
+ memcpy(z, p->aMem[i].z, p->aStack[tos].n);
+ p->zStack[tos] = z;
+ p->aStack[tos].flags |= STK_Dyn;
+ }
+ }
+ break;
+ }
+
/* An other opcode is illegal...
*/
default: {
diff --git a/src/vdbe.h b/src/vdbe.h
index 3abba05..c85a1d3 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -27,7 +27,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
-** $Id: vdbe.h,v 1.5 2000/06/04 12:58:39 drh Exp $
+** $Id: vdbe.h,v 1.6 2000/06/05 18:54:47 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -91,70 +91,73 @@
#define OP_PutIdx 16
#define OP_DeleteIdx 17
-#define OP_ListOpen 18
-#define OP_ListWrite 19
-#define OP_ListRewind 20
-#define OP_ListRead 21
-#define OP_ListClose 22
+#define OP_MemLoad 18
+#define OP_MemStore 19
-#define OP_SortOpen 23
-#define OP_SortPut 24
-#define OP_SortMakeRec 25
-#define OP_SortMakeKey 26
-#define OP_Sort 27
-#define OP_SortNext 28
-#define OP_SortKey 29
-#define OP_SortCallback 30
-#define OP_SortClose 31
+#define OP_ListOpen 20
+#define OP_ListWrite 21
+#define OP_ListRewind 22
+#define OP_ListRead 23
+#define OP_ListClose 24
-#define OP_FileOpen 32
-#define OP_FileRead 33
-#define OP_FileField 34
-#define OP_FileClose 35
+#define OP_SortOpen 25
+#define OP_SortPut 26
+#define OP_SortMakeRec 27
+#define OP_SortMakeKey 28
+#define OP_Sort 29
+#define OP_SortNext 30
+#define OP_SortKey 31
+#define OP_SortCallback 32
+#define OP_SortClose 33
-#define OP_MakeRecord 36
-#define OP_MakeKey 37
+#define OP_FileOpen 34
+#define OP_FileRead 35
+#define OP_FileField 36
+#define OP_FileClose 37
-#define OP_Goto 38
-#define OP_If 39
-#define OP_Halt 40
+#define OP_MakeRecord 38
+#define OP_MakeKey 39
-#define OP_ColumnCount 41
-#define OP_ColumnName 42
-#define OP_Callback 43
+#define OP_Goto 40
+#define OP_If 41
+#define OP_Halt 42
-#define OP_Integer 44
-#define OP_String 45
-#define OP_Null 46
-#define OP_Pop 47
-#define OP_Dup 48
-#define OP_Pull 49
+#define OP_ColumnCount 43
+#define OP_ColumnName 44
+#define OP_Callback 45
-#define OP_Add 50
-#define OP_AddImm 51
-#define OP_Subtract 52
-#define OP_Multiply 53
-#define OP_Divide 54
-#define OP_Min 55
-#define OP_Max 56
-#define OP_Like 57
-#define OP_Glob 58
-#define OP_Eq 59
-#define OP_Ne 60
-#define OP_Lt 61
-#define OP_Le 62
-#define OP_Gt 63
-#define OP_Ge 64
-#define OP_IsNull 65
-#define OP_NotNull 66
-#define OP_Negative 67
-#define OP_And 68
-#define OP_Or 69
-#define OP_Not 70
-#define OP_Concat 71
-#define OP_Noop 72
+#define OP_Integer 46
+#define OP_String 47
+#define OP_Null 48
+#define OP_Pop 49
+#define OP_Dup 50
+#define OP_Pull 51
-#define OP_MAX 72
+#define OP_Add 52
+#define OP_AddImm 53
+#define OP_Subtract 54
+#define OP_Multiply 55
+#define OP_Divide 56
+#define OP_Min 57
+#define OP_Max 58
+#define OP_Like 59
+#define OP_Glob 60
+#define OP_Eq 61
+#define OP_Ne 62
+#define OP_Lt 63
+#define OP_Le 64
+#define OP_Gt 65
+#define OP_Ge 66
+#define OP_IsNull 67
+#define OP_NotNull 68
+#define OP_Negative 69
+#define OP_And 70
+#define OP_Or 71
+#define OP_Not 72
+#define OP_Concat 73
+#define OP_Noop 74
+
+#define OP_MAX 74
/*
** Prototypes for the VDBE interface. See comments on the implementation
diff --git a/src/where.c b/src/where.c
index 188d172..69c7e16 100644
--- a/src/where.c
+++ b/src/where.c
@@ -25,7 +25,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
-** $Id: where.c,v 1.5 2000/05/31 15:34:54 drh Exp $
+** $Id: where.c,v 1.6 2000/06/05 18:54:47 drh Exp $
*/
#include "sqliteInt.h"
@@ -86,18 +86,22 @@
** In order for this routine to work, the calling function must have
** previously invoked sqliteExprResolveIds() on the expression. See
** the header comment on that routine for additional information.
+**
+** "base" is the cursor number (the value of the iTable field) that
+** corresponds to the first entry in the table list. This is the
+** same as pParse->nTab.
*/
-static int exprTableUsage(Expr *p){
+static int exprTableUsage(int base, Expr *p){
unsigned int mask = 0;
if( p==0 ) return 0;
if( p->op==TK_FIELD ){
- return 1<<p->iTable;
+ return 1<< (p->iTable - base);
}
if( p->pRight ){
- mask = exprTableUsage(p->pRight);
+ mask = exprTableUsage(base, p->pRight);
}
if( p->pLeft ){
- mask |= exprTableUsage(p->pLeft);
+ mask |= exprTableUsage(base, p->pLeft);
}
return mask;
}
@@ -107,21 +111,25 @@
** "p" field filled in. The job of this routine is to analyze the
** subexpression and populate all the other fields of the ExprInfo
** structure.
+**
+** "base" is the cursor number (the value of the iTable field) that
+** corresponds to the first entyr in the table list. This is the
+** same as pParse->nTab.
*/
-static void exprAnalyze(ExprInfo *pInfo){
+static void exprAnalyze(int base, ExprInfo *pInfo){
Expr *pExpr = pInfo->p;
- pInfo->prereqLeft = exprTableUsage(pExpr->pLeft);
- pInfo->prereqRight = exprTableUsage(pExpr->pRight);
+ pInfo->prereqLeft = exprTableUsage(base, pExpr->pLeft);
+ pInfo->prereqRight = exprTableUsage(base, pExpr->pRight);
pInfo->indexable = 0;
pInfo->idxLeft = -1;
pInfo->idxRight = -1;
if( pExpr->op==TK_EQ && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
if( pExpr->pRight->op==TK_FIELD ){
- pInfo->idxRight = pExpr->pRight->iTable;
+ pInfo->idxRight = pExpr->pRight->iTable - base;
pInfo->indexable = 1;
}
if( pExpr->pLeft->op==TK_FIELD ){
- pInfo->idxLeft = pExpr->pLeft->iTable;
+ pInfo->idxLeft = pExpr->pLeft->iTable - base;
pInfo->indexable = 1;
}
}
@@ -150,6 +158,7 @@
int nExpr; /* Number of subexpressions in the WHERE clause */
int loopMask; /* One bit set for each outer loop */
int haveKey; /* True if KEY is on the stack */
+ int base; /* First available index for OP_Open opcodes */
Index *aIdx[32]; /* Index to use on each nested loop. */
ExprInfo aExpr[50]; /* The WHERE clause is divided into these expressions */
@@ -166,6 +175,7 @@
}
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
+ base = pWInfo->base = pParse->nTab;
/* Split the WHERE clause into as many as 32 separate subexpressions
** where each subexpression is separated by an AND operator. Any additional
@@ -180,7 +190,7 @@
/* Analyze all of the subexpressions.
*/
for(i=0; i<nExpr; i++){
- exprAnalyze(&aExpr[i]);
+ exprAnalyze(pParse->nTab, &aExpr[i]);
}
/* Figure out a good nesting order for the tables. aOrder[0] will
@@ -261,11 +271,12 @@
/* Open all tables in the pTabList and all indices in aIdx[].
*/
for(i=0; i<pTabList->nId; i++){
- sqliteVdbeAddOp(v, OP_Open, i, 0, pTabList->a[i].pTab->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, base+i, 0, pTabList->a[i].pTab->zName, 0);
if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
- sqliteVdbeAddOp(v, OP_Open, pTabList->nId+i, 0, aIdx[i]->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, 0, aIdx[i]->zName, 0);
}
}
+ memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx));
/* Generate the code to do the search
*/
@@ -281,7 +292,7 @@
/* Case 1: There was no usable index. We must do a complete
** scan of the table.
*/
- sqliteVdbeAddOp(v, OP_Next, idx, brk, 0, cont);
+ sqliteVdbeAddOp(v, OP_Next, base+idx, brk, 0, cont);
haveKey = 0;
}else{
/* Case 2: We do have a usable index in pIdx.
@@ -308,8 +319,8 @@
}
}
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
- sqliteVdbeAddOp(v, OP_Fetch, pTabList->nId+i, 0, 0, 0);
- sqliteVdbeAddOp(v, OP_NextIdx, pTabList->nId+i, brk, 0, cont);
+ sqliteVdbeAddOp(v, OP_Fetch, base+pTabList->nId+i, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_NextIdx, base+pTabList->nId+i, brk, 0, cont);
if( i==pTabList->nId-1 && pushKey ){
haveKey = 1;
}else{
@@ -327,7 +338,7 @@
if( (aExpr[j].prereqRight & loopMask)!=aExpr[j].prereqRight ) continue;
if( (aExpr[j].prereqLeft & loopMask)!=aExpr[j].prereqLeft ) continue;
if( haveKey ){
- sqliteVdbeAddOp(v, OP_Fetch, idx, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Fetch, base+idx, 0, 0, 0);
haveKey = 0;
}
sqliteExprIfFalse(pParse, aExpr[j].p, cont);
@@ -348,8 +359,21 @@
*/
void sqliteWhereEnd(WhereInfo *pWInfo){
Vdbe *v = pWInfo->pParse->pVdbe;
+ int i;
+ int brk = pWInfo->iBreak;
+ int base = pWInfo->base;
+
sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue, 0, 0);
- sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, pWInfo->iBreak);
+ for(i=0; i<pWInfo->pTabList->nId; i++){
+ sqliteVdbeAddOp(v, OP_Close, base+i, 0, 0, brk);
+ brk = 0;
+ if( i<ARRAYSIZE(pWInfo->aIdx) && pWInfo->aIdx[i]!=0 ){
+ sqliteVdbeAddOp(v, OP_Close, base+pWInfo->pTabList->nId+i, 0, 0, 0);
+ }
+ }
+ if( brk!=0 ){
+ sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, brk);
+ }
sqliteFree(pWInfo);
return;
}