:-) (CVS 62)
FossilOrigin-Name: f4d9089c5d69b16fee5feb49b02e524499e6328d
diff --git a/src/parse.y b/src/parse.y
index 082ac27..e42aded 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.13 2000/06/06 17:27:05 drh Exp $
+** @(#) $Id: parse.y,v 1.14 2000/06/06 21:56:08 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -139,9 +139,22 @@
%type select {Select*}
%destructor select {sqliteSelectDelete($$);}
+%type oneselect {Select*}
+%destructor oneselect {sqliteSelectDelete($$);}
-select(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
- groupby_opt(P) having_opt(Q) orderby_opt(Z). {
+select(A) ::= oneselect(X). {A = X;}
+select(A) ::= select(X) joinop(Y) oneselect(Z). {
+ Z->op = Y;
+ Z->pPrior = X;
+ A = Z;
+}
+%type joinop {int}
+joinop(A) ::= UNION. {A = TK_UNION;}
+joinop(A) ::= UNION ALL. {A = TK_ALL;}
+joinop(A) ::= INTERSECT. {A = TK_INTERSECT;}
+joinop(A) ::= EXCEPT. {A = TK_EXCEPT;}
+oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
+ groupby_opt(P) having_opt(Q) orderby_opt(Z). {
A = sqliteSelectNew(W,X,Y,P,Q,Z,D);
}
@@ -222,6 +235,7 @@
having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;}
+
cmd ::= DELETE FROM ID(X) where_opt(Y).
{sqliteDeleteFrom(pParse, &X, Y);}
diff --git a/src/select.c b/src/select.c
index 8d04d9d..bcfcd69 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.12 2000/06/06 18:00:16 drh Exp $
+** $Id: select.c,v 1.13 2000/06/06 21:56:08 drh Exp $
*/
#include "sqliteInt.h"
@@ -51,6 +51,7 @@
pNew->pHaving = pHaving;
pNew->pOrderBy = pOrderBy;
pNew->isDistinct = isDistinct;
+ pNew->op = TK_SELECT;
return pNew;
}
@@ -58,12 +59,14 @@
** Delete the given Select structure and all of its substructures.
*/
void sqliteSelectDelete(Select *p){
+ if( p==0 ) return;
sqliteExprListDelete(p->pEList);
sqliteIdListDelete(p->pSrc);
sqliteExprDelete(p->pWhere);
sqliteExprListDelete(p->pGroupBy);
sqliteExprDelete(p->pHaving);
sqliteExprListDelete(p->pOrderBy);
+ sqliteSelectDelete(p->pPrior);
sqliteFree(p);
}
@@ -81,10 +84,16 @@
/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
+**
+** The pEList is used to determine the values for each column in the
+** result row. Except if pEList==NULL, then we just read nField
+** elements from the srcTab table.
*/
static int selectInnerLoop(
Parse *pParse, /* The parser context */
ExprList *pEList, /* List of values being extracted */
+ int srcTab, /* Pull data from this table */
+ int nField, /* Number of fields in the source table */
ExprList *pOrderBy, /* If not NULL, sort results using this key */
int distinct, /* If >=0, make sure results are distinct */
int eDest, /* How to dispose of the results */
@@ -97,8 +106,15 @@
/* Pull the requested fields.
*/
- for(i=0; i<pEList->nExpr; i++){
- sqliteExprCode(pParse, pEList->a[i].pExpr);
+ if( pEList ){
+ for(i=0; i<pEList->nExpr; i++){
+ sqliteExprCode(pParse, pEList->a[i].pExpr);
+ }
+ nField = pEList->nExpr;
+ }else{
+ for(i=0; i<nField; i++){
+ sqliteVdbeAddOp(v, OP_Field, srcTab, i, 0, 0);
+ }
}
/* If the current result is not distinct, skip the rest
@@ -113,6 +129,7 @@
sqliteVdbeAddOp(v, OP_String, 0, 0, "", lbl);
sqliteVdbeAddOp(v, OP_Put, distinct, 0, 0, 0);
}
+
/* If there is an ORDER BY clause, then store the results
** in a sorter.
*/
@@ -130,12 +147,22 @@
sqliteVdbeAddOp(v, OP_SortPut, 0, 0, 0, 0);
}else
- /* If we are writing to a table, then write the results to the table.
+ /* In this mode, write each query result to the key of the temporary
+ ** table iParm.
*/
- if( eDest==SRT_Table ){
- sqliteVdbeAddOp(v, OP_MakeRecord, pEList->nExpr, 0, 0, 0);
- sqliteVdbeAddOp(v, OP_New, iParm, 0, 0, 0);
- sqliteVdbeAddOp(v, OP_Pull, 1, 0, 0, 0);
+ if( eDest==SRT_Union ){
+ sqliteVdbeAddOp(v, OP_MakeRecord, nField, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_String, iParm, 0, "", 0);
+ sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0);
+ }else
+
+ /* Construct a record from the query result, but instead of
+ ** saving that record, use it as a key to delete elements from
+ ** the temporary table iParm.
+ */
+ if( eDest==SRT_Except ){
+ assert( pEList->nExpr==1 );
+ sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0);
}else
@@ -149,6 +176,7 @@
sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0);
}else
+
/* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out
** of the scan loop.
@@ -161,7 +189,160 @@
/* If none of the above, send the data to the callback function.
*/
{
- sqliteVdbeAddOp(v, OP_Callback, pEList->nExpr, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Callback, nField, 0, 0, 0);
+ }
+ return 0;
+}
+
+/*
+** Generate code that will tell the VDBE how many columns there
+** are in the result and the name for each column. This information
+** is used to provide "argc" and "azCol[]" values in the callback.
+*/
+static void generateColumnNames(Vdbe *v, IdList *pTabList, ExprList *pEList){
+ int i;
+ 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;
+ }
+ p = pEList->a[i].pExpr;
+ if( p->op!=TK_FIELD || pTabList==0 ){
+ 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);
+ 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);
+ }
+ }
+ }
+}
+
+/*
+** This routine is called to process a query that is really the union
+** or intersection of two or more separate queries.
+*/
+static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
+ int rc;
+ Select *pPrior;
+ Vdbe *v;
+ int i;
+
+ /* Make sure we have a valid query engine. If not, create a new one.
+ */
+ v = pParse->pVdbe;
+ if( v==0 ){
+ v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+ }
+ if( v==0 ){
+ sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
+ pParse->nErr++;
+ return 1;
+ }
+
+ assert( p->pPrior!=0 );
+ pPrior = p->pPrior;
+ switch( p->op ){
+ case TK_ALL: {
+ rc = sqliteSelect(pParse, pPrior, eDest, iParm);
+ if( rc ) return rc;
+ p->pPrior = 0;
+ rc = sqliteSelect(pParse, p, eDest, iParm);
+ p->pPrior = pPrior;
+ break;
+ }
+ case TK_EXCEPT:
+ case TK_UNION: {
+ int unionTab;
+ int op;
+
+ if( eDest==SRT_Union ){
+ unionTab = iParm;
+ }else{
+ unionTab = pParse->nTab++;
+ sqliteVdbeAddOp(v, OP_Open, unionTab, 1, 0, 0);
+ sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1, 0, 0);
+ }
+ rc = sqliteSelect(pParse, pPrior, SRT_Union, unionTab);
+ if( rc ) return rc;
+ op = p->op==TK_EXCEPT ? SRT_Except : SRT_Union;
+ p->pPrior = 0;
+ rc = sqliteSelect(pParse, p, op, unionTab);
+ p->pPrior = pPrior;
+ if( rc ) return rc;
+ if( eDest!=SRT_Union ){
+ int iCont, iBreak;
+ assert( p->pEList );
+ generateColumnNames(v, 0, p->pEList);
+ iBreak = sqliteVdbeMakeLabel(v);
+ iCont = sqliteVdbeAddOp(v, OP_Next, unionTab, iBreak, 0, 0);
+ rc = selectInnerLoop(pParse, 0, unionTab, p->pEList->nExpr,
+ 0, -1, eDest, iParm,
+ iCont, iBreak);
+ if( rc ) return 1;
+ sqliteVdbeAddOp(v, OP_Goto, 0, iCont, 0, 0);
+ sqliteVdbeAddOp(v, OP_Close, unionTab, 0, 0, iBreak);
+ }
+ break;
+ }
+ case TK_INTERSECT: {
+ int tab1, tab2;
+ Select *pPrior;
+ int iCont, iBreak;
+
+ tab1 = pParse->nTab++;
+ tab2 = pParse->nTab++;
+ sqliteVdbeAddOp(v, OP_Open, tab1, 1, 0, 0);
+ sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1, 0, 0);
+ rc = sqliteSelect(pParse, pPrior, SRT_Union, tab1);
+ if( rc ) return rc;
+ sqliteVdbeAddOp(v, OP_Open, tab2, 1, 0, 0);
+ sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1, 0, 0);
+ p->pPrior = 0;
+ rc = sqliteSelect(pParse, p, SRT_Union, tab2);
+ p->pPrior = pPrior;
+ if( rc ) return rc;
+ assert( p->pEList );
+ generateColumnNames(v, 0, p->pEList);
+ iBreak = sqliteVdbeMakeLabel(v);
+ iCont = sqliteVdbeAddOp(v, OP_Next, tab1, iBreak, 0, 0);
+ sqliteVdbeAddOp(v, OP_Key, tab1, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont, 0, 0);
+ rc = selectInnerLoop(pParse, 0, tab1, p->pEList->nExpr,
+ 0, -1, eDest, iParm,
+ iCont, iBreak);
+ if( rc ) return 1;
+ sqliteVdbeAddOp(v, OP_Goto, 0, iCont, 0, 0);
+ sqliteVdbeAddOp(v, OP_Close, tab2, 0, 0, iBreak);
+ sqliteVdbeAddOp(v, OP_Close, tab1, 0, 0, 0);
+ break;
+ }
+ }
+ assert( p->pEList && pPrior->pEList );
+ if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
+ sqliteSetString(&pParse->zErrMsg, "SELECTs have different numbers "
+ "of columns and therefore cannot be joined", 0);
+ pParse->nErr++;
+ return 1;
}
return 0;
}
@@ -180,7 +361,9 @@
**
** SRT_Set Store results as keys of a table with cursor iParm
**
-** SRT_Table Store results in a regular table with cursor iParm
+** SRT_Union Store results as a key in a temporary table iParm
+**
+** SRT_Except Remove results form the temporary talbe iParm.
**
** This routine returns the number of errors. If any errors are
** encountered, then an appropriate error message is left in
@@ -192,7 +375,7 @@
int sqliteSelect(
Parse *pParse, /* The parser context */
Select *p, /* The SELECT statement being coded. */
- int eDest, /* One of SRT_Callback, SRT_Mem, SRT_Set, SRT_Table */
+ int eDest, /* One of: SRT_Callback Mem Set Union Except */
int iParm /* Save result in this memory location, if >=0 */
){
int i, j;
@@ -208,6 +391,14 @@
int isDistinct; /* True if the DISTINCT keyword is present */
int distinct; /* Table to use for the distinct set */
+ /* If there is are a sequence of queries, do the earlier ones first.
+ */
+ if( p->pPrior ){
+ return multiSelect(pParse, p, eDest, iParm);
+ }
+
+ /* Make local copies of the parameters for this query.
+ */
pEList = p->pEList;
pTabList = p->pSrc;
pWhere = p->pWhere;
@@ -255,7 +446,7 @@
Expr *pExpr = sqliteExpr(TK_FIELD, 0, 0, 0);
pExpr->iTable = i + pParse->nTab;
pExpr->iField = j;
- pEList = sqliteExprListAppend(pEList, pExpr, 0);
+ p->pEList = pEList = sqliteExprListAppend(pEList, pExpr, 0);
}
}
}
@@ -388,40 +579,7 @@
** step is skipped if the output is going to a table or a memory cell.
*/
if( eDest==SRT_Callback ){
- 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;
- }
- 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);
- 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);
- }
- }
- }
+ generateColumnNames(v, pTabList, pEList);
}
/* Reset the aggregator
@@ -449,7 +607,7 @@
** aggregates
*/
if( !isAgg ){
- if( selectInnerLoop(pParse, pEList, pOrderBy, distinct, eDest, iParm,
+ if( selectInnerLoop(pParse, pEList, 0, 0, pOrderBy, distinct, eDest, iParm,
pWInfo->iContinue, pWInfo->iBreak) ){
return 1;
}
@@ -528,7 +686,7 @@
if( pHaving ){
sqliteExprIfFalse(pParse, pHaving, startagg);
}
- if( selectInnerLoop(pParse, pEList, pOrderBy, distinct, eDest, iParm,
+ if( selectInnerLoop(pParse, pEList, 0, 0, pOrderBy, distinct, eDest, iParm,
startagg, endagg) ){
return 1;
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 8b1f94f..ebe04df 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -23,7 +23,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.18 2000/06/06 17:27:05 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.19 2000/06/06 21:56:08 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
@@ -228,6 +228,8 @@
ExprList *pGroupBy; /* The GROUP BY clause */
Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY clause */
+ int op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
+ Select *pPrior; /* Prior select to which this one joins */
};
/*
@@ -235,8 +237,9 @@
*/
#define SRT_Callback 1 /* Invoke a callback with each row of result */
#define SRT_Mem 2 /* Store result in a memory cell */
-#define SRT_Set 3 /* Store result in a table for use with "IN" */
-#define SRT_Table 4 /* Store result in a regular table */
+#define SRT_Set 3 /* Store result as unique keys in a table */
+#define SRT_Union 5 /* Store result as keys in a table */
+#define SRT_Except 6 /* Remove result from a UNION table */
/*
** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")
diff --git a/src/tokenize.c b/src/tokenize.c
index b64e325..f750deb 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -27,7 +27,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
-** $Id: tokenize.c,v 1.7 2000/06/06 17:27:06 drh Exp $
+** $Id: tokenize.c,v 1.8 2000/06/06 21:56:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -65,6 +65,7 @@
{ "DESC", 0, TK_DESC, 0 },
{ "DISTINCT", 0, TK_DISTINCT, 0 },
{ "DROP", 0, TK_DROP, 0 },
+ { "EXCEPT", 0, TK_EXCEPT, 0 },
{ "EXPLAIN", 0, TK_EXPLAIN, 0 },
{ "FROM", 0, TK_FROM, 0 },
{ "GLOB", 0, TK_GLOB, 0 },
@@ -73,6 +74,7 @@
{ "IN", 0, TK_IN, 0 },
{ "INDEX", 0, TK_INDEX, 0 },
{ "INSERT", 0, TK_INSERT, 0 },
+ { "INTERSECT", 0, TK_INTERSECT, 0 },
{ "INTO", 0, TK_INTO, 0 },
{ "IS", 0, TK_IS, 0 },
{ "ISNULL", 0, TK_ISNULL, 0 },
@@ -88,6 +90,7 @@
{ "SELECT", 0, TK_SELECT, 0 },
{ "SET", 0, TK_SET, 0 },
{ "TABLE", 0, TK_TABLE, 0 },
+ { "UNION", 0, TK_UNION, 0 },
{ "UNIQUE", 0, TK_UNIQUE, 0 },
{ "UPDATE", 0, TK_UPDATE, 0 },
{ "USING", 0, TK_USING, 0 },
diff --git a/src/vdbe.c b/src/vdbe.c
index f159fef..6a9c1c7 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.22 2000/06/06 19:18:24 drh Exp $
+** $Id: vdbe.c,v 1.23 2000/06/06 21:56:08 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
@@ -60,6 +60,7 @@
struct VdbeTable {
DbbeTable *pTable; /* The table 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;
@@ -735,26 +736,26 @@
static char *zOpName[] = { 0,
"Open", "Close", "Fetch", "New",
"Put", "Distinct", "Found", "NotFound",
- "Delete", "Field", "Key", "Rewind",
- "Next", "Destroy", "Reorganize", "ResetIdx",
- "NextIdx", "PutIdx", "DeleteIdx", "MemLoad",
- "MemStore", "ListOpen", "ListWrite", "ListRewind",
- "ListRead", "ListClose", "SortOpen", "SortPut",
- "SortMakeRec", "SortMakeKey", "Sort", "SortNext",
- "SortKey", "SortCallback", "SortClose", "FileOpen",
- "FileRead", "FileField", "FileClose", "AggReset",
- "AggFocus", "AggIncr", "AggNext", "AggSet",
- "AggGet", "SetInsert", "SetFound", "SetNotFound",
- "SetClear", "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",
+ "Delete", "Field", "KeyAsData", "Key",
+ "Rewind", "Next", "Destroy", "Reorganize",
+ "ResetIdx", "NextIdx", "PutIdx", "DeleteIdx",
+ "MemLoad", "MemStore", "ListOpen", "ListWrite",
+ "ListRewind", "ListRead", "ListClose", "SortOpen",
+ "SortPut", "SortMakeRec", "SortMakeKey", "Sort",
+ "SortNext", "SortKey", "SortCallback", "SortClose",
+ "FileOpen", "FileRead", "FileField", "FileClose",
+ "AggReset", "AggFocus", "AggIncr", "AggNext",
+ "AggSet", "AggGet", "SetInsert", "SetFound",
+ "SetNotFound", "SetClear", "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",
};
/*
@@ -1882,6 +1883,22 @@
break;
}
+ /* Opcode: KeyAsData P1 P2 *
+ **
+ ** Turn the key-as-data mode for cursor P1 either on (if P2==1) or
+ ** off (if P2==0). In key-as-data mode, the OP_Fetch opcode pulls
+ ** data off of the key rather than the data. This is useful for
+ ** outer joins and stuff...
+ */
+ case OP_KeyAsData: {
+ int i = pOp->p1;
+ VdbeTable *pTab;
+ if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+ p->aTab[i].keyAsData = pOp->p2;
+ }
+ break;
+ }
+
/* Opcode: Field P1 P2 *
**
** Push onto the stack the value of the P2-th field from the
@@ -1903,17 +1920,32 @@
if( NeedStack(p, tos) ) goto no_mem;
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
- amt = sqliteDbbeDataLength(pTab);
- if( amt<=sizeof(int)*(p2+1) ){
- p->aStack[tos].flags = STK_Null;
- break;
+ if( p->aTab[i].keyAsData ){
+ amt = sqliteDbbeKeyLength(pTab);
+ if( amt<=sizeof(int)*(p2+1) ){
+ p->aStack[tos].flags = STK_Null;
+ break;
+ }
+ pAddr = (int*)sqliteDbbeReadKey(pTab, sizeof(int)*p2);
+ if( *pAddr==0 ){
+ p->aStack[tos].flags = STK_Null;
+ break;
+ }
+ z = sqliteDbbeReadKey(pTab, *pAddr);
+ }else{
+ amt = sqliteDbbeDataLength(pTab);
+ if( amt<=sizeof(int)*(p2+1) ){
+ p->aStack[tos].flags = STK_Null;
+ break;
+ }
+ pAddr = (int*)sqliteDbbeReadData(pTab, sizeof(int)*p2);
+ if( *pAddr==0 ){
+ p->aStack[tos].flags = STK_Null;
+ break;
+ }
+ z = sqliteDbbeReadData(pTab, *pAddr);
}
- pAddr = (int*)sqliteDbbeReadData(pTab, sizeof(int)*p2);
- if( *pAddr==0 ){
- p->aStack[tos].flags = STK_Null;
- break;
- }
- p->zStack[tos] = z = sqliteDbbeReadData(pTab, *pAddr);
+ p->zStack[tos] = z;
p->aStack[tos].n = strlen(z) + 1;
p->aStack[tos].flags = STK_Str;
}
diff --git a/src/vdbe.h b/src/vdbe.h
index ce2f973..35fa085 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.8 2000/06/06 01:50:44 drh Exp $
+** $Id: vdbe.h,v 1.9 2000/06/06 21:56:08 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -81,97 +81,98 @@
#define OP_NotFound 8
#define OP_Delete 9
#define OP_Field 10
-#define OP_Key 11
-#define OP_Rewind 12
-#define OP_Next 13
+#define OP_KeyAsData 11
+#define OP_Key 12
+#define OP_Rewind 13
+#define OP_Next 14
-#define OP_Destroy 14
-#define OP_Reorganize 15
+#define OP_Destroy 15
+#define OP_Reorganize 16
-#define OP_ResetIdx 16
-#define OP_NextIdx 17
-#define OP_PutIdx 18
-#define OP_DeleteIdx 19
+#define OP_ResetIdx 17
+#define OP_NextIdx 18
+#define OP_PutIdx 19
+#define OP_DeleteIdx 20
-#define OP_MemLoad 20
-#define OP_MemStore 21
+#define OP_MemLoad 21
+#define OP_MemStore 22
-#define OP_ListOpen 22
-#define OP_ListWrite 23
-#define OP_ListRewind 24
-#define OP_ListRead 25
-#define OP_ListClose 26
+#define OP_ListOpen 23
+#define OP_ListWrite 24
+#define OP_ListRewind 25
+#define OP_ListRead 26
+#define OP_ListClose 27
-#define OP_SortOpen 27
-#define OP_SortPut 28
-#define OP_SortMakeRec 29
-#define OP_SortMakeKey 30
-#define OP_Sort 31
-#define OP_SortNext 32
-#define OP_SortKey 33
-#define OP_SortCallback 34
-#define OP_SortClose 35
+#define OP_SortOpen 28
+#define OP_SortPut 29
+#define OP_SortMakeRec 30
+#define OP_SortMakeKey 31
+#define OP_Sort 32
+#define OP_SortNext 33
+#define OP_SortKey 34
+#define OP_SortCallback 35
+#define OP_SortClose 36
-#define OP_FileOpen 36
-#define OP_FileRead 37
-#define OP_FileField 38
-#define OP_FileClose 39
+#define OP_FileOpen 37
+#define OP_FileRead 38
+#define OP_FileField 39
+#define OP_FileClose 40
-#define OP_AggReset 40
-#define OP_AggFocus 41
-#define OP_AggIncr 42
-#define OP_AggNext 43
-#define OP_AggSet 44
-#define OP_AggGet 45
+#define OP_AggReset 41
+#define OP_AggFocus 42
+#define OP_AggIncr 43
+#define OP_AggNext 44
+#define OP_AggSet 45
+#define OP_AggGet 46
-#define OP_SetInsert 46
-#define OP_SetFound 47
-#define OP_SetNotFound 48
-#define OP_SetClear 49
+#define OP_SetInsert 47
+#define OP_SetFound 48
+#define OP_SetNotFound 49
+#define OP_SetClear 50
-#define OP_MakeRecord 50
-#define OP_MakeKey 51
+#define OP_MakeRecord 51
+#define OP_MakeKey 52
-#define OP_Goto 52
-#define OP_If 53
-#define OP_Halt 54
+#define OP_Goto 53
+#define OP_If 54
+#define OP_Halt 55
-#define OP_ColumnCount 55
-#define OP_ColumnName 56
-#define OP_Callback 57
+#define OP_ColumnCount 56
+#define OP_ColumnName 57
+#define OP_Callback 58
-#define OP_Integer 58
-#define OP_String 59
-#define OP_Null 60
-#define OP_Pop 61
-#define OP_Dup 62
-#define OP_Pull 63
+#define OP_Integer 59
+#define OP_String 60
+#define OP_Null 61
+#define OP_Pop 62
+#define OP_Dup 63
+#define OP_Pull 64
-#define OP_Add 64
-#define OP_AddImm 65
-#define OP_Subtract 66
-#define OP_Multiply 67
-#define OP_Divide 68
-#define OP_Min 69
-#define OP_Max 70
-#define OP_Like 71
-#define OP_Glob 72
-#define OP_Eq 73
-#define OP_Ne 74
-#define OP_Lt 75
-#define OP_Le 76
-#define OP_Gt 77
-#define OP_Ge 78
-#define OP_IsNull 79
-#define OP_NotNull 80
-#define OP_Negative 81
-#define OP_And 82
-#define OP_Or 83
-#define OP_Not 84
-#define OP_Concat 85
-#define OP_Noop 86
+#define OP_Add 65
+#define OP_AddImm 66
+#define OP_Subtract 67
+#define OP_Multiply 68
+#define OP_Divide 69
+#define OP_Min 70
+#define OP_Max 71
+#define OP_Like 72
+#define OP_Glob 73
+#define OP_Eq 74
+#define OP_Ne 75
+#define OP_Lt 76
+#define OP_Le 77
+#define OP_Gt 78
+#define OP_Ge 79
+#define OP_IsNull 80
+#define OP_NotNull 81
+#define OP_Negative 82
+#define OP_And 83
+#define OP_Or 84
+#define OP_Not 85
+#define OP_Concat 86
+#define OP_Noop 87
-#define OP_MAX 86
+#define OP_MAX 87
/*
** Prototypes for the VDBE interface. See comments on the implementation