diff --git a/manifest b/manifest index 28bcf84eba..1d1c1fcb90 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C :-)\s(CVS\s50) -D 2000-06-05T02:07:04 +C separate\sSelect\sstructure\s(CVS\s51) +D 2000-06-05T16:01:39 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 @@ -12,17 +12,17 @@ F src/dbbe.h a8a46f71238e0f09f3ec08fd9d1c8c7f4cdc49bf F src/delete.c e11433c14ed5cc8553cba14296b3baa3c23054bc F src/expr.c 793c15de4ce2911fa1a74999750bd3c0c9ca513f F src/insert.c ddae33b3dea1b4e743092d04240a20def9f88b72 -F src/main.c 06ee1dd1929b0a90e22a977c033e53c31cc012dd -F src/parse.y 9ec486608b7b4daaccf4ad9f05eef1a26a008fb8 -F src/select.c 2dff3d237db6588ad657bb13f19dedebc046a4eb +F src/main.c 93a7ad14bb5a82ad13ad59da23ef674a94b0c3d6 +F src/parse.y 020e5da71e14b63860c97589700eb11bf4699981 +F src/select.c 98f417b72e2edd277602cc14eb5c23743e616e60 F src/shell.c 5fa24c0bb678782ffe9070128e3e160674f297eb F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268 -F src/sqliteInt.h 7c269d229848045995782b10688acd59cbf08079 +F src/sqliteInt.h da8e0abf204438b812e315279acce05122166440 F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7 F src/tokenize.c 15c229fee77325334c6814652e429b0930eba6c1 F src/update.c 3f05d5082fd2c34f15d1e4a4db17355ad8807a78 -F src/util.c a06e8379665b18539cd9400641f3581d925f337e -F src/vdbe.c c101c98de98cb4f946bb003ca2e6347cdd218ebc +F src/util.c 33f9baa01e45394ef0cf85361a0e872987884315 +F src/vdbe.c 108f0e58beee1361bcb8dc2a59c7d54e5f4360bc F src/vdbe.h f20a3140905c385237e0891122beccde779c78c7 F src/where.c bed9a8360cbfbf712bdc397c8e22216a5e5f9800 F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7 @@ -47,7 +47,7 @@ F www/c_interface.tcl 8867d76ddd416d2fbd41e4cb3de8efa9cef105a5 F www/changes.tcl 567cc6066d87460bdedff8e5bbc20f41ddaadf77 F www/index.tcl f8189a7898f6d06307c34047b9d7e00860026e44 F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd -P 6ea5cebf05562de00d2cf0b9e2aac5f3857638ee -R 6949f362a1592f0e27ca1ae669f63813 +P 1cf2873d55b471bb3e397f90dc0868dd88c440a0 +R dfbce0b035783f6473b57dede04bcdd9 U drh -Z aae59671b659273e5022be83deddccc9 +Z 4195201472d7632b2259e7fe18f40c66 diff --git a/manifest.uuid b/manifest.uuid index d97df18fa6..b3958a948e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1cf2873d55b471bb3e397f90dc0868dd88c440a0 \ No newline at end of file +ce45dea902f9010a1c2c9ba3550dd789e7c15fcd \ No newline at end of file diff --git a/src/main.c b/src/main.c index aeb75e3cff..317c08ce61 100644 --- a/src/main.c +++ b/src/main.c @@ -26,7 +26,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.8 2000/06/05 02:07:04 drh Exp $ +** $Id: main.c,v 1.9 2000/06/05 16:01:39 drh Exp $ */ #include "sqliteInt.h" @@ -40,7 +40,6 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){ sqlite *db = (sqlite*)pDb; Parse sParse; int nErr; - char *zErrMsg = 0; if( argc!=1 ) return 0; memset(&sParse, 0, sizeof(sParse)); diff --git a/src/parse.y b/src/parse.y index 69be1485dc..001b03d0bc 100644 --- a/src/parse.y +++ b/src/parse.y @@ -26,7 +26,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.8 2000/06/03 19:19:41 drh Exp $ +** @(#) $Id: parse.y,v 1.9 2000/06/05 16:01:39 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -132,28 +132,44 @@ cmd ::= DROP TABLE id(X). {sqliteDropTable(pParse,&X);} // The select statement // -cmd ::= select. -select ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) orderby_opt(Z). - {sqliteSelect(pParse, W, X, Y, Z, D);} -select ::= SELECT distinct(D) STAR from(X) where_opt(Y) orderby_opt(Z). - {sqliteSelect(pParse, 0, X, Y, Z, D);} +cmd ::= select(X). { + sqliteSelect(pParse, X, 0, 0); + sqliteSelectDelete(X); +} +%type select {Select*} +%destructor select {sqliteSelectDelete($$);} + +select(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) + orderby_opt(Z). { + A = sqliteSelectNew(W,X,Y,0,0,Z,D); +} + +// The "distinct" nonterminal is true (1) if the DISTINCT keyword is +// present and false (0) if it is not. +// %type distinct {int} - distinct(A) ::= DISTINCT. {A = 1;} distinct(A) ::= . {A = 0;} +// selcollist is a list of expressions that are to become the return +// values of the SELECT statement. In the case of "SELECT * FROM ..." +// the selcollist value is NULL. +// %type selcollist {ExprList*} %destructor selcollist {sqliteExprListDelete($$);} %type sclp {ExprList*} %destructor sclp {sqliteExprListDelete($$);} - sclp(A) ::= selcollist(X) COMMA. {A = X;} sclp(A) ::= . {A = 0;} +selcollist(A) ::= STAR. {A = 0;} selcollist(A) ::= sclp(P) expr(X). {A = sqliteExprListAppend(P,X,0);} -selcollist(A) ::= sclp(P) expr(X) AS ID(Y). {A = sqliteExprListAppend(P,X,&Y);} -selcollist(A) ::= sclp(P) expr(X) AS STRING(Y). +selcollist(A) ::= sclp(P) expr(X) as ID(Y). {A = sqliteExprListAppend(P,X,&Y);} +selcollist(A) ::= sclp(P) expr(X) as STRING(Y). {A = sqliteExprListAppend(P,X,&Y);} +as ::= . +as ::= AS. + %type seltablist {IdList*} %destructor seltablist {sqliteIdListDelete($$);} @@ -179,16 +195,14 @@ seltablist(A) ::= stl_prefix(X) id(Y) AS id(Z). orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} -sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). - { - A = sqliteExprListAppend(X,Y,0); - A->a[A->nExpr-1].idx = Z; - } -sortlist(A) ::= sortitem(Y) sortorder(Z). - { - A = sqliteExprListAppend(0,Y,0); - A->a[0].idx = Z; - } +sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). { + A = sqliteExprListAppend(X,Y,0); + A->a[A->nExpr-1].idx = Z; /* 0 for ascending order, 1 for decending */ +} +sortlist(A) ::= sortitem(Y) sortorder(Z). { + A = sqliteExprListAppend(0,Y,0); + A->a[0].idx = Z; +} sortitem(A) ::= expr(X). {A = X;} %type sortorder {int} diff --git a/src/select.c b/src/select.c index 82001ea18f..e1f94891ec 100644 --- a/src/select.c +++ b/src/select.c @@ -24,28 +24,94 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements. ** -** $Id: select.c,v 1.6 2000/06/04 12:58:38 drh Exp $ +** $Id: select.c,v 1.7 2000/06/05 16:01:39 drh Exp $ */ #include "sqliteInt.h" /* -** Process a SELECT statement. +** Allocate a new Select structure and return a pointer to that +** structure. */ -void sqliteSelect( +Select *sqliteSelectNew( + ExprList *pEList, + IdList *pSrc, + Expr *pWhere, + ExprList *pGroupBy, + Expr *pHaving, + ExprList *pOrderBy, + int isDistinct +){ + Select *pNew; + pNew = sqliteMalloc( sizeof(*pNew) ); + if( pNew==0 ) return 0; + pNew->pEList = pEList; + pNew->pSrc = pSrc; + pNew->pWhere = pWhere; + pNew->pGroupBy = pGroupBy; + pNew->pHaving = pHaving; + pNew->pOrderBy = pOrderBy; + pNew->isDistinct = isDistinct; + return pNew; +} + +/* +** Delete the given Select structure and all of its substructures. +*/ +void sqliteSelectDelete(Select *p){ + sqliteExprListDelete(p->pEList); + sqliteIdListDelete(p->pSrc); + sqliteExprDelete(p->pWhere); + sqliteExprListDelete(p->pGroupBy); + sqliteExprDelete(p->pHaving); + sqliteExprListDelete(p->pOrderBy); + sqliteFree(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. +** +** This routine returns the number of errors. If any errors are +** encountered, then an appropriate error message is left in +** pParse->zErrMsg. +** +** This routine does NOT free the Select structure passed in. The +** calling function needs to do that. +*/ +int sqliteSelect( Parse *pParse, /* The parser context */ - ExprList *pEList, /* List of fields to extract. NULL means "*" */ - 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 */ + Select *p, /* The SELECT statement being coded. */ + Table *pDest, /* Write results here, if not NULL */ + int iMem /* Save result in this memory location, if >=0 */ ){ int i, j; WhereInfo *pWInfo; Vdbe *v; int isAgg = 0; /* True for select lists like "count(*)" */ + ExprList *pEList; /* List of fields to extract. NULL means "*" */ + 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 */ - if( pParse->nErr>0 ) goto select_cleanup; + + pEList = p->pEList; + pTabList = p->pSrc; + pWhere = p->pWhere; + pOrderBy = p->pOrderBy; + distinct = p->isDistinct; + + /* + ** Do not even attempt to generate any code if we have already seen + ** errors before this routine starts. + */ + if( pParse->nErr>0 ) return 0; /* Look up every table in the table list. */ @@ -55,7 +121,7 @@ void sqliteSelect( sqliteSetString(&pParse->zErrMsg, "no such table: ", pTabList->a[i].zName, 0); pParse->nErr++; - goto select_cleanup; + return 1; } } @@ -78,10 +144,10 @@ void sqliteSelect( */ for(i=0; inExpr; i++){ if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){ - goto select_cleanup; + return 1; } if( sqliteExprCheck(pParse, pEList->a[i].pExpr, 1, &pEList->a[i].isAgg) ){ - goto select_cleanup; + return 1; } } if( pEList->nExpr>0 ){ @@ -91,25 +157,25 @@ void sqliteSelect( sqliteSetString(&pParse->zErrMsg, "some selected items are aggregates " "and others are not", 0); pParse->nErr++; - goto select_cleanup; + return 1; } } } if( pWhere ){ if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){ - goto select_cleanup; + return 1; } if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ - goto select_cleanup; + return 1; } } if( pOrderBy ){ for(i=0; inExpr; i++){ if( sqliteExprResolveIds(pParse, pTabList, pOrderBy->a[i].pExpr) ){ - goto select_cleanup; + return 1; } if( sqliteExprCheck(pParse, pOrderBy->a[i].pExpr, 0, 0) ){ - goto select_cleanup; + return 1; } } } @@ -118,7 +184,6 @@ void sqliteSelect( ** since only one row will be returned. */ if( isAgg && pOrderBy ){ - sqliteExprListDelete(pOrderBy); pOrderBy = 0; } @@ -134,7 +199,11 @@ void sqliteSelect( if( v==0 ){ v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe); } - if( v==0 ) goto select_cleanup; + if( v==0 ){ + sqliteSetString(&pParse->zErrMsg, "out of memory", 0); + pParse->nErr++; + return 1; + } if( pOrderBy ){ sqliteVdbeAddOp(v, OP_SortOpen, 0, 0, 0, 0); } @@ -201,7 +270,7 @@ void sqliteSelect( sqliteVdbeAddOp(v, OP_Open, distinct, 1, 0, 0); } pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0); - if( pWInfo==0 ) goto select_cleanup; + if( pWInfo==0 ) return 1; /* Pull the requested fields. */ @@ -232,7 +301,7 @@ void sqliteSelect( char *zSortOrder; sqliteVdbeAddOp(v, OP_SortMakeRec, pEList->nExpr, 0, 0, 0); zSortOrder = sqliteMalloc( pOrderBy->nExpr + 1 ); - if( zSortOrder==0 ) goto select_cleanup; + if( zSortOrder==0 ) return 1; for(i=0; inExpr; i++){ zSortOrder[i] = pOrderBy->a[i].idx ? '-' : '+'; sqliteExprCode(pParse, pOrderBy->a[i].pExpr); @@ -288,14 +357,5 @@ void sqliteSelect( if( isAgg ){ sqliteVdbeAddOp(v, OP_Callback, pEList->nExpr, 0, 0, 0); } - - /* Always execute the following code before exiting, in order to - ** release resources. - */ -select_cleanup: - sqliteExprListDelete(pEList); - sqliteIdListDelete(pTabList); - sqliteExprDelete(pWhere); - sqliteExprListDelete(pOrderBy); - return; + return 0; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 48f3895f3a..a0a6f319d0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -23,7 +23,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.13 2000/06/05 02:07:04 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.14 2000/06/05 16:01:39 drh Exp $ */ #include "sqlite.h" #include "dbbe.h" @@ -35,7 +35,7 @@ #include #include -/* #define MEMORY_DEBUG 1 */ +#define MEMORY_DEBUG 1 #ifdef MEMORY_DEBUG # define sqliteMalloc(X) sqliteMalloc_(X,__FILE__,__LINE__) # define sqliteFree(X) sqliteFree_(X,__FILE__,__LINE__) @@ -87,6 +87,7 @@ typedef struct Parse Parse; typedef struct Token Token; typedef struct IdList IdList; typedef struct WhereInfo WhereInfo; +typedef struct Select Select; /* ** Each database is an instance of the following structure @@ -208,6 +209,20 @@ struct WhereInfo { int iBreak; }; +/* +** An instance of the following structure contains all information +** needed to generate code for a single SELECT statement. +*/ +struct Select { + int isDistinct; /* True if the DISTINCT keyword is present */ + ExprList *pEList; /* The fields of the result */ + IdList *pSrc; /* The FROM clause */ + Expr *pWhere; /* The WHERE clause */ + ExprList *pGroupBy; /* The GROUP BY clause */ + Expr *pHaving; /* The HAVING clause */ + ExprList *pOrderBy; /* The ORDER BY clause */ +}; + /* ** An SQL parser context */ @@ -266,7 +281,9 @@ void sqliteIdListAddAlias(IdList*, Token*); void sqliteIdListDelete(IdList*); void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, Token*, Token*); void sqliteDropIndex(Parse*, Token*); -void sqliteSelect(Parse*, ExprList*, IdList*, Expr*, ExprList*, int); +int sqliteSelect(Parse*, Select*, Table*, int); +Select *sqliteSelectNew(ExprList*,IdList*,Expr*,ExprList*,Expr*,ExprList*,int); +void sqliteSelectDelete(Select*); void sqliteDeleteFrom(Parse*, Token*, Expr*); void sqliteUpdate(Parse*, Token*, ExprList*, Expr*); WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int); diff --git a/src/util.c b/src/util.c index 1142a60e9a..b3e0d7760c 100644 --- a/src/util.c +++ b/src/util.c @@ -26,7 +26,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.10 2000/06/04 12:58:38 drh Exp $ +** $Id: util.c,v 1.11 2000/06/05 16:01:39 drh Exp $ */ #include "sqliteInt.h" #include @@ -102,13 +102,13 @@ void *sqliteRealloc_(void *oldP, int n, char *zFile, int line){ oldPi -= 2; if( oldPi[0]!=0xdead1122 ){ fprintf(stderr,"Low-end memory corruption in realloc at 0x%x\n", (int)p); - return; + return 0; } oldN = oldPi[1]; oldK = (oldN+sizeof(int)-1)/sizeof(int); if( oldPi[oldK+2]!=0xdead3344 ){ fprintf(stderr,"High-end memory corruption in realloc at 0x%x\n", (int)p); - return; + return 0; } k = (n + sizeof(int) - 1)/sizeof(int); pi = malloc( (k+3)*sizeof(int) ); diff --git a/src/vdbe.c b/src/vdbe.c index 53a4e01921..d302a031b6 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -41,9 +41,10 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.14 2000/06/05 02:07:04 drh Exp $ +** $Id: vdbe.c,v 1.15 2000/06/05 16:01:39 drh Exp $ */ #include "sqliteInt.h" +#include /* ** SQL is translated into a sequence of instructions to be @@ -741,7 +742,6 @@ int sqliteVdbeExec( */ case OP_Null: { int i = ++p->tos; - char *z; if( NeedStack(p, p->tos) ) goto no_mem; p->zStack[i] = 0; p->aStack[i].flags = STK_Null;