1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

:-) (CVS 62)

FossilOrigin-Name: f4d9089c5d69b16fee5feb49b02e524499e6328d
This commit is contained in:
drh
2000-06-06 21:56:07 +00:00
parent 6b922e545f
commit 82c3d6368d
8 changed files with 387 additions and 176 deletions

View File

@@ -1,5 +1,5 @@
C :-)\s(CVS\s61) C :-)\s(CVS\s62)
D 2000-06-06T19:18:24 D 2000-06-06T21:56:08
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644 F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@@ -13,17 +13,17 @@ F src/delete.c 8c733bb82a1b84126116d03dcdccf433c0856f5d
F src/expr.c d350fe393e1753aaa733a5d21f0830a23e547400 F src/expr.c d350fe393e1753aaa733a5d21f0830a23e547400
F src/insert.c 5e69dd70c3f91cf5ec5090f39fd6cd8e135af9bf F src/insert.c 5e69dd70c3f91cf5ec5090f39fd6cd8e135af9bf
F src/main.c 93a7ad14bb5a82ad13ad59da23ef674a94b0c3d6 F src/main.c 93a7ad14bb5a82ad13ad59da23ef674a94b0c3d6
F src/parse.y 210c888c052f3fde3def6ff1f402e4b4e8ba270d F src/parse.y 8b632f4c4ff2f4400f15592ca9d8fda27d97d0c4
F src/select.c 5fd6fbd73f68f0baf1d53a73c4217f7862c37c0e F src/select.c db29a091b6a5a4e90e7a0afb5721910ccaa9e19d
F src/shell.c 5fa24c0bb678782ffe9070128e3e160674f297eb F src/shell.c 5fa24c0bb678782ffe9070128e3e160674f297eb
F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268 F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268
F src/sqliteInt.h 267f66d4a851e19adb0f9a3050a3acb62fc70cae F src/sqliteInt.h 3cca846df0a8b5f811cf4f8021303547cd8f21fd
F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7 F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
F src/tokenize.c 32f0579d4a7276b8e3bfd353cac034f67976aa82 F src/tokenize.c 09373590cc3942aa4744eb431ac5b5ce31e7cfea
F src/update.c 18746f920f989b3d19d96c08263c92584823cd35 F src/update.c 18746f920f989b3d19d96c08263c92584823cd35
F src/util.c 33f9baa01e45394ef0cf85361a0e872987884315 F src/util.c 33f9baa01e45394ef0cf85361a0e872987884315
F src/vdbe.c 73c93464c40866f11156bc5b0f19baf6ec851e7a F src/vdbe.c 562b12a9bafc098c114ab5eaec1307d071b89fd3
F src/vdbe.h 49e0f9c6742860e224cd81d1278059f5d029dfb6 F src/vdbe.h 8f79f57c66ce1030f6371ff067b326d627a52c6d
F src/where.c c9b90e7672f4662a83ef9a27a193020d69fe034c F src/where.c c9b90e7672f4662a83ef9a27a193020d69fe034c
F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7 F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
F test/copy.test 73c3783535db538c8ebd8fffb931376864fc3226 F test/copy.test 73c3783535db538c8ebd8fffb931376864fc3226
@@ -50,7 +50,7 @@ F www/c_interface.tcl 9ac800854272db5fe439e07b7435b243a5422293
F www/changes.tcl f5839fe8de7449d994c71a8e48ce8ea736bec7d1 F www/changes.tcl f5839fe8de7449d994c71a8e48ce8ea736bec7d1
F www/index.tcl 0c63672bad5188327143ecd0a07c7c0741ff9823 F www/index.tcl 0c63672bad5188327143ecd0a07c7c0741ff9823
F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd
P 4eca3bf64fd96303bee653b7e44fa7bbdfccbdfb P 25984b4d3ce0f94fa98a159d840cc7bd4e8bc1ab
R 361d483638ebf01832ee4fb64c6b45f1 R 390a7e6fa62aea4b8e4067014add32c4
U drh U drh
Z a433e93955d8d7af421e38bc9064d041 Z 9866a189debd27c7a4ca83d1442824ae

View File

@@ -1 +1 @@
25984b4d3ce0f94fa98a159d840cc7bd4e8bc1ab f4d9089c5d69b16fee5feb49b02e524499e6328d

