SQLite

Check-in [6121e5ab93]
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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6121e5ab9328c90c64d40ade3de73ad11d4aaf4e
User & Date: drh 2002-03-03 18:59:40.000
Context
2002-03-03
23:06
More bugs fixed for views. (CVS 416) (check-in: 8130776230 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: 6121e5ab93 user: drh tags: trunk)
03:42
Fix a memory leak in expression processing. (CVS 414) (check-in: dfe431c9b7 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/build.c.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.81 2002/03/02 17:04:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.82 2002/03/03 18:59:40 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817



818
819
820
821
822
823
824
825
826
827


828
829
830
831
832
833
834
835
836
837
838

839
840
841






























































842


843





































844
845
846
847
848
849
850
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);
  sqliteSelectUnbind(pSelect);


  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.
*/
Table *sqliteTableFromToken(Parse *pParse, Token *pTok){







<






|
>
>
>

|
|
<
<
<
<
<
|
<
>
>







|
|
|
|
>

|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







803
804
805
806
807
808
809

810
811
812
813
814
815
816
817
818
819
820
821
822





823

824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
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 *p;
  char *z;
  int n, offset;

  sqliteStartTable(pParse, pBegin, pName, 0);
  p = pParse->pNewTable;
  if( p==0 ){
    sqliteSelectDelete(pSelect);
    return;
  }
  p->pSelect = pSelect;
  if( !pParse->initFlag ){
    if( sqliteViewGetColumnNames(pParse, p) ){





      return;

    }
  }
  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 ){
    offset = ((int)z) - (int)pBegin->z;
    sqliteSelectMoveStrings(p->pSelect, offset);
    sqliteEndTable(pParse, &sEnd, 0);
  }
  return;
}

/*
** The Table structure pTable is really a VIEW.  Fill in the names of
** the columns of the view in the pTable structure.  Return the number
** of errors.  If an error is seen leave an error message in pPare->zErrMsg.
*/
int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
  ExprList *pEList;
  Select *pSel;
  Table *pSelTab;
  int nErr = 0;

  assert( pTable );

  /* A positive nCol means the columns names for this view are
  ** already known.
  */
  if( pTable->nCol>0 ) return 0;

  /* A negative nCol is a special marker meaning that we are currently
  ** trying to compute the column names.  If we enter this routine with
  ** a negative nCol, it means two or more views form a loop, like this:
  **
  **     CREATE VIEW one AS SELECT * FROM two;
  **     CREATE VIEW two AS SELECT * FROM one;
  */
  if( pTable->nCol<0 ){
    sqliteSetString(&pParse->zErrMsg, "view ", pTable->zName,
         " is circularly defined", 0);
    pParse->nErr++;
    return 1;
  }

  /* If we get this far, it means we need to compute the table names.
  */
  assert( pTable->pSelect ); /* If nCol==0, then pTable must be a VIEW */
  pSel = pTable->pSelect;

  /* Note that the call to sqliteResultSetOfSelect() will expand any
  ** "*" elements in this list.  But we will need to restore the list
  ** back to its original configuration afterwards, so we save a copy of
  ** the original in pEList.
  */
  pEList = pSel->pEList;
  pSel->pEList = sqliteExprListDup(pEList);
  if( pSel->pEList==0 ){
    pSel->pEList = pEList;
    return 1;  /* Malloc failed */
  }
  pTable->nCol = -1;
  pSelTab = sqliteResultSetOfSelect(pParse, 0, pSel);
  if( pSelTab ){
    assert( pTable->aCol==0 );
    pTable->nCol = pSelTab->nCol;
    pTable->aCol = pSelTab->aCol;
    pSelTab->nCol = 0;
    pSelTab->aCol = 0;
    sqliteDeleteTable(0, pSelTab);
    pParse->db->flags |= SQLITE_UnresetViews;
  }else{
    pTable->nCol = 0;
    nErr++;
  }
  sqliteSelectUnbind(pSel);
  sqliteExprListDelete(pSel->pEList);
  pSel->pEList = pEList;
  return nErr;  
}

