/ Check-in [6121e5ab]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:VIEWs are bound to tables when they are used, not when they are first entered. This works around the problem of what to do if a table is deleted that a view refers to. (CVS 415)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:6121e5ab9328c90c64d40ade3de73ad11d4aaf4e
User & Date: drh 2002-03-03 18:59:40
Context
2002-03-03
23:06
More bugs fixed for views. (CVS 416) check-in: 81307762 user: drh tags: trunk
18:59
VIEWs are bound to tables when they are used, not when they are first entered. This works around the problem of what to do if a table is deleted that a view refers to. (CVS 415) check-in: 6121e5ab user: drh tags: trunk
03:42
Fix a memory leak in expression processing. (CVS 414) check-in: dfe431c9 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

    21     21   **     COPY
    22     22   **     VACUUM
    23     23   **     BEGIN TRANSACTION
    24     24   **     COMMIT
    25     25   **     ROLLBACK
    26     26   **     PRAGMA
    27     27   **
    28         -** $Id: build.c,v 1.81 2002/03/02 17:04:08 drh Exp $
           28  +** $Id: build.c,v 1.82 2002/03/03 18:59:40 drh Exp $
    29     29   */
    30     30   #include "sqliteInt.h"
    31     31   #include <ctype.h>
    32     32   
    33     33   /*
    34     34   ** This routine is called after a single SQL statement has been
    35     35   ** parsed and we want to execute the VDBE code to implement 
................................................................................
   803    803   void sqliteCreateView(
   804    804     Parse *pParse,     /* The parsing context */
   805    805     Token *pBegin,     /* The CREATE token that begins the statement */
   806    806     Token *pName,      /* The token that holds the name of the view */
   807    807     Select *pSelect    /* A SELECT statement that will become the new view */
   808    808   ){
   809    809     Token sEnd;
   810         -  Table *pSelTab;
   811    810     Table *p;
   812    811     char *z;
   813    812     int n, offset;
   814    813   
   815    814     sqliteStartTable(pParse, pBegin, pName, 0);
   816    815     p = pParse->pNewTable;
   817         -  if( p==0 ) goto create_view_failed;
          816  +  if( p==0 ){
          817  +    sqliteSelectDelete(pSelect);
          818  +    return;
          819  +  }
   818    820     p->pSelect = pSelect;
   819         -  pSelTab = sqliteResultSetOfSelect(pParse, 0, pSelect);
   820         -  if( pSelTab==0 ) goto create_view_failed;
   821         -  assert( p->aCol==0 );
   822         -  p->nCol = pSelTab->nCol;
   823         -  p->aCol = pSelTab->aCol;
   824         -  pSelTab->nCol = 0;
   825         -  pSelTab->aCol = 0;
   826         -  sqliteDeleteTable(0, pSelTab);
   827         -  sqliteSelectUnbind(pSelect);
          821  +  if( !pParse->initFlag ){
          822  +    if( sqliteViewGetColumnNames(pParse, p) ){
          823  +      return;
          824  +    }
          825  +  }
   828    826     sEnd = pParse->sLastToken;
   829    827     if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){
   830    828       sEnd.z += sEnd.n;
   831    829     }
   832    830     sEnd.n = 0;
   833    831     n = ((int)sEnd.z) - (int)pBegin->z;
   834    832     z = p->pSelect->zSelect = sqliteStrNDup(pBegin->z, n+1);
   835         -  if( z==0 ) goto create_view_failed;
   836         -  offset = ((int)z) - (int)pBegin->z;
   837         -  sqliteSelectMoveStrings(p->pSelect, offset);
   838         -  sqliteEndTable(pParse, &sEnd, 0);
          833  +  if( z ){
          834  +    offset = ((int)z) - (int)pBegin->z;
          835  +    sqliteSelectMoveStrings(p->pSelect, offset);
          836  +    sqliteEndTable(pParse, &sEnd, 0);
          837  +  }
   839    838     return;
   840         -
   841         -create_view_failed:
   842         -  sqliteSelectDelete(pSelect);
   843         -  return;
          839  +}
          840  +
          841  +/*
          842  +** The Table structure pTable is really a VIEW.  Fill in the names of
          843  +** the columns of the view in the pTable structure.  Return the number
          844  +** of errors.  If an error is seen leave an error message in pPare->zErrMsg.
          845  +*/
          846  +int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
          847  +  ExprList *pEList;
          848  +  Select *pSel;
          849  +  Table *pSelTab;
          850  +  int nErr = 0;
          851  +
          852  +  assert( pTable );
          853  +
          854  +  /* A positive nCol means the columns names for this view are
          855  +  ** already known.
          856  +  */
          857  +  if( pTable->nCol>0 ) return 0;
          858  +
          859  +  /* A negative nCol is a special marker meaning that we are currently
          860  +  ** trying to compute the column names.  If we enter this routine with
          861  +  ** a negative nCol, it means two or more views form a loop, like this:
          862  +  **
          863  +  **     CREATE VIEW one AS SELECT * FROM two;
          864  +  **     CREATE VIEW two AS SELECT * FROM one;
          865  +  */
          866  +  if( pTable->nCol<0 ){
          867  +    sqliteSetString(&pParse->zErrMsg, "view ", pTable->zName,
          868  +         " is circularly defined", 0);
          869  +    pParse->nErr++;
          870  +    return 1;
          871  +  }
          872  +
          873  +  /* If we get this far, it means we need to compute the table names.
          874  +  */
          875  +  assert( pTable->pSelect ); /* If nCol==0, then pTable must be a VIEW */
          876  +  pSel = pTable->pSelect;
          877  +
          878  +  /* Note that the call to sqliteResultSetOfSelect() will expand any
          879  +  ** "*" elements in this list.  But we will need to restore the list
          880  +  ** back to its original configuration afterwards, so we save a copy of
          881  +  ** the original in pEList.
          882  +  */
          883  +  pEList = pSel->pEList;
          884  +  pSel->pEList = sqliteExprListDup(pEList);
          885  +  if( pSel->pEList==0 ){
          886  +    pSel->pEList = pEList;
          887  +    return 1;  /* Malloc failed */
          888  +  }
          889  +  pTable->nCol = -1;
          890  +  pSelTab = sqliteResultSetOfSelect(pParse, 0, pSel);
          891  +  if( pSelTab ){
          892  +    assert( pTable->aCol==0 );
          893  +    pTable->nCol = pSelTab->nCol;
          894  +    pTable->aCol = pSelTab->aCol;
          895  +    pSelTab->nCol = 0;
          896  +    pSelTab->aCol = 0;
          897  +    sqliteDeleteTable(0, pSelTab);
          898  +    pParse->db->flags |= SQLITE_UnresetViews;
          899  +  }else{
          900  +    pTable->nCol = 0;
          901  +    nErr++;
          902  +  }
          903  +  sqliteSelectUnbind(pSel);
          904  +  sqliteExprListDelete(pSel->pEList);
          905  +  pSel->pEList = pEList;
          906  +  return nErr;  
          907  +}
          908  +
          909  +/*
          910  +** Clear the column names from the VIEW pTable.
          911  +**
          912  +** This routine is called whenever any other table or view is modified.
          913  +** The view passed into this routine might depend directly or indirectly
          914  +** on the modified or deleted table so we need to clear the old column
          915  +** names so that they will be recomputed.
          916  +*/
          917  +static void sqliteViewResetColumnNames(Table *pTable){
          918  +  int i;
          919  +  if( pTable==0 || pTable->pSelect==0 ) return;
          920  +  if( pTable->nCol==0 ) return;
          921  +  for(i=0; i<pTable->nCol; i++){
          922  +    sqliteFree(pTable->aCol[i].zName);
          923  +    sqliteFree(pTable->aCol[i].zDflt);
          924  +    sqliteFree(pTable->aCol[i].zType);
          925  +  }
          926  +  sqliteFree(pTable->aCol);
          927  +  pTable->aCol = 0;
          928  +  pTable->nCol = 0;
          929  +}
          930  +
          931  +/*
          932  +** Clear the column names from every VIEW.
          933  +*/
          934  +void sqliteViewResetAll(sqlite *db){
          935  +  HashElem *i;
          936  +  if( (db->flags & SQLITE_UnresetViews)==0 ) return;
          937  +  for(i=sqliteHashFirst(&db->tblHash); i; i=sqliteHashNext(i)){
          938  +    Table *pTab = sqliteHashData(i);
          939  +    if( pTab->pSelect ){
          940  +      sqliteViewResetColumnNames(pTab);
          941  +    }
          942  +  }
          943  +  db->flags &= ~SQLITE_UnresetViews;
   844    944   }
   845    945   
   846    946   /*
   847    947   ** Given a token, look up a table with that name.  If not found, leave
   848    948   ** an error for the parser to find and return NULL.
   849    949   */
   850    950   Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
