Code to implement CREATE VIEW is in place. A quick smoke test shows that

it works, but there are probably still many bugs. (CVS 387)

FossilOrigin-Name: 39fed2df11382b9855d518502a6c2ca200fa66b8
This commit is contained in:
drh 2002-02-23 02:32:10 +00:00
parent 17f7193434
commit a76b5dfca6
12 changed files with 357 additions and 204 deletions

View File

@ -1,5 +1,5 @@
C Change\sthe\sSQLITE_MASTER\sformat\sto\sversion\s2\sin\spreparation\sfor\sadding\sviews.\s(CVS\s386)
D 2002-02-21T12:01:27
C Code\sto\simplement\sCREATE\sVIEW\sis\sin\splace.\s\sA\squick\ssmoke\stest\sshows\sthat\nit\sworks,\sbut\sthere\sare\sprobably\sstill\smany\sbugs.\s(CVS\s387)
D 2002-02-23T02:32:10
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@ -21,38 +21,38 @@ F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 495275fe14f3b718cf2f691dce979d4c0e1f8e5d
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
F src/build.c 4e10d8e61971fe900317d00a98f49dd7ceb27c20
F src/delete.c f8ad71be53cf18656b6573de65395852fe817f0c
F src/expr.c 7aff65ea0732b07d36925087ad611019103ad69a
F src/build.c 1da051784be0155ae579d47890db74f0186f9b9f
F src/delete.c 950d8f9097361419f1963875f9943344b469cf02
F src/expr.c 6b641c43941094a5d1f7a96657d8a34d07188856
F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
F src/hash.h d1ce47900c7325af5e41c4feb4855c4bf2b841e7
F src/insert.c eae5aa2e9ac68c4d465e71b2ad34bcbb882979cf
F src/insert.c 164d2d5e943268a8ff0594e1947599e04df0ce11
F src/main.c abc0732d4caa676ff8337f278b01f1f1b57538f5
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/os.c f6bc9b7ab530346bb7fef2ed39f2f1f214bc14ea
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
F src/pager.c 9761c79ccb844bf29ffc5cbed4fa1a32e0740147
F src/pager.h b28f004e2f5541dc60cc32db01bf80cf4d056283
F src/parse.y b82278917959eefd05bd08c90e07a4fa5917ea51
F src/parse.y fc460cda6f475beae963c7f9c737cf13f44f3420
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c f0cbfd2d9059e0f33837797ee326fbe964a35f09
F src/select.c 61d4a739956aaeb124cdf12c34c66e99ae34212c
F src/shell.c cbf48bf0ca35c4e0d8a7d2a86f7724f52c525cd7
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
F src/sqliteInt.h 338cd586b9322105080a2a31122446e504ac1fc4
F src/sqliteInt.h 81dcdf77391471443d53e4b96ac5e78a10e9df4b
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
F src/test2.c d410dbd8a90faa466c3ab694fa0aa57f5a773aa6
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
F src/tokenize.c 777b734f9d06f5a9055b6808e5baec18936a4fd9
F src/update.c 95459f94a061860bf8e5716b3426a5ba85c79103
F src/tokenize.c 4b5d30590a744b9bb5605a92d1f620ab2e7e75af
F src/update.c 18971d265b0341574b7e3f73116e7947ddab0997
F src/util.c f31f3d6198a0d1296a16f5a6ceec423a932cbbf6
F src/vdbe.c 44832d804e109248e9e2abd40daee5f8ac735450
F src/vdbe.h 002bb8cf884034bea25a9fe901a9c5e9d29bc045
F src/where.c f79bc3179379b46b131a67ab10713779368dceee
F src/where.c 664be01b0ce9ffaecbde609afbd4d8d3e5ed1585
F test/all.test 7a8a8a7a579ed2bb4d8976d55402f21eacd58049
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
@ -125,7 +125,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P ffb00bf36a9a5851ea4a69f9c7dd7ce412553e3b
R 827e990a5d306ede002baf12f96964e4
P b2a9807fed544e83002366149b9a363759338c5d
R e0b567ef590e442398fe19c801c19dbc
U drh
Z 93dfb9234ed5554b3f3a0a3a7b0ddf3a
Z 84f7f5c8e0889cae09918887440ad98b

