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:
22
manifest
22
manifest
@@ -1,5 +1,5 @@
|
||||
C :-)\s(CVS\s61)
|
||||
D 2000-06-06T19:18:24
|
||||
C :-)\s(CVS\s62)
|
||||
D 2000-06-06T21:56:08
|
||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||
F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644
|
||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||
@@ -13,17 +13,17 @@ F src/delete.c 8c733bb82a1b84126116d03dcdccf433c0856f5d
|
||||
F src/expr.c d350fe393e1753aaa733a5d21f0830a23e547400
|
||||
F src/insert.c 5e69dd70c3f91cf5ec5090f39fd6cd8e135af9bf
|
||||
F src/main.c 93a7ad14bb5a82ad13ad59da23ef674a94b0c3d6
|
||||
F src/parse.y 210c888c052f3fde3def6ff1f402e4b4e8ba270d
|
||||
F src/select.c 5fd6fbd73f68f0baf1d53a73c4217f7862c37c0e
|
||||
F src/parse.y 8b632f4c4ff2f4400f15592ca9d8fda27d97d0c4
|
||||
F src/select.c db29a091b6a5a4e90e7a0afb5721910ccaa9e19d
|
||||
F src/shell.c 5fa24c0bb678782ffe9070128e3e160674f297eb
|
||||
F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268
|
||||
F src/sqliteInt.h 267f66d4a851e19adb0f9a3050a3acb62fc70cae
|
||||
F src/sqliteInt.h 3cca846df0a8b5f811cf4f8021303547cd8f21fd
|
||||
F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
|
||||
F src/tokenize.c 32f0579d4a7276b8e3bfd353cac034f67976aa82
|
||||
F src/tokenize.c 09373590cc3942aa4744eb431ac5b5ce31e7cfea
|
||||
F src/update.c 18746f920f989b3d19d96c08263c92584823cd35
|
||||
F src/util.c 33f9baa01e45394ef0cf85361a0e872987884315
|
||||
F src/vdbe.c 73c93464c40866f11156bc5b0f19baf6ec851e7a
|
||||
F src/vdbe.h 49e0f9c6742860e224cd81d1278059f5d029dfb6
|
||||
F src/vdbe.c 562b12a9bafc098c114ab5eaec1307d071b89fd3
|
||||
F src/vdbe.h 8f79f57c66ce1030f6371ff067b326d627a52c6d
|
||||
F src/where.c c9b90e7672f4662a83ef9a27a193020d69fe034c
|
||||
F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
|
||||
F test/copy.test 73c3783535db538c8ebd8fffb931376864fc3226
|
||||
@@ -50,7 +50,7 @@ F www/c_interface.tcl 9ac800854272db5fe439e07b7435b243a5422293
|
||||
F www/changes.tcl f5839fe8de7449d994c71a8e48ce8ea736bec7d1
|
||||
F www/index.tcl 0c63672bad5188327143ecd0a07c7c0741ff9823
|
||||
F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd
|
||||
P 4eca3bf64fd96303bee653b7e44fa7bbdfccbdfb
|
||||
R 361d483638ebf01832ee4fb64c6b45f1
|
||||
P 25984b4d3ce0f94fa98a159d840cc7bd4e8bc1ab
|
||||
R 390a7e6fa62aea4b8e4067014add32c4
|
||||
U drh
|
||||
Z a433e93955d8d7af421e38bc9064d041
|
||||
Z 9866a189debd27c7a4ca83d1442824ae
|
||||
|
@@ -1 +1 @@
|
||||
25984b4d3ce0f94fa98a159d840cc7bd4e8bc1ab
|
||||
f4d9089c5d69b16fee5feb49b02e524499e6328d
|
18
src/parse.y
18
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,8 +139,21 @@ cmd ::= select(X). {
|
||||
|
||||
%type select {Select*}
|
||||
%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). {
|
||||
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) ::= HAVING expr(X). {A = X;}
|
||||
|
||||
|
||||
cmd ::= DELETE FROM ID(X) where_opt(Y).
|
||||
{sqliteDeleteFrom(pParse, &X, Y);}
|
||||
|
||||
|
250
src/select.c
250
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 @@ Select *sqliteSelectNew(
|
||||
pNew->pHaving = pHaving;
|
||||
pNew->pOrderBy = pOrderBy;
|
||||
pNew->isDistinct = isDistinct;
|
||||
pNew->op = TK_SELECT;
|
||||
return pNew;
|
||||
}
|
||||
|
||||
@@ -58,12 +59,14 @@ Select *sqliteSelectNew(
|
||||
** 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 @@ void sqliteParseInfoReset(Parse *pParse){
|
||||
/*
|
||||
** 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,9 +106,16 @@ static int selectInnerLoop(
|
||||
|
||||
/* Pull the requested fields.
|
||||
*/
|
||||
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
|
||||
** of the processing for the current row.
|
||||
@@ -113,6 +129,7 @@ static int selectInnerLoop(
|
||||
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 @@ static int selectInnerLoop(
|
||||
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 @@ static int selectInnerLoop(
|
||||
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 @@ static int selectInnerLoop(
|
||||
/* 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 @@ static int selectInnerLoop(
|
||||
**
|
||||
** 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 @@ static int selectInnerLoop(
|
||||
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 sqliteSelect(
|
||||
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 @@ int sqliteSelect(
|
||||
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 @@ int sqliteSelect(
|
||||
** 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 @@ int sqliteSelect(
|
||||
** 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 @@ int sqliteSelect(
|
||||
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;
|
||||
}
|
||||
|
@@ -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 @@ struct Select {
|
||||
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 @@ struct Select {
|
||||
*/
|
||||
#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)")
|
||||
|
@@ -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 @@ static Keyword aKeywordTable[] = {
|
||||
{ "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 @@ static Keyword aKeywordTable[] = {
|
||||
{ "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 @@ static Keyword aKeywordTable[] = {
|
||||
{ "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 },
|
||||
|
76
src/vdbe.c
76
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 @@ typedef struct VdbeOp Op;
|
||||
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 @@ void sqliteVdbeDelete(Vdbe *p){
|
||||
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 @@ int sqliteVdbeExec(
|
||||
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,6 +1920,19 @@ int sqliteVdbeExec(
|
||||
|
||||
if( NeedStack(p, tos) ) goto no_mem;
|
||||
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
|
||||
if( p->aTab[i].keyAsData ){
|
||||
amt = sqliteDbbeKeyLength(pTab);
|
||||
if( 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;
|
||||
@@ -1913,7 +1943,9 @@ int sqliteVdbeExec(
|
||||
p->aStack[tos].flags = STK_Null;
|
||||
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].flags = STK_Str;
|
||||
}
|
||||
|
157
src/vdbe.h
157
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 @@ typedef struct VdbeOp VdbeOp;
|
||||
#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
|
||||
|
Reference in New Issue
Block a user