/*
** Clear the column names from the VIEW pTable.
**
** This routine is called whenever any other table or view is modified.
** The view passed into this routine might depend directly or indirectly
** on the modified or deleted table so we need to clear the old column
** names so that they will be recomputed.
*/
static void sqliteViewResetColumnNames(Table *pTable){
  int i;
  if( pTable==0 || pTable->pSelect==0 ) return;
  if( pTable->nCol==0 ) return;
  for(i=0; i<pTable->nCol; i++){
    sqliteFree(pTable->aCol[i].zName);
    sqliteFree(pTable->aCol[i].zDflt);
    sqliteFree(pTable->aCol[i].zType);
  }
  sqliteFree(pTable->aCol);
  pTable->aCol = 0;
  pTable->nCol = 0;
}

/*
** Clear the column names from every VIEW.
*/
void sqliteViewResetAll(sqlite *db){
  HashElem *i;
  if( (db->flags & SQLITE_UnresetViews)==0 ) return;
  for(i=sqliteHashFirst(&db->tblHash); i; i=sqliteHashNext(i)){
    Table *pTab = sqliteHashData(i);
    if( pTab->pSelect ){
      sqliteViewResetColumnNames(pTab);
    }
  }
  db->flags &= ~SQLITE_UnresetViews;
}

/*
** Given a token, look up a table with that name.  If not found, leave
** an error for the parser to find and return NULL.
*/
Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
923
924
925
926
927
928
929

930
931
932
933
934
935
936
  ** Exception: if the SQL statement began with the EXPLAIN keyword,
  ** then no changes should be made.
  */
  if( !pParse->explain ){
    sqlitePendingDropTable(db, pTable);
    db->flags |= SQLITE_InternChanges;
  }

}

/*
** Create a new index for an SQL table.  pIndex is the name of the index 
** and pTable is the name of the table that is to be indexed.  Both will 
** be NULL for a primary key or an index that is created to satisfy a
** UNIQUE constraint.  If pTable and pIndex are NULL, use pParse->pNewTable







>







1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
  ** Exception: if the SQL statement began with the EXPLAIN keyword,
  ** then no changes should be made.
  */
  if( !pParse->explain ){
    sqlitePendingDropTable(db, pTable);
    db->flags |= SQLITE_InternChanges;
  }
  sqliteViewResetAll(db);
}