View File

@@ -26,7 +26,7 @@
** the parser. Lemon will also generate a header file containing ** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens. ** 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_prefix TK_
%token_type {Token} %token_type {Token}
@@ -139,8 +139,21 @@ cmd ::= select(X). {
%type select {Select*} %type select {Select*}
%destructor select {sqliteSelectDelete($$);} %destructor select {sqliteSelectDelete($$);}
%type oneselect {Select*}
%destructor oneselect {sqliteSelectDelete($$);}
select(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) 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). { groupby_opt(P) having_opt(Q) orderby_opt(Z). {
A = sqliteSelectNew(W,X,Y,P,Q,Z,D); A = sqliteSelectNew(W,X,Y,P,Q,Z,D);
} }
@@ -222,6 +235,7 @@ groupby_opt(A) ::= GROUP BY exprlist(X). {A = X;}
having_opt(A) ::= . {A = 0;} having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;} having_opt(A) ::= HAVING expr(X). {A = X;}
cmd ::= DELETE FROM ID(X) where_opt(Y). cmd ::= DELETE FROM ID(X) where_opt(Y).
{sqliteDeleteFrom(pParse, &X, Y);} {sqliteDeleteFrom(pParse, &X, Y);}

View File

@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle SELECT statements. ** 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" #include "sqliteInt.h"
@@ -51,6 +51,7 @@ Select *sqliteSelectNew(
pNew->pHaving = pHaving; pNew->pHaving = pHaving;
pNew->pOrderBy = pOrderBy; pNew->pOrderBy = pOrderBy;
pNew->isDistinct = isDistinct; pNew->isDistinct = isDistinct;
pNew->op = TK_SELECT;
return pNew; return pNew;
} }
@@ -58,12 +59,14 @@ Select *sqliteSelectNew(
** Delete the given Select structure and all of its substructures. ** Delete the given Select structure and all of its substructures.
*/ */
void sqliteSelectDelete(Select *p){ void sqliteSelectDelete(Select *p){
if( p==0 ) return;
sqliteExprListDelete(p->pEList); sqliteExprListDelete(p->pEList);
sqliteIdListDelete(p->pSrc); sqliteIdListDelete(p->pSrc);
sqliteExprDelete(p->pWhere); sqliteExprDelete(p->pWhere);
sqliteExprListDelete(p->pGroupBy); sqliteExprListDelete(p->pGroupBy);
sqliteExprDelete(p->pHaving); sqliteExprDelete(p->pHaving);
sqliteExprListDelete(p->pOrderBy); sqliteExprListDelete(p->pOrderBy);
sqliteSelectDelete(p->pPrior);
sqliteFree(p); sqliteFree(p);
} }
@@ -81,10 +84,16 @@ void sqliteParseInfoReset(Parse *pParse){
/* /*
** This routine generates the code for the inside of the inner loop ** This routine generates the code for the inside of the inner loop
** of a SELECT. ** 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( static int selectInnerLoop(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
ExprList *pEList, /* List of values being extracted */ 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 */ ExprList *pOrderBy, /* If not NULL, sort results using this key */
int distinct, /* If >=0, make sure results are distinct */ int distinct, /* If >=0, make sure results are distinct */
int eDest, /* How to dispose of the results */ int eDest, /* How to dispose of the results */
@@ -97,9 +106,16 @@ static int selectInnerLoop(
/* Pull the requested fields. /* Pull the requested fields.
*/ */
if( pEList ){
for(i=0; i<pEList->nExpr; i++){ for(i=0; i<pEList->nExpr; i++){
sqliteExprCode(pParse, pEList->a[i].pExpr); 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 /* If the current result is not distinct, skip the rest
** of the processing for the current row. ** of the processing for the current row.
@@ -113,6 +129,7 @@ static int selectInnerLoop(
sqliteVdbeAddOp(v, OP_String, 0, 0, "", lbl); sqliteVdbeAddOp(v, OP_String, 0, 0, "", lbl);
sqliteVdbeAddOp(v, OP_Put, distinct, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, distinct, 0, 0, 0);
} }
/* If there is an ORDER BY clause, then store the results /* If there is an ORDER BY clause, then store the results
** in a sorter. ** in a sorter.
*/ */
@@ -130,12 +147,22 @@ static int selectInnerLoop(
sqliteVdbeAddOp(v, OP_SortPut, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_SortPut, 0, 0, 0, 0);
}else }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 ){ if( eDest==SRT_Union ){
sqliteVdbeAddOp(v, OP_MakeRecord, pEList->nExpr, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeRecord, nField, 0, 0, 0);
sqliteVdbeAddOp(v, OP_New, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_String, iParm, 0, "", 0);
sqliteVdbeAddOp(v, OP_Pull, 1, 0, 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); sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0);
}else }else
@@ -149,6 +176,7 @@ static int selectInnerLoop(
sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0);
}else }else
/* If this is a scalar select that is part of an expression, then /* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out ** store the results in the appropriate memory cell and break out
** of the scan loop. ** of the scan loop.
@@ -161,7 +189,160 @@ static int selectInnerLoop(
/* If none of the above, send the data to the callback function. /* 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; return 0;
} }
@@ -180,7 +361,9 @@ static int selectInnerLoop(
** **
** SRT_Set Store results as keys of a table with cursor iParm ** 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 ** This routine returns the number of errors. If any errors are
** encountered, then an appropriate error message is left in ** encountered, then an appropriate error message is left in
@@ -192,7 +375,7 @@ static int selectInnerLoop(
int sqliteSelect( int sqliteSelect(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
Select *p, /* The SELECT statement being coded. */ 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 iParm /* Save result in this memory location, if >=0 */
){ ){
int i, j; int i, j;
@@ -208,6 +391,14 @@ int sqliteSelect(
int isDistinct; /* True if the DISTINCT keyword is present */ int isDistinct; /* True if the DISTINCT keyword is present */
int distinct; /* Table to use for the distinct set */ 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; pEList = p->pEList;
pTabList = p->pSrc; pTabList = p->pSrc;
pWhere = p->pWhere; pWhere = p->pWhere;
@@ -255,7 +446,7 @@ int sqliteSelect(
Expr *pExpr = sqliteExpr(TK_FIELD, 0, 0, 0); Expr *pExpr = sqliteExpr(TK_FIELD, 0, 0, 0);
pExpr->iTable = i + pParse->nTab; pExpr->iTable = i + pParse->nTab;
pExpr->iField = j; pExpr->iField = j;
pEList = sqliteExprListAppend(pEList, pExpr, 0); p->pEList = pEList = sqliteExprListAppend(pEList, pExpr, 0);
} }
} }
} }
@@ -388,40 +579,7 @@ int sqliteSelect(
** step is skipped if the output is going to a table or a memory cell. ** step is skipped if the output is going to a table or a memory cell.
*/ */
if( eDest==SRT_Callback ){ if( eDest==SRT_Callback ){
sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0, 0, 0); generateColumnNames(v, pTabList, pEList);
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);
}
}
}
} }
/* Reset the aggregator /* Reset the aggregator
@@ -449,7 +607,7 @@ int sqliteSelect(
** aggregates ** aggregates
*/ */
if( !isAgg ){ if( !isAgg ){
if( selectInnerLoop(pParse, pEList, pOrderBy, distinct, eDest, iParm, if( selectInnerLoop(pParse, pEList, 0, 0, pOrderBy, distinct, eDest, iParm,
pWInfo->iContinue, pWInfo->iBreak) ){ pWInfo->iContinue, pWInfo->iBreak) ){
return 1; return 1;
} }
@@ -528,7 +686,7 @@ int sqliteSelect(
if( pHaving ){ if( pHaving ){
sqliteExprIfFalse(pParse, pHaving, startagg); sqliteExprIfFalse(pParse, pHaving, startagg);
} }
if( selectInnerLoop(pParse, pEList, pOrderBy, distinct, eDest, iParm, if( selectInnerLoop(pParse, pEList, 0, 0, pOrderBy, distinct, eDest, iParm,
startagg, endagg) ){ startagg, endagg) ){
return 1; return 1;
} }

View File

@@ -23,7 +23,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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 "sqlite.h"
#include "dbbe.h" #include "dbbe.h"
@@ -228,6 +228,8 @@ struct Select {
ExprList *pGroupBy; /* The GROUP BY clause */ ExprList *pGroupBy; /* The GROUP BY clause */
Expr *pHaving; /* The HAVING clause */ Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY 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 @@ struct Select {
*/ */
#define SRT_Callback 1 /* Invoke a callback with each row of result */ #define SRT_Callback 1 /* Invoke a callback with each row of result */
#define SRT_Mem 2 /* Store result in a memory cell */ #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_Set 3 /* Store result as unique keys in a table */
#define SRT_Table 4 /* Store result in a regular 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)") ** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")

View File

@@ -27,7 +27,7 @@
** individual tokens and sends those tokens one-by-one over to the ** individual tokens and sends those tokens one-by-one over to the
** parser for analysis. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -65,6 +65,7 @@ static Keyword aKeywordTable[] = {
{ "DESC", 0, TK_DESC, 0 }, { "DESC", 0, TK_DESC, 0 },
{ "DISTINCT", 0, TK_DISTINCT, 0 }, { "DISTINCT", 0, TK_DISTINCT, 0 },
{ "DROP", 0, TK_DROP, 0 }, { "DROP", 0, TK_DROP, 0 },
{ "EXCEPT", 0, TK_EXCEPT, 0 },
{ "EXPLAIN", 0, TK_EXPLAIN, 0 }, { "EXPLAIN", 0, TK_EXPLAIN, 0 },
{ "FROM", 0, TK_FROM, 0 }, { "FROM", 0, TK_FROM, 0 },
{ "GLOB", 0, TK_GLOB, 0 }, { "GLOB", 0, TK_GLOB, 0 },
@@ -73,6 +74,7 @@ static Keyword aKeywordTable[] = {
{ "IN", 0, TK_IN, 0 }, { "IN", 0, TK_IN, 0 },
{ "INDEX", 0, TK_INDEX, 0 }, { "INDEX", 0, TK_INDEX, 0 },
{ "INSERT", 0, TK_INSERT, 0 }, { "INSERT", 0, TK_INSERT, 0 },
{ "INTERSECT", 0, TK_INTERSECT, 0 },
{ "INTO", 0, TK_INTO, 0 }, { "INTO", 0, TK_INTO, 0 },
{ "IS", 0, TK_IS, 0 }, { "IS", 0, TK_IS, 0 },
{ "ISNULL", 0, TK_ISNULL, 0 }, { "ISNULL", 0, TK_ISNULL, 0 },
@@ -88,6 +90,7 @@ static Keyword aKeywordTable[] = {
{ "SELECT", 0, TK_SELECT, 0 }, { "SELECT", 0, TK_SELECT, 0 },
{ "SET", 0, TK_SET, 0 }, { "SET", 0, TK_SET, 0 },
{ "TABLE", 0, TK_TABLE, 0 }, { "TABLE", 0, TK_TABLE, 0 },
{ "UNION", 0, TK_UNION, 0 },
{ "UNIQUE", 0, TK_UNIQUE, 0 }, { "UNIQUE", 0, TK_UNIQUE, 0 },
{ "UPDATE", 0, TK_UPDATE, 0 }, { "UPDATE", 0, TK_UPDATE, 0 },
{ "USING", 0, TK_USING, 0 }, { "USING", 0, TK_USING, 0 },

View File

@@ -41,7 +41,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** 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 "sqliteInt.h"
#include <unistd.h> #include <unistd.h>
@@ -60,6 +60,7 @@ typedef struct VdbeOp Op;
struct VdbeTable { struct VdbeTable {
DbbeTable *pTable; /* The table structure of the backend */ DbbeTable *pTable; /* The table structure of the backend */
int index; /* The next index to extract */ 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 VdbeTable VdbeTable;
@@ -735,26 +736,26 @@ void sqliteVdbeDelete(Vdbe *p){
static char *zOpName[] = { 0, static char *zOpName[] = { 0,
"Open", "Close", "Fetch", "New", "Open", "Close", "Fetch", "New",
"Put", "Distinct", "Found", "NotFound", "Put", "Distinct", "Found", "NotFound",
"Delete", "Field", "Key", "Rewind", "Delete", "Field", "KeyAsData", "Key",
"Next", "Destroy", "Reorganize", "ResetIdx", "Rewind", "Next", "Destroy", "Reorganize",
"NextIdx", "PutIdx", "DeleteIdx", "MemLoad", "ResetIdx", "NextIdx", "PutIdx", "DeleteIdx",
"MemStore", "ListOpen", "ListWrite", "ListRewind", "MemLoad", "MemStore", "ListOpen", "ListWrite",
"ListRead", "ListClose", "SortOpen", "SortPut", "ListRewind", "ListRead", "ListClose", "SortOpen",
"SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortPut", "SortMakeRec", "SortMakeKey", "Sort",
"SortKey", "SortCallback", "SortClose", "FileOpen", "SortNext", "SortKey", "SortCallback", "SortClose",
"FileRead", "FileField", "FileClose", "AggReset", "FileOpen", "FileRead", "FileField", "FileClose",
"AggFocus", "AggIncr", "AggNext", "AggSet", "AggReset", "AggFocus", "AggIncr", "AggNext",
"AggGet", "SetInsert", "SetFound", "SetNotFound", "AggSet", "AggGet", "SetInsert", "SetFound",
"SetClear", "MakeRecord", "MakeKey", "Goto", "SetNotFound", "SetClear", "MakeRecord", "MakeKey",
"If", "Halt", "ColumnCount", "ColumnName", "Goto", "If", "Halt", "ColumnCount",
"Callback", "Integer", "String", "Null", "ColumnName", "Callback", "Integer", "String",
"Pop", "Dup", "Pull", "Add", "Null", "Pop", "Dup", "Pull",
"AddImm", "Subtract", "Multiply", "Divide", "Add", "AddImm", "Subtract", "Multiply",
"Min", "Max", "Like", "Glob", "Divide", "Min", "Max", "Like",
"Eq", "Ne", "Lt", "Le", "Glob", "Eq", "Ne", "Lt",
"Gt", "Ge", "IsNull", "NotNull", "Le", "Gt", "Ge", "IsNull",
"Negative", "And", "Or", "Not", "NotNull", "Negative", "And", "Or",
"Concat", "Noop", "Not", "Concat", "Noop",
}; };
/* /*
@@ -1882,6 +1883,22 @@ int sqliteVdbeExec(
break; 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 * /* Opcode: Field P1 P2 *
** **
** Push onto the stack the value of the P2-th field from the ** Push onto the stack the value of the P2-th field from the
@@ -1903,6 +1920,19 @@ int sqliteVdbeExec(
if( NeedStack(p, tos) ) goto no_mem; if( NeedStack(p, tos) ) goto no_mem;
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){ if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
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); amt = sqliteDbbeDataLength(pTab);
if( amt<=sizeof(int)*(p2+1) ){ if( amt<=sizeof(int)*(p2+1) ){
p->aStack[tos].flags = STK_Null; p->aStack[tos].flags = STK_Null;
@@ -1913,7 +1943,9 @@ int sqliteVdbeExec(
p->aStack[tos].flags = STK_Null; p->aStack[tos].flags = STK_Null;
break; break;
} }
p->zStack[tos] = z = sqliteDbbeReadData(pTab, *pAddr); z = sqliteDbbeReadData(pTab, *pAddr);
}
p->zStack[tos] = z;
p->aStack[tos].n = strlen(z) + 1; p->aStack[tos].n = strlen(z) + 1;
p->aStack[tos].flags = STK_Str; p->aStack[tos].flags = STK_Str;
} }

View File

@@ -27,7 +27,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** 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_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@@ -81,97 +81,98 @@ typedef struct VdbeOp VdbeOp;
#define OP_NotFound 8 #define OP_NotFound 8
#define OP_Delete 9 #define OP_Delete 9
#define OP_Field 10 #define OP_Field 10
#define OP_Key 11 #define OP_KeyAsData 11
#define OP_Rewind 12 #define OP_Key 12
#define OP_Next 13 #define OP_Rewind 13
#define OP_Next 14
#define OP_Destroy 14 #define OP_Destroy 15
#define OP_Reorganize 15 #define OP_Reorganize 16
#define OP_ResetIdx 16 #define OP_ResetIdx 17
#define OP_NextIdx 17 #define OP_NextIdx 18
#define OP_PutIdx 18 #define OP_PutIdx 19
#define OP_DeleteIdx 19 #define OP_DeleteIdx 20
#define OP_MemLoad 20 #define OP_MemLoad 21
#define OP_MemStore 21 #define OP_MemStore 22
#define OP_ListOpen 22 #define OP_ListOpen 23
#define OP_ListWrite 23 #define OP_ListWrite 24
#define OP_ListRewind 24 #define OP_ListRewind 25
#define OP_ListRead 25 #define OP_ListRead 26
#define OP_ListClose 26 #define OP_ListClose 27
#define OP_SortOpen 27 #define OP_SortOpen 28
#define OP_SortPut 28 #define OP_SortPut 29
#define OP_SortMakeRec 29 #define OP_SortMakeRec 30
#define OP_SortMakeKey 30 #define OP_SortMakeKey 31
#define OP_Sort 31 #define OP_Sort 32
#define OP_SortNext 32 #define OP_SortNext 33
#define OP_SortKey 33 #define OP_SortKey 34
#define OP_SortCallback 34 #define OP_SortCallback 35
#define OP_SortClose 35 #define OP_SortClose 36
#define OP_FileOpen 36 #define OP_FileOpen 37
#define OP_FileRead 37 #define OP_FileRead 38
#define OP_FileField 38 #define OP_FileField 39
#define OP_FileClose 39 #define OP_FileClose 40
#define OP_AggReset 40 #define OP_AggReset 41
#define OP_AggFocus 41 #define OP_AggFocus 42
#define OP_AggIncr 42 #define OP_AggIncr 43
#define OP_AggNext 43 #define OP_AggNext 44
#define OP_AggSet 44 #define OP_AggSet 45
#define OP_AggGet 45 #define OP_AggGet 46
#define OP_SetInsert 46 #define OP_SetInsert 47
#define OP_SetFound 47 #define OP_SetFound 48
#define OP_SetNotFound 48 #define OP_SetNotFound 49
#define OP_SetClear 49 #define OP_SetClear 50
#define OP_MakeRecord 50 #define OP_MakeRecord 51
#define OP_MakeKey 51 #define OP_MakeKey 52
#define OP_Goto 52 #define OP_Goto 53
#define OP_If 53 #define OP_If 54
#define OP_Halt 54 #define OP_Halt 55
#define OP_ColumnCount 55 #define OP_ColumnCount 56
#define OP_ColumnName 56 #define OP_ColumnName 57
#define OP_Callback 57 #define OP_Callback 58
#define OP_Integer 58 #define OP_Integer 59
#define OP_String 59 #define OP_String 60
#define OP_Null 60 #define OP_Null 61
#define OP_Pop 61 #define OP_Pop 62
#define OP_Dup 62 #define OP_Dup 63
#define OP_Pull 63 #define OP_Pull 64
#define OP_Add 64 #define OP_Add 65
#define OP_AddImm 65 #define OP_AddImm 66
#define OP_Subtract 66 #define OP_Subtract 67
#define OP_Multiply 67 #define OP_Multiply 68
#define OP_Divide 68 #define OP_Divide 69
#define OP_Min 69 #define OP_Min 70
#define OP_Max 70 #define OP_Max 71
#define OP_Like 71 #define OP_Like 72
#define OP_Glob 72 #define OP_Glob 73
#define OP_Eq 73 #define OP_Eq 74
#define OP_Ne 74 #define OP_Ne 75
#define OP_Lt 75 #define OP_Lt 76
#define OP_Le 76 #define OP_Le 77
#define OP_Gt 77 #define OP_Gt 78
#define OP_Ge 78 #define OP_Ge 79
#define OP_IsNull 79 #define OP_IsNull 80
#define OP_NotNull 80 #define OP_NotNull 81
#define OP_Negative 81 #define OP_Negative 82
#define OP_And 82 #define OP_And 83
#define OP_Or 83 #define OP_Or 84
#define OP_Not 84 #define OP_Not 85
#define OP_Concat 85 #define OP_Concat 86
#define OP_Noop 86 #define OP_Noop 87
#define OP_MAX 86 #define OP_MAX 87
/* /*
** Prototypes for the VDBE interface. See comments on the implementation ** Prototypes for the VDBE interface. See comments on the implementation