View File

@ -1 +1 @@
b2a9807fed544e83002366149b9a363759338c5d
39fed2df11382b9855d518502a6c2ca200fa66b8

View File

@ -25,7 +25,7 @@
** ROLLBACK
** PRAGMA
**
** $Id: build.c,v 1.78 2002/02/21 12:01:27 drh Exp $
** $Id: build.c,v 1.79 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -64,75 +64,12 @@ void sqliteExec(Parse *pParse){
}
}
/*
** Construct a new expression node and return a pointer to it. Memory
** for this node is obtained from sqliteMalloc(). The calling function
** is responsible for making sure the node eventually gets freed.
*/
Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
Expr *pNew;
pNew = sqliteMalloc( sizeof(Expr) );
if( pNew==0 ){
sqliteExprDelete(pLeft);
sqliteExprDelete(pRight);
return 0;
}
pNew->op = op;
pNew->pLeft = pLeft;
pNew->pRight = pRight;
if( pToken ){
pNew->token = *pToken;
}else{
pNew->token.z = "";
pNew->token.n = 0;
}
if( pLeft && pRight ){
sqliteExprSpan(pNew, &pLeft->span, &pRight->span);
}else{
pNew->span = pNew->token;
}
return pNew;
}
/*
** Set the Expr.token field of the given expression to span all
** text between the two given tokens.
*/
void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
if( pExpr ){
pExpr->span.z = pLeft->z;
pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z);
}
}
/*
** Construct a new expression node for a function with multiple
** arguments.
*/
Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
Expr *pNew;
pNew = sqliteMalloc( sizeof(Expr) );
if( pNew==0 ){
sqliteExprListDelete(pList);
return 0;
}
pNew->op = TK_FUNCTION;
pNew->pList = pList;
if( pToken ){
pNew->token = *pToken;
}else{
pNew->token.z = "";
pNew->token.n = 0;
}
return pNew;
}
/*
** Locate the in-memory structure that describes
** a particular database table given the name
** of that table. Return NULL if not found.
*/
Table *sqliteFindTable(sqlite *db, char *zName){
Table *sqliteFindTable(sqlite *db, const char *zName){
Table *p = sqliteHashFind(&db->tblHash, zName, strlen(zName)+1);
return p;
}
@ -142,7 +79,7 @@ Table *sqliteFindTable(sqlite *db, char *zName){
** a particular index given the name of that index.
** Return NULL if not found.
*/
Index *sqliteFindIndex(sqlite *db, char *zName){
Index *sqliteFindIndex(sqlite *db, const char *zName){
Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1);
return p;
}
@ -235,6 +172,7 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
}
sqliteFree(pTable->zName);
sqliteFree(pTable->aCol);
sqliteSelectDelete(pTable->pSelect);
sqliteFree(pTable);
}
@ -859,6 +797,51 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
}
}
/*
** The parser calls this routine in order to create a new VIEW
*/
void sqliteCreateView(
Parse *pParse, /* The parsing context */
Token *pBegin, /* The CREATE token that begins the statement */
Token *pName, /* The token that holds the name of the view */
Select *pSelect /* A SELECT statement that will become the new view */
){
Token sEnd;
Table *pSelTab;
Table *p;
char *z;
int n, offset;
sqliteStartTable(pParse, pBegin, pName, 0);
p = pParse->pNewTable;
if( p==0 ) goto create_view_failed;
p->pSelect = pSelect;
pSelTab = sqliteResultSetOfSelect(pParse, 0, pSelect);
if( pSelTab==0 ) goto create_view_failed;
assert( p->aCol==0 );
p->nCol = pSelTab->nCol;
p->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
sqliteDeleteTable(0, pSelTab);
sEnd = pParse->sLastToken;
if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){
sEnd.z += sEnd.n;
}
sEnd.n = 0;
n = ((int)sEnd.z) - (int)pBegin->z;
z = p->pSelect->zSelect = sqliteStrNDup(pBegin->z, n+1);
if( z==0 ) goto create_view_failed;
offset = ((int)z) - (int)pBegin->z;
sqliteSelectMoveStrings(p->pSelect, offset);
sqliteEndTable(pParse, &sEnd, 0);
return;
create_view_failed:
sqliteSelectDelete(pSelect);
return;
}
/*
** Given a token, look up a table with that name. If not found, leave
** an error for the parser to find and return NULL.
@ -993,6 +976,11 @@ void sqliteCreateIndex(
pParse->nErr++;
goto exit_create_index;
}
if( pTab->pSelect ){
sqliteSetString(&pParse->zErrMsg, "views may not be indexed", 0);
pParse->nErr++;
goto exit_create_index;
}
/* If this index is created while re-reading the schema from sqlite_master
** but the table associated with this index is a temporary table, it can
@ -1298,55 +1286,6 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
}
}
/*
** Add a new element to the end of an expression list. If pList is
** initially NULL, then create a new expression list.
*/
ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
int i;
if( pList==0 ){
pList = sqliteMalloc( sizeof(ExprList) );
if( pList==0 ){
sqliteExprDelete(pExpr);
return 0;
}
}
if( (pList->nExpr & 7)==0 ){
int n = pList->nExpr + 8;
struct ExprList_item *a;
a = sqliteRealloc(pList->a, n*sizeof(pList->a[0]));
if( a==0 ){
sqliteExprDelete(pExpr);
return pList;
}
pList->a = a;
}
if( pExpr || pName ){
i = pList->nExpr++;
pList->a[i].pExpr = pExpr;
pList->a[i].zName = 0;
if( pName ){
sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0);
sqliteDequote(pList->a[i].zName);
}
}
return pList;
}
/*
** Delete an entire expression list.
*/
void sqliteExprListDelete(ExprList *pList){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){
sqliteExprDelete(pList->a[i].pExpr);
sqliteFree(pList->a[i].zName);
}
sqliteFree(pList->a);
sqliteFree(pList);
}
/*
** Append a new element to the given IdList. Create a new IdList if
** need be.
@ -1394,7 +1333,7 @@ void sqliteIdListAddAlias(IdList *pList, Token *pToken){
}
/*
** Delete an entire IdList
** Delete an entire IdList.
*/
void sqliteIdListDelete(IdList *pList){
int i;
@ -1402,8 +1341,13 @@ void sqliteIdListDelete(IdList *pList){
for(i=0; i<pList->nId; i++){
sqliteFree(pList->a[i].zName);
sqliteFree(pList->a[i].zAlias);
if( pList->a[i].pSelect ){
sqliteFree(pList->a[i].zName);
/* If the pSelect field is set and is not pointing to the Select
** structure that defines a VIEW, then the Select is for a subquery
** and should be deleted. Do not delete VIEWs, however.
*/
if( pList->a[i].pSelect &&
(pList->a[i].pTab==0 || pList->a[i].pTab->pSelect==0) ){
sqliteSelectDelete(pList->a[i].pSelect);
sqliteDeleteTable(0, pList->a[i].pTab);
}

View File

@ -12,10 +12,59 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.26 2002/01/31 15:54:22 drh Exp $
** $Id: delete.c,v 1.27 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"
/*
** Given a table name, find the corresponding table and make sure the
** table is writeable. Generate an error and return NULL if not. If
** everything checks out, return a pointer to the Table structure.
*/
Table *sqliteTableNameToTable(Parse *pParse, const char *zTab){
Table *pTab;
pTab = sqliteFindTable(pParse->db, zTab);
if( pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ", zTab, 0);
pParse->nErr++;
return 0;
}
if( pTab->readOnly || pTab->pSelect ){
sqliteSetString(&pParse->zErrMsg,
pTab->pSelect ? "view " : "table ",
zTab,
" may not be modified", 0);
pParse->nErr++;
return 0;
}
return pTab;
}
/*
** Given a table name, check to make sure the table exists, is writable
** and is not a view. If everything is OK, construct an IdList holding
** the table and return a pointer to the IdList. The calling function
** is responsible for freeing the IdList when it has finished with it.
** If there is an error, leave a message on pParse->zErrMsg and return
** NULL.
*/
IdList *sqliteTableTokenToIdList(Parse *pParse, Token *pTableName){
Table *pTab;
IdList *pTabList;
pTabList = sqliteIdListAppend(0, pTableName);
if( pTabList==0 ) return 0;
assert( pTabList->nId==1 );
pTab = sqliteTableNameToTable(pParse, pTabList->a[0].zName);
if( pTab==0 ){
sqliteIdListDelete(pTabList);
return 0;
}
pTabList->a[0].pTab = pTab;
return pTabList;
}
/*
** Process a DELETE FROM statement.
*/
@ -47,23 +96,8 @@ void sqliteDeleteFrom(
** will be calling are designed to work with multiple tables and expect
** an IdList* parameter instead of just a Table* parameger.
*/
pTabList = sqliteIdListAppend(0, pTableName);
pTabList = sqliteTableTokenToIdList(pParse, pTableName);
if( pTabList==0 ) goto delete_from_cleanup;
for(i=0; i<pTabList->nId; i++){
pTabList->a[i].pTab = sqliteFindTable(db, pTabList->a[i].zName);
if( pTabList->a[i].pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ",
pTabList->a[i].zName, 0);
pParse->nErr++;
goto delete_from_cleanup;
}
if( pTabList->a[i].pTab->readOnly ){
sqliteSetString(&pParse->zErrMsg, "table ", pTabList->a[i].zName,
" may not be modified", 0);
pParse->nErr++;
goto delete_from_cleanup;
}
}
pTab = pTabList->a[0].pTab;
/* Resolve the column names in all the expressions.

View File

@ -12,11 +12,74 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.41 2002/02/14 21:42:51 drh Exp $
** $Id: expr.c,v 1.42 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"
/*
** Construct a new expression node and return a pointer to it. Memory
** for this node is obtained from sqliteMalloc(). The calling function
** is responsible for making sure the node eventually gets freed.
*/
Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
Expr *pNew;
pNew = sqliteMalloc( sizeof(Expr) );
if( pNew==0 ){
sqliteExprDelete(pLeft);
sqliteExprDelete(pRight);
return 0;
}
pNew->op = op;
pNew->pLeft = pLeft;
pNew->pRight = pRight;
if( pToken ){
pNew->token = *pToken;
}else{
pNew->token.z = 0;
pNew->token.n = 0;
}
if( pLeft && pRight ){
sqliteExprSpan(pNew, &pLeft->span, &pRight->span);
}else{
pNew->span = pNew->token;
}
return pNew;
}
/*
** Set the Expr.token field of the given expression to span all
** text between the two given tokens.
*/
void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
if( pExpr ){
pExpr->span.z = pLeft->z;
pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z);
}
}
/*
** Construct a new expression node for a function with multiple
** arguments.
*/
Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
Expr *pNew;
pNew = sqliteMalloc( sizeof(Expr) );
if( pNew==0 ){
sqliteExprListDelete(pList);
return 0;
}
pNew->op = TK_FUNCTION;
pNew->pList = pList;
if( pToken ){
pNew->token = *pToken;
}else{
pNew->token.z = 0;
pNew->token.n = 0;
}
return pNew;
}
/*
** Recursively delete an expression tree.
*/
@ -31,6 +94,108 @@ void sqliteExprDelete(Expr *p){
sqliteFree(p);
}
/*
** The following group of functions are used to translate the string
** pointers of tokens in expression from one buffer to another.
**
** Normally, the Expr.token.z and Expr.span.z fields point into the
** original input buffer of an SQL statement. This is usually OK
** since the SQL statement is executed and the expression is deleted
** before the input buffer is freed. Making the tokens point to the
** original input buffer saves many calls to malloc() and thus helps
** the library to run faster.
**
** But sometimes we need an expression to persist past the time when
** the input buffer is freed. (Example: The SELECT clause of a
** CREATE VIEW statement contains expressions that must persist for
** the life of the view.) When that happens we have to make a
** persistent copy of the input buffer and translate the Expr.token.z
** and Expr.span.z fields to point to the copy rather than the
** original input buffer. The following group of routines to that
** translation.
**
** The "offset" parameter is the distance from the original input buffer
** to the persistent copy. These routines recursively walk the entire
** expression tree and shift all tokens by "offset" amount.
**
** The work of figuring out the appropriate "offset" and making the
** presistent copy of the input buffer is done by the calling routine.
*/
void sqliteExprMoveStrings(Expr *p, int offset){
if( p==0 ) return;
if( p->token.z ) p->token.z += offset;
if( p->span.z ) p->span.z += offset;
if( p->pLeft ) sqliteExprMoveStrings(p->pLeft, offset);
if( p->pRight ) sqliteExprMoveStrings(p->pRight, offset);
if( p->pList ) sqliteExprListMoveStrings(p->pList, offset);
if( p->pSelect ) sqliteSelectMoveStrings(p->pSelect, offset);
}
void sqliteExprListMoveStrings(ExprList *pList, int offset){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){
sqliteExprMoveStrings(pList->a[i].pExpr, offset);
}
}
void sqliteSelectMoveStrings(Select *pSelect, int offset){
if( pSelect==0 ) return;
sqliteExprListMoveStrings(pSelect->pEList, offset);
sqliteExprMoveStrings(pSelect->pWhere, offset);
sqliteExprListMoveStrings(pSelect->pGroupBy, offset);
sqliteExprMoveStrings(pSelect->pHaving, offset);
sqliteExprListMoveStrings(pSelect->pOrderBy, offset);
sqliteSelectMoveStrings(pSelect->pPrior, offset);
}
/*
** Add a new element to the end of an expression list. If pList is
** initially NULL, then create a new expression list.
*/
ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
int i;
if( pList==0 ){
pList = sqliteMalloc( sizeof(ExprList) );
if( pList==0 ){
sqliteExprDelete(pExpr);
return 0;
}
}
if( (pList->nExpr & 7)==0 ){
int n = pList->nExpr + 8;
struct ExprList_item *a;
a = sqliteRealloc(pList->a, n*sizeof(pList->a[0]));
if( a==0 ){
sqliteExprDelete(pExpr);
return pList;
}
pList->a = a;
}
if( pExpr || pName ){
i = pList->nExpr++;
pList->a[i].pExpr = pExpr;
pList->a[i].zName = 0;
if( pName ){
sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0);
sqliteDequote(pList->a[i].zName);
}
}
return pList;
}
/*
** Delete an entire expression list.
*/
void sqliteExprListDelete(ExprList *pList){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){
sqliteExprDelete(pList->a[i].pExpr);
sqliteFree(pList->a[i].zName);
}
sqliteFree(pList->a);
sqliteFree(pList);
}
/*
** Walk an expression tree. Return 1 if the expression is constant
** and 0 if it involves variables.
@ -156,7 +321,9 @@ int sqliteExprResolveIds(
case TK_ID: {
int cnt = 0; /* Number of matches */
int i; /* Loop counter */
char *z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
char *z;
assert( pExpr->token.z );
z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
sqliteDequote(z);
if( z==0 ) return 1;
for(i=0; i<pTabList->nId; i++){
@ -221,8 +388,8 @@ int sqliteExprResolveIds(
pLeft = pExpr->pLeft;
pRight = pExpr->pRight;
assert( pLeft && pLeft->op==TK_ID );
assert( pRight && pRight->op==TK_ID );
assert( pLeft && pLeft->op==TK_ID && pLeft->token.z );
assert( pRight && pRight->op==TK_ID && pRight->token.z );
zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n);
zRight = sqliteStrNDup(pRight->token.z, pRight->token.n);
if( zLeft==0 || zRight==0 ){
@ -327,6 +494,7 @@ int sqliteExprResolveIds(
case TK_INTEGER:
case TK_STRING: {
int addr = sqliteVdbeAddOp(v, OP_SetInsert, iSet, 0);
assert( pE2->token.z );
sqliteVdbeChangeP3(v, addr, pE2->token.z, pE2->token.n);
sqliteVdbeDequoteP3(v, addr);
break;
@ -577,11 +745,13 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
case TK_FLOAT:
case TK_INTEGER: {
sqliteVdbeAddOp(v, OP_String, 0, 0);
assert( pExpr->token.z );
sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
break;
}
case TK_STRING: {
int addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
assert( pExpr->token.z );
sqliteVdbeChangeP3(v, addr, pExpr->token.z, pExpr->token.n);
sqliteVdbeDequoteP3(v, addr);
break;

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.44 2002/02/19 13:39:22 drh Exp $
** $Id: insert.c,v 1.45 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"
@ -60,20 +60,9 @@ void sqliteInsert(
*/
zTab = sqliteTableNameFromToken(pTableName);
if( zTab==0 ) goto insert_cleanup;
pTab = sqliteFindTable(db, zTab);
pTab = sqliteTableNameToTable(pParse, zTab);
sqliteFree(zTab);
if( pTab==0 ){
sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0,
pTableName->z, pTableName->n, 0);
pParse->nErr++;
goto insert_cleanup;
}
if( pTab->readOnly ){
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" may not be modified", 0);
pParse->nErr++;
goto insert_cleanup;
}
if( pTab==0 ) goto insert_cleanup;
/* Allocate a VDBE
*/

View File

@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.52 2002/02/18 22:49:59 drh Exp $
** @(#) $Id: parse.y,v 1.53 2002/02/23 02:32:10 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@ -190,6 +190,15 @@ resolvetype(A) ::= REPLACE. { A = OE_Replace; }
//
cmd ::= DROP TABLE ids(X). {sqliteDropTable(pParse,&X);}
///////////////////// The CREATE VIEW statement /////////////////////////////
//
cmd ::= CREATE(X) VIEW ids(Y) AS select(S). {
sqliteCreateView(pParse, &X, &Y, S);
}
cmd ::= DROP VIEW ids(X). {
sqliteDropTable(pParse, &X);
}
//////////////////////// The SELECT statement /////////////////////////////////
//
cmd ::= select(X). {

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.64 2002/02/21 12:01:27 drh Exp $
** $Id: select.c,v 1.65 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"
@ -67,6 +67,7 @@ void sqliteSelectDelete(Select *p){
sqliteExprDelete(p->pHaving);
sqliteExprListDelete(p->pOrderBy);
sqliteSelectDelete(p->pPrior);
sqliteFree(p->zSelect);
sqliteFree(p);
}
@ -362,6 +363,7 @@ static int fillInColumnList(Parse *pParse, Select *p){
int i, j, k;
IdList *pTabList;
ExprList *pEList;
Table *pTab;
if( p==0 || p->pSrc==0 ) return 1;
pTabList = p->pSrc;
@ -376,7 +378,6 @@ static int fillInColumnList(Parse *pParse, Select *p){
}
if( pTabList->a[i].zName==0 ){
/* A sub-query in the FROM clause of a SELECT */
Table *pTab;
assert( pTabList->a[i].pSelect!=0 );
pTabList->a[i].pTab = pTab =
sqliteResultSetOfSelect(pParse, pTabList->a[i].zAlias,
@ -386,14 +387,18 @@ static int fillInColumnList(Parse *pParse, Select *p){
}
pTab->isTransient = 1;
}else{
/* An ordinary table name in the FROM clause */
pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
if( pTabList->a[i].pTab==0 ){
/* An ordinary table or view name in the FROM clause */
pTabList->a[i].pTab = pTab =
sqliteFindTable(pParse->db, pTabList->a[i].zName);
if( pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ",
pTabList->a[i].zName, 0);
pParse->nErr++;
return 1;
}
if( pTab->pSelect ){
pTabList->a[i].pSelect = pTab->pSelect;
}
}
}
@ -494,8 +499,10 @@ static int matchOrderbyToColumn(
if( pOrderBy->a[i].done ) continue;
for(j=0; j<pEList->nExpr; j++){
if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){
char *zName = pEList->a[j].zName;
char *zLabel = sqliteStrNDup(pE->token.z, pE->token.n);
char *zName, *zLabel;
zName = pEList->a[j].zName;
assert( pE->token.z );
zLabel = sqliteStrNDup(pE->token.z, pE->token.n);
sqliteDequote(zLabel);
if( sqliteStrICmp(zName, zLabel)==0 ){
match = 1;
@ -1036,9 +1043,7 @@ int sqliteSelect(
*/
for(i=0; i<pTabList->nId; i++){
int oldNTab;
Table *pTab = pTabList->a[i].pTab;
if( !pTab->isTransient ) continue;
assert( pTabList->a[i].pSelect!=0 );
if( pTabList->a[i].pSelect==0 ) continue;
oldNTab = pParse->nTab;
pParse->nTab += i+1;
sqliteVdbeAddOp(v, OP_OpenTemp, oldNTab+i, 0);

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.89 2002/02/21 12:01:27 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.90 2002/02/23 02:32:10 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
@ -250,6 +250,7 @@ struct Table {
int iPKey; /* If not less then 0, use aCol[iPKey] as the primary key */
Index *pIndex; /* List of SQL indexes on this table. */
int tnum; /* Root BTree node for this table (see note above) */
Select *pSelect; /* NULL for tables. Points to definition if a view. */
u8 readOnly; /* True if this table should not be written by the user */
u8 isCommit; /* True if creation of this table has been committed */
u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */
@ -442,6 +443,14 @@ struct WhereInfo {
/*
** An instance of the following structure contains all information
** needed to generate code for a single SELECT statement.
**
** The zSelect field is used when the Select structure must be persistent.
** Normally, the expression tree points to tokens in the original input
** string that encodes the select. But if the Select structure must live
** longer than its input string (for example when it is used to describe
** a VIEW) we have to make a copy of the input string so that the nodes
** of the expression tree will have something to point to. zSelect is used
** to hold that copy.
*/
struct Select {
int isDistinct; /* True if the DISTINCT keyword is present */
@ -454,6 +463,7 @@ struct Select {
int op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
Select *pPrior; /* Prior select in a compound select statement */
int nLimit, nOffset; /* LIMIT and OFFSET values. -1 means not used */
char *zSelect; /* Complete text of the SELECT command */
};
/*
@ -570,6 +580,7 @@ void sqliteAddPrimaryKey(Parse*, IdList*, int);
void sqliteAddColumnType(Parse*,Token*,Token*);
void sqliteAddDefaultValue(Parse*,Token*,int);
void sqliteEndTable(Parse*,Token*,Select*);
void sqliteCreateView(Parse*,Token*,Token*,Select*);
void sqliteDropTable(Parse*, Token*);
void sqliteDeleteTable(sqlite*, Table*);
void sqliteInsert(Parse*, Token*, ExprList*, Select*, IdList*, int);
@ -582,6 +593,8 @@ int sqliteSelect(Parse*, Select*, int, int);
Select *sqliteSelectNew(ExprList*,IdList*,Expr*,ExprList*,Expr*,ExprList*,
int,int,int);
void sqliteSelectDelete(Select*);
Table *sqliteTableNameToTable(Parse*, const char*);
IdList *sqliteTableTokenToIdList(Parse*, Token*);
void sqliteDeleteFrom(Parse*, Token*, Expr*);
void sqliteUpdate(Parse*, Token*, ExprList*, Expr*, int);
WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int);
@ -589,8 +602,8 @@ void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int);
void sqliteExprIfFalse(Parse*, Expr*, int);
Table *sqliteFindTable(sqlite*,char*);
Index *sqliteFindIndex(sqlite*,char*);
Table *sqliteFindTable(sqlite*,const char*);
Index *sqliteFindIndex(sqlite*,const char*);
void sqliteUnlinkAndDeleteIndex(sqlite*,Index*);
void sqliteCopy(Parse*, Token*, Token*, Token*, int);
void sqliteVacuum(Parse*, Token*);
@ -618,3 +631,6 @@ void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int);
void sqliteBeginWriteOperation(Parse*);
void sqliteBeginMultiWriteOperation(Parse*);
void sqliteEndWriteOperation(Parse*);
void sqliteExprMoveStrings(Expr*, int);
void sqliteExprListMoveStrings(ExprList*, int);
void sqliteSelectMoveStrings(Select*, int);

View File

@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.37 2002/02/21 12:01:27 drh Exp $
** $Id: tokenize.c,v 1.38 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -101,6 +101,7 @@ static Keyword aKeywordTable[] = {
{ "USING", 0, TK_USING, 0 },
{ "VACUUM", 0, TK_VACUUM, 0 },
{ "VALUES", 0, TK_VALUES, 0 },
{ "VIEW", 0, TK_VIEW, 0 },
{ "WHERE", 0, TK_WHERE, 0 },
};
@ -419,7 +420,7 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
break;
}
}
if( nErr==0 && (db->flags & SQLITE_Interrupt)==0 ){
if( zSql[i]==0 ){
sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
if( pParse->zErrMsg && pParse->sErrToken.z ){
sqliteSetNString(pzErrMsg, "near \"", -1,

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.33 2002/02/02 18:49:21 drh Exp $
** $Id: update.c,v 1.34 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"
@ -55,23 +55,8 @@ void sqliteUpdate(
** will be calling are designed to work with multiple tables and expect
** an IdList* parameter instead of just a Table* parameter.
*/
pTabList = sqliteIdListAppend(0, pTableName);
pTabList = sqliteTableTokenToIdList(pParse, pTableName);
if( pTabList==0 ) goto update_cleanup;
for(i=0; i<pTabList->nId; i++){
pTabList->a[i].pTab = sqliteFindTable(db, pTabList->a[i].zName);
if( pTabList->a[i].pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ",
pTabList->a[i].zName, 0);
pParse->nErr++;
goto update_cleanup;
}
if( pTabList->a[i].pTab->readOnly ){
sqliteSetString(&pParse->zErrMsg, "table ", pTabList->a[i].zName,
" may not be modified", 0);
pParse->nErr++;
goto update_cleanup;
}
}
pTab = pTabList->a[0].pTab;
aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
if( aXRef==0 ) goto update_cleanup;

View File

@ -13,7 +13,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.36 2002/02/18 22:49:59 drh Exp $
** $Id: where.c,v 1.37 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"
@ -399,7 +399,7 @@ WhereInfo *sqliteWhereBegin(
Table *pTab;
pTab = pTabList->a[i].pTab;
if( pTab->isTransient ) continue;
if( pTab->isTransient || pTab->pSelect ) continue;
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
sqliteVdbeAddOp(v, openOp, base+i, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);