/*
** Create a new index for an SQL table.  pIndex is the name of the index 
** and pTable is the name of the table that is to be indexed.  Both will 
** be NULL for a primary key or an index that is created to satisfy a
** UNIQUE constraint.  If pTable and pIndex are NULL, use pParse->pNewTable
1670
1671
1672
1673
1674
1675
1676

1677
1678
1679
1680
1681
1682
1683
        { OP_ColumnName,  1, 0,       "name"},
        { OP_ColumnName,  2, 0,       "type"},
        { OP_ColumnName,  3, 0,       "notnull"},
        { OP_ColumnName,  4, 0,       "dflt_value"},
      };
      int i;
      sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);

      for(i=0; i<pTab->nCol; i++){
        sqliteVdbeAddOp(v, OP_Integer, i, 0);
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zName, P3_STATIC);
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        sqliteVdbeChangeP3(v, -1, 
           pTab->aCol[i].zType ? pTab->aCol[i].zType : "text", P3_STATIC);







>







1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
        { OP_ColumnName,  1, 0,       "name"},
        { OP_ColumnName,  2, 0,       "type"},
        { OP_ColumnName,  3, 0,       "notnull"},
        { OP_ColumnName,  4, 0,       "dflt_value"},
      };
      int i;
      sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
      sqliteViewGetColumnNames(pParse, pTab);
      for(i=0; i<pTab->nCol; i++){
        sqliteVdbeAddOp(v, OP_Integer, i, 0);
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zName, P3_STATIC);
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        sqliteVdbeChangeP3(v, -1, 
           pTab->aCol[i].zType ? pTab->aCol[i].zType : "text", P3_STATIC);
1706
1707
1708
1709
1710
1711
1712

1713
1714
1715
1716
1717
1718
1719
      pTab = pIdx->pTable;
      sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
      for(i=0; i<pIdx->nColumn; i++){
        int cnum = pIdx->aiColumn[i];
        sqliteVdbeAddOp(v, OP_Integer, i, 0);
        sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
        sqliteVdbeAddOp(v, OP_String, 0, 0);

        sqliteVdbeChangeP3(v, -1, pTab->aCol[cnum].zName, P3_STATIC);
        sqliteVdbeAddOp(v, OP_Callback, 3, 0);
      }
    }
  }else

  if( sqliteStrICmp(zLeft, "index_list")==0 ){







>







1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
      pTab = pIdx->pTable;
      sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
      for(i=0; i<pIdx->nColumn; i++){
        int cnum = pIdx->aiColumn[i];
        sqliteVdbeAddOp(v, OP_Integer, i, 0);
        sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        assert( pTab->nCol>cnum );
        sqliteVdbeChangeP3(v, -1, pTab->aCol[cnum].zName, P3_STATIC);
        sqliteVdbeAddOp(v, OP_Callback, 3, 0);
      }
    }
  }else

  if( sqliteStrICmp(zLeft, "index_list")==0 ){
Changes to src/delete.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.28 2002/03/02 17:04:08 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







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.29 2002/03/03 18:59:40 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
94
95
96
97
98
99
100

101

102
103
104
105
106
107
108
  /* Locate the table which we want to delete.  This table has to be
  ** put in an IdList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an IdList* parameter instead of just a Table* parameger.
  */
  pTabList = sqliteTableTokenToIdList(pParse, pTableName);
  if( pTabList==0 ) goto delete_from_cleanup;

  pTab = pTabList->a[0].pTab;


  /* Resolve the column names in all the expressions.
  */
  base = pParse->nTab++;
  if( pWhere ){
    if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){
      goto delete_from_cleanup;







>

>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  /* Locate the table which we want to delete.  This table has to be
  ** put in an IdList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an IdList* parameter instead of just a Table* parameger.
  */
  pTabList = sqliteTableTokenToIdList(pParse, pTableName);
  if( pTabList==0 ) goto delete_from_cleanup;
  assert( pTabList->nId==1 );
  pTab = pTabList->a[0].pTab;
  assert( pTab->pSelect==0 );  /* This table is not a view */

  /* Resolve the column names in all the expressions.
  */
  base = pParse->nTab++;
  if( pWhere ){
    if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){
      goto delete_from_cleanup;
Changes to src/expr.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.53 2002/03/03 03:42:31 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







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.54 2002/03/03 18:59:41 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
380
381
382
383
384
385
386

387
388
389
390
391
392
393
      z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
      sqliteDequote(z);
      if( z==0 ) return 1;
      for(i=0; i<pTabList->nId; i++){
        int j;
        Table *pTab = pTabList->a[i].pTab;
        if( pTab==0 ) continue;

        for(j=0; j<pTab->nCol; j++){
          if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
            cnt++;
            pExpr->iTable = i + base;
            if( j==pTab->iPKey ){
              /* Substitute the record number for the INTEGER PRIMARY KEY */
              pExpr->iColumn = -1;







>







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
      z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
      sqliteDequote(z);
      if( z==0 ) return 1;
      for(i=0; i<pTabList->nId; i++){
        int j;
        Table *pTab = pTabList->a[i].pTab;
        if( pTab==0 ) continue;
        assert( pTab->nCol>0 );
        for(j=0; j<pTab->nCol; j++){
          if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
            cnt++;
            pExpr->iTable = i + base;
            if( j==pTab->iPKey ){
              /* Substitute the record number for the INTEGER PRIMARY KEY */
              pExpr->iColumn = -1;
455
456
457
458
459
460
461

462
463
464
465
466
467
468
      sqliteDequote(zRight);
      pExpr->iTable = -1;
      for(i=0; i<pTabList->nId; i++){
        int j;
        char *zTab;
        Table *pTab = pTabList->a[i].pTab;
        if( pTab==0 ) continue;

        if( pTabList->a[i].zAlias ){
          zTab = pTabList->a[i].zAlias;
        }else{
          zTab = pTab->zName;
        }
        if( sqliteStrICmp(zTab, zLeft)!=0 ) continue;
        if( 0==(cntTab++) ) pExpr->iTable = i + base;







>







456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
      sqliteDequote(zRight);
      pExpr->iTable = -1;
      for(i=0; i<pTabList->nId; i++){
        int j;
        char *zTab;
        Table *pTab = pTabList->a[i].pTab;
        if( pTab==0 ) continue;
        assert( pTab->nCol>0 );
        if( pTabList->a[i].zAlias ){
          zTab = pTabList->a[i].zAlias;
        }else{
          zTab = pTab->zName;
        }
        if( sqliteStrICmp(zTab, zLeft)!=0 ) continue;
        if( 0==(cntTab++) ) pExpr->iTable = i + base;
Changes to src/insert.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.46 2002/03/02 17:04:08 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.47 2002/03/03 18:59:41 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
59
60
61
62
63
64
65

66
67
68
69
70
71
72
  /* Locate the table into which we will be inserting new information.
  */
  zTab = sqliteTableNameFromToken(pTableName);
  if( zTab==0 ) goto insert_cleanup;
  pTab = sqliteTableNameToTable(pParse, zTab);
  sqliteFree(zTab);
  if( pTab==0 ) goto insert_cleanup;


  /* Allocate a VDBE
  */
  v = sqliteGetVdbe(pParse);
  if( v==0 ) goto insert_cleanup;
  if( pSelect ){
    sqliteBeginMultiWriteOperation(pParse);







>







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  /* Locate the table into which we will be inserting new information.
  */
  zTab = sqliteTableNameFromToken(pTableName);
  if( zTab==0 ) goto insert_cleanup;
  pTab = sqliteTableNameToTable(pParse, zTab);
  sqliteFree(zTab);
  if( pTab==0 ) goto insert_cleanup;
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */

  /* Allocate a VDBE
  */
  v = sqliteGetVdbe(pParse);
  if( v==0 ) goto insert_cleanup;
  if( pSelect ){
    sqliteBeginMultiWriteOperation(pParse);
388
389
390
391
392
393
394

395
396
397
398
399
400
401
  int seenReplace = 0;
  int jumpInst;
  int contAddr;
  int hasTwoRecnos = (isUpdate && recnoChng);

  v = sqliteGetVdbe(pParse);
  assert( v!=0 );

  nCol = pTab->nCol;

  /* Test all NOT NULL constraints.
  */
  for(i=0; i<nCol; i++){
    if( i==pTab->iPKey ){
      /* Fix me: Make sure the INTEGER PRIMARY KEY is not NULL. */







>







389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  int seenReplace = 0;
  int jumpInst;
  int contAddr;
  int hasTwoRecnos = (isUpdate && recnoChng);

  v = sqliteGetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  nCol = pTab->nCol;

  /* Test all NOT NULL constraints.
  */
  for(i=0; i<nCol; i++){
    if( i==pTab->iPKey ){
      /* Fix me: Make sure the INTEGER PRIMARY KEY is not NULL. */
549
550
551
552
553
554
555

556
557
558
559
560
561
562
563
564
565
566
  int i;
  Vdbe *v;
  int nIdx;
  Index *pIdx;

  v = sqliteGetVdbe(pParse);
  assert( v!=0 );

  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
  for(i=nIdx-1; i>=0; i--){
    if( aIdxUsed && aIdxUsed[i]==0 ) continue;
    sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0);
  }
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  sqliteVdbeAddOp(v, OP_PutIntKey, base, 0);
  if( isUpdate && recnoChng ){
    sqliteVdbeAddOp(v, OP_Pop, 1, 0);
  }
}







>











551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  int i;
  Vdbe *v;
  int nIdx;
  Index *pIdx;

  v = sqliteGetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
  for(i=nIdx-1; i>=0; i--){
    if( aIdxUsed && aIdxUsed[i]==0 ) continue;
    sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0);
  }
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  sqliteVdbeAddOp(v, OP_PutIntKey, base, 0);
  if( isUpdate && recnoChng ){
    sqliteVdbeAddOp(v, OP_Pop, 1, 0);
  }
}
Changes to src/select.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.73 2002/03/03 03:03:53 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.74 2002/03/03 18:59:41 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
323
324
325
326
327
328
329

330
331
332
333
334
335
336
  pTab = sqliteMalloc( sizeof(Table) );
  if( pTab==0 ){
    return 0;
  }
  pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0;
  pEList = pSelect->pEList;
  pTab->nCol = pEList->nExpr;

  pTab->aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
  for(i=0; i<pTab->nCol; i++){
    Expr *p;
    if( pEList->a[i].zName ){
      pTab->aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
    }else if( (p=pEList->a[i].pExpr)->span.z && p->span.z[0] ){
      sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0);







>







323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  pTab = sqliteMalloc( sizeof(Table) );
  if( pTab==0 ){
    return 0;
  }
  pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0;
  pEList = pSelect->pEList;
  pTab->nCol = pEList->nExpr;
  assert( pTab->nCol>0 );
  pTab->aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
  for(i=0; i<pTab->nCol; i++){
    Expr *p;
    if( pEList->a[i].zName ){
      pTab->aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
    }else if( (p=pEList->a[i].pExpr)->span.z && p->span.z[0] ){
      sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0);
396
397
398
399
400
401
402



403
404
405
406
407
408
409
      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 = sqliteSelectDup(pTab->pSelect);
      }
    }
  }

  /* For every "*" that occurs in the column list, insert the names of
  ** all columns in all tables.  The parser inserted a special expression







>
>
>







397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
      if( pTab==0 ){
        sqliteSetString(&pParse->zErrMsg, "no such table: ", 
           pTabList->a[i].zName, 0);
        pParse->nErr++;
        return 1;
      }
      if( pTab->pSelect ){
        if( sqliteViewGetColumnNames(pParse, pTab) ){
          return 1;
        }
        pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect);
      }
    }
  }

  /* For every "*" that occurs in the column list, insert the names of
  ** all columns in all tables.  The parser inserted a special expression
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.99 2002/03/03 03:03:53 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.100 2002/03/03 18:59:41 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
179
180
181
182
183
184
185


186
187
188
189
190
191
192
#define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */
#define SQLITE_CountRows      0x00000040  /* Count rows changed by INSERT, */
                                          /*   DELETE, or UPDATE and return */
                                          /*   the count using a callback. */
#define SQLITE_NullCallback   0x00000080  /* Invoke the callback once if the */
                                          /*   result set is empty */
#define SQLITE_ResultDetails  0x00000100  /* Details added to result set */



/*
** Each SQL function is defined by an instance of the following
** structure.  A pointer to this structure is stored in the sqlite.aFunc
** hash table.  When multiple functions have the same name, the hash table
** points to a linked list of these structures.
*/







>
>







179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */
#define SQLITE_CountRows      0x00000040  /* Count rows changed by INSERT, */
                                          /*   DELETE, or UPDATE and return */
                                          /*   the count using a callback. */
#define SQLITE_NullCallback   0x00000080  /* Invoke the callback once if the */
                                          /*   result set is empty */
#define SQLITE_ResultDetails  0x00000100  /* Details added to result set */
#define SQLITE_UnresetViews   0x00000200  /* True if one or more views have */
                                          /*   defined column names */

/*
** Each SQL function is defined by an instance of the following
** structure.  A pointer to this structure is stored in the sqlite.aFunc
** hash table.  When multiple functions have the same name, the hash table
** points to a linked list of these structures.
*/
578
579
580
581
582
583
584


585
586
587
588
589
590
591
void sqliteAddColumn(Parse*,Token*);
void sqliteAddNotNull(Parse*, int);
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);
IdList *sqliteIdListAppend(IdList*, Token*);
void sqliteIdListAddAlias(IdList*, Token*);
void sqliteIdListDelete(IdList*);
void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, int, Token*, Token*);







>
>







580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
void sqliteAddColumn(Parse*,Token*);
void sqliteAddNotNull(Parse*, int);
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*);
int sqliteViewGetColumnNames(Parse*,Table*);
void sqliteViewResetAll(sqlite*);
void sqliteDropTable(Parse*, Token*);
void sqliteDeleteTable(sqlite*, Table*);
void sqliteInsert(Parse*, Token*, ExprList*, Select*, IdList*, int);
IdList *sqliteIdListAppend(IdList*, Token*);
void sqliteIdListAddAlias(IdList*, Token*);
void sqliteIdListDelete(IdList*);
void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, int, Token*, Token*);
Changes to src/update.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.35 2002/03/02 17:04:09 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.36 2002/03/03 18:59:41 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
54
55
56
57
58
59
60

61
62
63
64
65
66
67
  ** put in an IdList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an IdList* parameter instead of just a Table* parameter.
  */
  pTabList = sqliteTableTokenToIdList(pParse, pTableName);
  if( pTabList==0 ) goto update_cleanup;
  pTab = pTabList->a[0].pTab;

  aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
  if( aXRef==0 ) goto update_cleanup;
  for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;

  /* Resolve the column names in all the expressions in both the
  ** WHERE clause and in the new values.  Also find the column index
  ** for each column to be updated in the pChanges array.







>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  ** put in an IdList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an IdList* parameter instead of just a Table* parameter.
  */
  pTabList = sqliteTableTokenToIdList(pParse, pTableName);
  if( pTabList==0 ) goto update_cleanup;
  pTab = pTabList->a[0].pTab;
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
  if( aXRef==0 ) goto update_cleanup;
  for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;

  /* Resolve the column names in all the expressions in both the
  ** WHERE clause and in the new values.  Also find the column index
  ** for each column to be updated in the pChanges array.
Changes to test/view.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2002 February 26
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing VIEW statements.
#
# $Id: view.test,v 1.1 2002/02/27 01:47:12 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test view-1.0 {
  execsql {
    CREATE TABLE t1(a,b,c);
    INSERT INTO t1 VALUES(1,2,3);













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2002 February 26
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing VIEW statements.
#
# $Id: view.test,v 1.2 2002/03/03 18:59:41 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test view-1.0 {
  execsql {
    CREATE TABLE t1(a,b,c);
    INSERT INTO t1 VALUES(1,2,3);
39
40
41
42
43
44
45







46
47
48
49
50
51
52
  }
} {1 {no such table: v1}}
do_test view-1.3 {
  execsql {
    CREATE VIEW v1 AS SELECT a,b FROM t1;
    SELECT * FROM v1 ORDER BY a;
  }







} {1 2 4 5 7 8}
do_test view-1.4 {
  catchsql {
    DROP VIEW v1;
    SELECT * FROM v1 ORDER BY a;
  }
} {1 {no such table: v1}}







>
>
>
>
>
>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  }
} {1 {no such table: v1}}
do_test view-1.3 {
  execsql {
    CREATE VIEW v1 AS SELECT a,b FROM t1;
    SELECT * FROM v1 ORDER BY a;
  }
} {1 2 4 5 7 8}
do_test view-1.3.1 {
  db close
  sqlite db test.db
  execsql {
    SELECT * FROM v1 ORDER BY a;
  }
} {1 2 4 5 7 8}
do_test view-1.4 {
  catchsql {
    DROP VIEW v1;
    SELECT * FROM v1 ORDER BY a;
  }
} {1 {no such table: v1}}
67
68
69
70
71
72
73





74



75
    CREATE TABLE t1(x,a,b,c);
    INSERT INTO t1 VALUES(1,2,3,4);
    INSERT INTO t1 VALUES(4,5,6,7);
    INSERT INTO t1 VALUES(7,8,9,10);
    SELECT * FROM v1 ORDER BY a;
  }
} {2 3 5 6 8 9}









finish_test







>
>
>
>
>
|
>
>
>

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    CREATE TABLE t1(x,a,b,c);
    INSERT INTO t1 VALUES(1,2,3,4);
    INSERT INTO t1 VALUES(4,5,6,7);
    INSERT INTO t1 VALUES(7,8,9,10);
    SELECT * FROM v1 ORDER BY a;
  }
} {2 3 5 6 8 9}
do_test view-1.8 {
  db close
  sqlite db test.db
  execsql {
    SELECT * FROM v1 ORDER BY a;
  }
} {2 3 5 6 8 9}


finish_test