-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
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
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
-b2a9807fed544e83002366149b9a363759338c5d
\ No newline at end of file
+39fed2df11382b9855d518502a6c2ca200fa66b8
\ No newline at end of file
** 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>
}
}
-/*
-** 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;
}
** 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;
}
}
sqliteFree(pTable->zName);
sqliteFree(pTable->aCol);
+ sqliteSelectDelete(pTable->pSelect);
sqliteFree(pTable);
}
}
}
+/*
+** 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.
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
}
}
-/*
-** 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.
}
/*
-** Delete an entire IdList
+** Delete an entire IdList.
*/
void sqliteIdListDelete(IdList *pList){
int i;
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);
}
** 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.
*/
** 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.
** 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.
*/
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.
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++){
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 ){
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;
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;
** 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"
*/
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
*/
** 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}
//
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). {
** 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"
sqliteExprDelete(p->pHaving);
sqliteExprListDelete(p->pOrderBy);
sqliteSelectDelete(p->pPrior);
+ sqliteFree(p->zSelect);
sqliteFree(p);
}
int i, j, k;
IdList *pTabList;
ExprList *pEList;
+ Table *pTab;
if( p==0 || p->pSrc==0 ) return 1;
pTabList = p->pSrc;
}
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,
}
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;
+ }
}
}
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;
*/
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);
*************************************************************************
** 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"
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 */
/*
** 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 */
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 */
};
/*
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);
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);
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*);
void sqliteBeginWriteOperation(Parse*);
void sqliteBeginMultiWriteOperation(Parse*);
void sqliteEndWriteOperation(Parse*);
+void sqliteExprMoveStrings(Expr*, int);
+void sqliteExprListMoveStrings(ExprList*, int);
+void sqliteSelectMoveStrings(Select*, int);
** 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"
{ "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 },
};
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,
** 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"
** 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;
** 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"
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);