................................................................................
   923   1023     ** Exception: if the SQL statement began with the EXPLAIN keyword,
   924   1024     ** then no changes should be made.
   925   1025     */
   926   1026     if( !pParse->explain ){
   927   1027       sqlitePendingDropTable(db, pTable);
   928   1028       db->flags |= SQLITE_InternChanges;
   929   1029     }
         1030  +  sqliteViewResetAll(db);
   930   1031   }
   931   1032   
   932   1033   /*
   933   1034   ** Create a new index for an SQL table.  pIndex is the name of the index 
   934   1035   ** and pTable is the name of the table that is to be indexed.  Both will 
   935   1036   ** be NULL for a primary key or an index that is created to satisfy a
   936   1037   ** UNIQUE constraint.  If pTable and pIndex are NULL, use pParse->pNewTable
................................................................................
  1670   1771           { OP_ColumnName,  1, 0,       "name"},
  1671   1772           { OP_ColumnName,  2, 0,       "type"},
  1672   1773           { OP_ColumnName,  3, 0,       "notnull"},
  1673   1774           { OP_ColumnName,  4, 0,       "dflt_value"},
  1674   1775         };
  1675   1776         int i;
  1676   1777         sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
         1778  +      sqliteViewGetColumnNames(pParse, pTab);
  1677   1779         for(i=0; i<pTab->nCol; i++){
  1678   1780           sqliteVdbeAddOp(v, OP_Integer, i, 0);
  1679   1781           sqliteVdbeAddOp(v, OP_String, 0, 0);
  1680   1782           sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zName, P3_STATIC);
  1681   1783           sqliteVdbeAddOp(v, OP_String, 0, 0);
  1682   1784           sqliteVdbeChangeP3(v, -1, 
  1683   1785              pTab->aCol[i].zType ? pTab->aCol[i].zType : "text", P3_STATIC);
................................................................................
  1706   1808         pTab = pIdx->pTable;
  1707   1809         sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
  1708   1810         for(i=0; i<pIdx->nColumn; i++){
  1709   1811           int cnum = pIdx->aiColumn[i];
  1710   1812           sqliteVdbeAddOp(v, OP_Integer, i, 0);
  1711   1813           sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
  1712   1814           sqliteVdbeAddOp(v, OP_String, 0, 0);
         1815  +        assert( pTab->nCol>cnum );
  1713   1816           sqliteVdbeChangeP3(v, -1, pTab->aCol[cnum].zName, P3_STATIC);
  1714   1817           sqliteVdbeAddOp(v, OP_Callback, 3, 0);
  1715   1818         }
  1716   1819       }
  1717   1820     }else
  1718   1821   
  1719   1822     if( sqliteStrICmp(zLeft, "index_list")==0 ){

Changes to src/delete.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle DELETE FROM statements.
    14     14   **
    15         -** $Id: delete.c,v 1.28 2002/03/02 17:04:08 drh Exp $
           15  +** $Id: delete.c,v 1.29 2002/03/03 18:59:40 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   
    20     20   /*
    21     21   ** Given a table name, find the corresponding table and make sure the
    22     22   ** table is writeable.  Generate an error and return NULL if not.  If
................................................................................
    94     94     /* Locate the table which we want to delete.  This table has to be
    95     95     ** put in an IdList structure because some of the subroutines we
    96     96     ** will be calling are designed to work with multiple tables and expect
    97     97     ** an IdList* parameter instead of just a Table* parameger.
    98     98     */
    99     99     pTabList = sqliteTableTokenToIdList(pParse, pTableName);
   100    100     if( pTabList==0 ) goto delete_from_cleanup;
          101  +  assert( pTabList->nId==1 );
   101    102     pTab = pTabList->a[0].pTab;
          103  +  assert( pTab->pSelect==0 );  /* This table is not a view */
   102    104   
   103    105     /* Resolve the column names in all the expressions.
   104    106     */
   105    107     base = pParse->nTab++;
   106    108     if( pWhere ){
   107    109       if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){
   108    110         goto delete_from_cleanup;

Changes to src/expr.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains routines used for analyzing expressions and
    13     13   ** for generating VDBE code that evaluates expressions in SQLite.
    14     14   **
    15         -** $Id: expr.c,v 1.53 2002/03/03 03:42:31 drh Exp $
           15  +** $Id: expr.c,v 1.54 2002/03/03 18:59:41 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   
    20     20   /*
    21     21   ** Construct a new expression node and return a pointer to it.  Memory
    22     22   ** for this node is obtained from sqliteMalloc().  The calling function
................................................................................
   380    380         z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
   381    381         sqliteDequote(z);
   382    382         if( z==0 ) return 1;
   383    383         for(i=0; i<pTabList->nId; i++){
   384    384           int j;
   385    385           Table *pTab = pTabList->a[i].pTab;
   386    386           if( pTab==0 ) continue;
          387  +        assert( pTab->nCol>0 );
   387    388           for(j=0; j<pTab->nCol; j++){
   388    389             if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
   389    390               cnt++;
   390    391               pExpr->iTable = i + base;
   391    392               if( j==pTab->iPKey ){
   392    393                 /* Substitute the record number for the INTEGER PRIMARY KEY */
   393    394                 pExpr->iColumn = -1;
................................................................................
   455    456         sqliteDequote(zRight);
   456    457         pExpr->iTable = -1;
   457    458         for(i=0; i<pTabList->nId; i++){
   458    459           int j;
   459    460           char *zTab;
   460    461           Table *pTab = pTabList->a[i].pTab;
   461    462           if( pTab==0 ) continue;
          463  +        assert( pTab->nCol>0 );
   462    464           if( pTabList->a[i].zAlias ){
   463    465             zTab = pTabList->a[i].zAlias;
   464    466           }else{
   465    467             zTab = pTab->zName;
   466    468           }
   467    469           if( sqliteStrICmp(zTab, zLeft)!=0 ) continue;
   468    470           if( 0==(cntTab++) ) pExpr->iTable = i + base;

Changes to src/insert.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle INSERT statements in SQLite.
    14     14   **
    15         -** $Id: insert.c,v 1.46 2002/03/02 17:04:08 drh Exp $
           15  +** $Id: insert.c,v 1.47 2002/03/03 18:59:41 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   /*
    20     20   ** This routine is call to handle SQL of the following forms:
    21     21   **
    22     22   **    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
    59     59     /* Locate the table into which we will be inserting new information.
    60     60     */
    61     61     zTab = sqliteTableNameFromToken(pTableName);
    62     62     if( zTab==0 ) goto insert_cleanup;
    63     63     pTab = sqliteTableNameToTable(pParse, zTab);
    64     64     sqliteFree(zTab);
    65     65     if( pTab==0 ) goto insert_cleanup;
           66  +  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
    66     67   
    67     68     /* Allocate a VDBE
    68     69     */
    69     70     v = sqliteGetVdbe(pParse);
    70     71     if( v==0 ) goto insert_cleanup;
    71     72     if( pSelect ){
    72     73       sqliteBeginMultiWriteOperation(pParse);
................................................................................
   388    389     int seenReplace = 0;
   389    390     int jumpInst;
   390    391     int contAddr;
   391    392     int hasTwoRecnos = (isUpdate && recnoChng);
   392    393   
   393    394     v = sqliteGetVdbe(pParse);
   394    395     assert( v!=0 );
          396  +  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
   395    397     nCol = pTab->nCol;
   396    398   
   397    399     /* Test all NOT NULL constraints.
   398    400     */
   399    401     for(i=0; i<nCol; i++){
   400    402       if( i==pTab->iPKey ){
   401    403         /* Fix me: Make sure the INTEGER PRIMARY KEY is not NULL. */
................................................................................
   549    551     int i;
   550    552     Vdbe *v;
   551    553     int nIdx;
   552    554     Index *pIdx;
   553    555   
   554    556     v = sqliteGetVdbe(pParse);
   555    557     assert( v!=0 );
          558  +  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
   556    559     for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
   557    560     for(i=nIdx-1; i>=0; i--){
   558    561       if( aIdxUsed && aIdxUsed[i]==0 ) continue;
   559    562       sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0);
   560    563     }
   561    564     sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
   562    565     sqliteVdbeAddOp(v, OP_PutIntKey, base, 0);
   563    566     if( isUpdate && recnoChng ){
   564    567       sqliteVdbeAddOp(v, OP_Pop, 1, 0);
   565    568     }
   566    569   }

Changes to src/select.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle SELECT statements in SQLite.
    14     14   **
    15         -** $Id: select.c,v 1.73 2002/03/03 03:03:53 drh Exp $
           15  +** $Id: select.c,v 1.74 2002/03/03 18:59:41 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   /*
    20     20   ** Allocate a new Select structure and return a pointer to that
    21     21   ** structure.
    22     22   */
................................................................................
   323    323     pTab = sqliteMalloc( sizeof(Table) );
   324    324     if( pTab==0 ){
   325    325       return 0;
   326    326     }
   327    327     pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0;
   328    328     pEList = pSelect->pEList;
   329    329     pTab->nCol = pEList->nExpr;
          330  +  assert( pTab->nCol>0 );
   330    331     pTab->aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
   331    332     for(i=0; i<pTab->nCol; i++){
   332    333       Expr *p;
   333    334       if( pEList->a[i].zName ){
   334    335         pTab->aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
   335    336       }else if( (p=pEList->a[i].pExpr)->span.z && p->span.z[0] ){
   336    337         sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0);
................................................................................
   396    397         if( pTab==0 ){
   397    398           sqliteSetString(&pParse->zErrMsg, "no such table: ", 
   398    399              pTabList->a[i].zName, 0);
   399    400           pParse->nErr++;
   400    401           return 1;
   401    402         }
   402    403         if( pTab->pSelect ){
          404  +        if( sqliteViewGetColumnNames(pParse, pTab) ){
          405  +          return 1;
          406  +        }
   403    407           pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect);
   404    408         }
   405    409       }
   406    410     }
   407    411   
   408    412     /* For every "*" that occurs in the column list, insert the names of
   409    413     ** all columns in all tables.  The parser inserted a special expression

Changes to src/sqliteInt.h.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Internal interface definitions for SQLite.
    13     13   **
    14         -** @(#) $Id: sqliteInt.h,v 1.99 2002/03/03 03:03:53 drh Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.100 2002/03/03 18:59:41 drh Exp $
    15     15   */
    16     16   #include "sqlite.h"
    17     17   #include "hash.h"
    18     18   #include "vdbe.h"
    19     19   #include "parse.h"
    20     20   #include "btree.h"
    21     21   #include <stdio.h>
................................................................................
   179    179   #define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */
   180    180   #define SQLITE_CountRows      0x00000040  /* Count rows changed by INSERT, */
   181    181                                             /*   DELETE, or UPDATE and return */
   182    182                                             /*   the count using a callback. */
   183    183   #define SQLITE_NullCallback   0x00000080  /* Invoke the callback once if the */
   184    184                                             /*   result set is empty */
   185    185   #define SQLITE_ResultDetails  0x00000100  /* Details added to result set */
          186  +#define SQLITE_UnresetViews   0x00000200  /* True if one or more views have */
          187  +                                          /*   defined column names */
   186    188   
   187    189   /*
   188    190   ** Each SQL function is defined by an instance of the following
   189    191   ** structure.  A pointer to this structure is stored in the sqlite.aFunc
   190    192   ** hash table.  When multiple functions have the same name, the hash table
   191    193   ** points to a linked list of these structures.
   192    194   */
................................................................................
   578    580   void sqliteAddColumn(Parse*,Token*);
   579    581   void sqliteAddNotNull(Parse*, int);
   580    582   void sqliteAddPrimaryKey(Parse*, IdList*, int);
   581    583   void sqliteAddColumnType(Parse*,Token*,Token*);
   582    584   void sqliteAddDefaultValue(Parse*,Token*,int);
   583    585   void sqliteEndTable(Parse*,Token*,Select*);
   584    586   void sqliteCreateView(Parse*,Token*,Token*,Select*);
          587  +int sqliteViewGetColumnNames(Parse*,Table*);
          588  +void sqliteViewResetAll(sqlite*);
   585    589   void sqliteDropTable(Parse*, Token*);
   586    590   void sqliteDeleteTable(sqlite*, Table*);
   587    591   void sqliteInsert(Parse*, Token*, ExprList*, Select*, IdList*, int);
   588    592   IdList *sqliteIdListAppend(IdList*, Token*);
   589    593   void sqliteIdListAddAlias(IdList*, Token*);
   590    594   void sqliteIdListDelete(IdList*);
   591    595   void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, int, Token*, Token*);

