mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
:-) (CVS 52)
FossilOrigin-Name: c02268bdf4c28edc2542ce0ca1ba24fd6b5058fa
This commit is contained in:
@@ -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 @@ void sqliteExprDelete(Expr *p){
|
||||
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);
|
||||
}
|
||||
|
||||
|
27
src/expr.c
27
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 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
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 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
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 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
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 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_SELECT: {
|
||||
sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iField, 0, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@@ -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 @@ void sqliteInsert(
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
@@ -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 @@ cmd ::= DROP TABLE id(X). {sqliteDropTable(pParse,&X);}
|
||||
// The select statement
|
||||
//
|
||||
cmd ::= select(X). {
|
||||
sqliteSelect(pParse, X, 0, 0);
|
||||
sqliteSelect(pParse, X, -1, -1);
|
||||
sqliteSelectDelete(X);
|
||||
}
|
||||
|
||||
@@ -311,6 +311,10 @@ expr(A) ::= expr(X) NOTNULL. {A = sqliteExpr(TK_NOTNULL, X, 0, 0);}
|
||||
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($$);}
|
||||
|
158
src/select.c
158
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 @@ void sqliteSelectDelete(Select *p){
|
||||
/*
|
||||
** 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 @@ void sqliteSelectDelete(Select *p){
|
||||
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 @@ int sqliteSelect(
|
||||
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 @@ int sqliteSelect(
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 @@ int sqliteSelect(
|
||||
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 @@ int sqliteSelect(
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 @@ int sqliteSelect(
|
||||
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 @@ int sqliteSelect(
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 @@ int sqliteSelect(
|
||||
/* 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 @@ int sqliteSelect(
|
||||
}
|
||||
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 @@ int sqliteSelect(
|
||||
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;
|
||||
}
|
||||
|
@@ -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 @@ struct Expr {
|
||||
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 @@ struct IdList {
|
||||
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 IdList {
|
||||
*/
|
||||
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 @@ struct Parse {
|
||||
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 sqliteIdListAddAlias(IdList*, Token*);
|
||||
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*);
|
||||
|
111
src/vdbe.c
111
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,10 +92,20 @@ struct Stack {
|
||||
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
|
||||
*/
|
||||
@@ -133,6 +143,8 @@ struct Vdbe {
|
||||
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 @@ static void Cleanup(Vdbe *p){
|
||||
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 @@ static char *zOpName[] = { 0,
|
||||
"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 @@ int sqliteVdbeExec(
|
||||
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: {
|
||||
|
117
src/vdbe.h
117
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 @@ typedef struct VdbeOp VdbeOp;
|
||||
#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
|
||||
|
60
src/where.c
60
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 @@ static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
|
||||
** 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 @@ static int exprTableUsage(Expr *p){
|
||||
** "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 @@ WhereInfo *sqliteWhereBegin(
|
||||
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 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
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 @@ WhereInfo *sqliteWhereBegin(
|
||||
/* 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 @@ WhereInfo *sqliteWhereBegin(
|
||||
/* 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 @@ WhereInfo *sqliteWhereBegin(
|
||||
/* 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 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
}
|
||||
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 @@ WhereInfo *sqliteWhereBegin(
|
||||
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 @@ WhereInfo *sqliteWhereBegin(
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user