Changes to src/update.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle UPDATE statements.
    14     14   **
    15         -** $Id: update.c,v 1.35 2002/03/02 17:04:09 drh Exp $
           15  +** $Id: update.c,v 1.36 2002/03/03 18:59:41 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   /*
    20     20   ** Process an UPDATE statement.
    21     21   */
    22     22   void sqliteUpdate(
................................................................................
    54     54     ** put in an IdList structure because some of the subroutines we
    55     55     ** will be calling are designed to work with multiple tables and expect
    56     56     ** an IdList* parameter instead of just a Table* parameter.
    57     57     */
    58     58     pTabList = sqliteTableTokenToIdList(pParse, pTableName);
    59     59     if( pTabList==0 ) goto update_cleanup;
    60     60     pTab = pTabList->a[0].pTab;
           61  +  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
    61     62     aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
    62     63     if( aXRef==0 ) goto update_cleanup;
    63     64     for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
    64     65   
    65     66     /* Resolve the column names in all the expressions in both the
    66     67     ** WHERE clause and in the new values.  Also find the column index
    67     68     ** for each column to be updated in the pChanges array.

Changes to test/view.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing VIEW statements.
    13     13   #
    14         -# $Id: view.test,v 1.1 2002/02/27 01:47:12 drh Exp $
           14  +# $Id: view.test,v 1.2 2002/03/03 18:59:41 drh Exp $
    15     15   set testdir [file dirname $argv0]
    16     16   source $testdir/tester.tcl
    17     17   
    18     18   do_test view-1.0 {
    19     19     execsql {
    20     20       CREATE TABLE t1(a,b,c);
    21     21       INSERT INTO t1 VALUES(1,2,3);
................................................................................
    39     39     }
    40     40   } {1 {no such table: v1}}
    41     41   do_test view-1.3 {
    42     42     execsql {
    43     43       CREATE VIEW v1 AS SELECT a,b FROM t1;
    44     44       SELECT * FROM v1 ORDER BY a;
    45     45     }
           46  +} {1 2 4 5 7 8}
           47  +do_test view-1.3.1 {
           48  +  db close
           49  +  sqlite db test.db
           50  +  execsql {
           51  +    SELECT * FROM v1 ORDER BY a;
           52  +  }
    46     53   } {1 2 4 5 7 8}
    47     54   do_test view-1.4 {
    48     55     catchsql {
    49     56       DROP VIEW v1;
    50     57       SELECT * FROM v1 ORDER BY a;
    51     58     }
    52     59   } {1 {no such table: v1}}
................................................................................
    67     74       CREATE TABLE t1(x,a,b,c);
    68     75       INSERT INTO t1 VALUES(1,2,3,4);
    69     76       INSERT INTO t1 VALUES(4,5,6,7);
    70     77       INSERT INTO t1 VALUES(7,8,9,10);
    71     78       SELECT * FROM v1 ORDER BY a;
    72     79     }
    73     80   } {2 3 5 6 8 9}
           81  +do_test view-1.8 {
           82  +  db close
           83  +  sqlite db test.db
           84  +  execsql {
           85  +    SELECT * FROM v1 ORDER BY a;
           86  +  }
           87  +} {2 3 5 6 8 9}
           88  +
    74     89   
    75     90   finish_test