/ Check-in [8a593e9c]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Regression tests now work - except for some changes in error message text. The library is now safe to use for experimental work. (CVS 885)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8a593e9c2d57e758739a7ef54fa40ca6a0071a9a
User & Date: drh 2003-03-27 13:50:00
Context
2003-03-30
00:19
Fix a memory leak in triggers and update tests to show the latest error message text. (CVS 886) check-in: b90d9de3 user: drh tags: trunk
2003-03-27
13:50
Regression tests now work - except for some changes in error message text. The library is now safe to use for experimental work. (CVS 885) check-in: 8a593e9c user: drh tags: trunk
13:01
Fix a segfault in the trigger code. (CVS 884) check-in: 7672914b user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
113
114
115
116
117
118
119

120
121
122
123
124
125
126
127
128
...
129
130
131
132
133
134
135

136
137
138
139
140
141
142
143
144
....
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
....
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.134 2003/03/27 12:51:24 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
................................................................................
** a particular database table given the name
** of that table.  Return NULL if not found.
*/
Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){
  Table *p = 0;
  int i;
  for(i=0; i<db->nDb; i++){

    if( zDatabase!=0 && sqliteStrICmp(zDatabase, db->aDb[i].zName) ) continue;
    p = sqliteHashFind(&db->aDb[i].tblHash, zName, strlen(zName)+1);
    if( p ) break;
  }
  return p;
}

/*
** Locate the in-memory structure that describes 
................................................................................
** a particular index given the name of that index.
** Return NULL if not found.
*/
Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){
  Index *p = 0;
  int i;
  for(i=0; i<db->nDb; i++){

    if( zDb && sqliteStrICmp(zDb, db->aDb[i].zName) ) continue;
    p = sqliteHashFind(&db->aDb[i].idxHash, zName, strlen(zName)+1);
    if( p ) break;
  }
  return p;
}

/*
** Remove the given index from the index hash table, and free
................................................................................

  /*
  ** Find the table that is to be indexed.  Return early if not found.
  */
  if( pTable!=0 ){
    assert( pName!=0 );
    assert( pTable->nSrc==1 );
    pTab =  sqliteTableNameToTable(pParse, 
                 pTable->a[0].zName, pTable->a[0].zDatabase);
  }else{
    assert( pName==0 );
    pTab =  pParse->pNewTable;
  }
  if( pTab==0 || pParse->nErr ) goto exit_create_index;
  if( !isTemp && (pTab->readOnly || pTab->iDb>=2) ){
    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, 
................................................................................
  Index *pIdx;
  char *zFile = 0;
  sqlite *db = pParse->db;


  if( sqlite_malloc_failed  ) goto copy_cleanup;
  assert( pTableName->nSrc==1 );
  pTab = sqliteTableNameToTable(pParse, pTableName->a[0].zName,
                                pTableName->a[0].zDatabase);
  if( pTab==0 ) goto copy_cleanup;
  zFile = sqliteStrNDup(pFilename->z, pFilename->n);
  sqliteDequote(zFile);
  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, zFile)
      || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile) ){
    goto copy_cleanup;
  }
  v = sqliteGetVdbe(pParse);







|







 







>
|
|







 







>
|
|







 







|
<







 







|
<
|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
....
1442
1443
1444
1445
1446
1447
1448
1449

1450
1451
1452
1453
1454
1455
1456
....
1982
1983
1984
1985
1986
1987
1988
1989

1990
1991
1992
1993
1994
1995
1996
1997
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.135 2003/03/27 13:50:00 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
................................................................................
** a particular database table given the name
** of that table.  Return NULL if not found.
*/
Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){
  Table *p = 0;
  int i;
  for(i=0; i<db->nDb; i++){
    int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
    if( zDatabase!=0 && sqliteStrICmp(zDatabase, db->aDb[j].zName) ) continue;
    p = sqliteHashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1);
    if( p ) break;
  }
  return p;
}

/*
** Locate the in-memory structure that describes 
................................................................................
** a particular index given the name of that index.
** Return NULL if not found.
*/
Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){
  Index *p = 0;
  int i;
  for(i=0; i<db->nDb; i++){
    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    if( zDb && sqliteStrICmp(zDb, db->aDb[j].zName) ) continue;
    p = sqliteHashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1);
    if( p ) break;
  }
  return p;
}

/*
** Remove the given index from the index hash table, and free
................................................................................

  /*
  ** Find the table that is to be indexed.  Return early if not found.
  */
  if( pTable!=0 ){
    assert( pName!=0 );
    assert( pTable->nSrc==1 );
    pTab =  sqliteSrcListLookup(pParse, pTable);

  }else{
    assert( pName==0 );
    pTab =  pParse->pNewTable;
  }
  if( pTab==0 || pParse->nErr ) goto exit_create_index;
  if( !isTemp && (pTab->readOnly || pTab->iDb>=2) ){
    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, 
................................................................................
  Index *pIdx;
  char *zFile = 0;
  sqlite *db = pParse->db;


  if( sqlite_malloc_failed  ) goto copy_cleanup;
  assert( pTableName->nSrc==1 );
  pTab = sqliteSrcListLookup(pParse, pTableName);

  if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ) goto copy_cleanup;
  zFile = sqliteStrNDup(pFilename->z, pFilename->n);
  sqliteDequote(zFile);
  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, zFile)
      || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile) ){
    goto copy_cleanup;
  }
  v = sqliteGetVdbe(pParse);

Changes to src/delete.c.

8
9
10
11
12
13
14
15
16
17
18
19
20

21
22
23
24
25

26




27
28
29
30
31
32
33
34




35
36







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
..
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
**    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.48 2003/03/27 12:51:24 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, const char *zDb){

  Table *pTab;




  pTab = sqliteFindTable(pParse->db, zTab, zDb);
  if( pTab==0 ){
    if( zDb==0 || zDb[0]==0 ){
      sqliteSetString(&pParse->zErrMsg, "no such table: ", zTab, 0);
    }else{
      sqliteSetString(&pParse->zErrMsg, "no such table: ", zDb, ".", 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;
}

/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
  Parse *pParse,         /* The parser context */
  SrcList *pTabList,     /* The table from which we should delete things */
................................................................................
  }

  /* Locate the table which we want to delete.  This table has to be
  ** put in an SrcList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an SrcList* parameter instead of just a Table* parameter.
  */
  pTab = pTabList->a[0].pTab = sqliteTableNameToTable(pParse, zTab, zDb);
  if( pTab==0 ){
    goto delete_from_cleanup;
  }
  assert( pTab->pSelect==0 );  /* This table is not a view */
  if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0) ){
    goto delete_from_cleanup;
  }








|



<

>
|
<
|

<
>
|
>
>
>
>
|
|
|
|
|
|
|
|
>
>
>
>
|
|
>
>
>
>
>
>
>


|
<


|

|








 







|
|







8
9
10
11
12
13
14
15
16
17
18

19
20
21

22
23

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65
66
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
**    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.49 2003/03/27 13:50:00 drh Exp $
*/
#include "sqliteInt.h"


/*
** Look up every table that is named in pSrc.  If any table is not found,
** add an error message to pParse->zErrMsg and return NULL.  If all tables

** are found, return a pointer to the last table.
*/

Table *sqliteSrcListLookup(Parse *pParse, SrcList *pSrc){
  Table *pTab = 0;
  int i;
  for(i=0; i<pSrc->nSrc; i++){
    const char *zTab = pSrc->a[i].zName;
    const char *zDb = pSrc->a[i].zDatabase;
    pTab = sqliteFindTable(pParse->db, zTab, zDb);
    if( pTab==0 ){
      if( zDb==0 || zDb[0]==0 ){
        sqliteSetString(&pParse->zErrMsg, "no such table: ", zTab, 0);
      }else{
        sqliteSetString(&pParse->zErrMsg, "no such table: ", zDb, ".", zTab, 0);
      }
      pParse->nErr++;
      break;
    }
    pSrc->a[i].pTab = pTab;
  }
  return pTab;
}

/*
** Check to make sure the given table is writable.  If it is not
** writable, generate an error message and return 1.  If it is
** writable return 0;
*/
int sqliteIsReadOnly(Parse *pParse, Table *pTab){
  if( pTab->readOnly || pTab->pSelect ){
    sqliteSetString(&pParse->zErrMsg, 
      pTab->pSelect ? "view " : "table ", pTab->zName,

      " may not be modified", 0);
    pParse->nErr++;
    return 1;
  }
  return 0;
}

/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
  Parse *pParse,         /* The parser context */
  SrcList *pTabList,     /* The table from which we should delete things */
................................................................................
  }

  /* Locate the table which we want to delete.  This table has to be
  ** put in an SrcList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an SrcList* parameter instead of just a Table* parameter.
  */
  pTab = sqliteSrcListLookup(pParse, pTabList);
  if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ){
    goto delete_from_cleanup;
  }
  assert( pTab->pSelect==0 );  /* This table is not a view */
  if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0) ){
    goto delete_from_cleanup;
  }

Changes to src/insert.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
**    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.75 2003/03/27 12:51:25 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
  ExprList *pList,      /* List of values to be inserted */
  Select *pSelect,      /* A SELECT statement to use as the data source */
  IdList *pColumn,      /* Column names corresponding to IDLIST. */
  int onError           /* How to handle constraint errors */
){
  Table *pTab;          /* The table to insert into */
  char *zTab;           /* Name of the table into which we are inserting */
  char *zDb;            /* Name of the database holding zTab */
  int i, j, idx;        /* Loop counters */
  Vdbe *v;              /* Generate code into this virtual machine */
  Index *pIdx;          /* For looping over indices of the table */
  int nColumn;          /* Number of columns in the data */
  int base;             /* First available cursor */
  int iCont, iBreak;    /* Beginning and end of the loop over srcTab */
  sqlite *db;           /* The main database structure */
................................................................................
  db = pParse->db;

  /* Locate the table into which we will be inserting new information.
  */
  assert( pTabList->nSrc==1 );
  zTab = pTabList->a[0].zName;
  if( zTab==0 ) goto insert_cleanup;
  zDb = pTabList->a[0].zDatabase;
  pTab = sqliteTableNameToTable(pParse, zTab, zDb);
  if( pTab==0 ){
    goto insert_cleanup;
  }
  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0) ){
    goto insert_cleanup;
  }








|







 







<







 







|
<







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
89
90
91
92
93
94
95

96
97
98
99
100
101
102
...
116
117
118
119
120
121
122
123

124
125
126
127
128
129
130
**    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.76 2003/03/27 13:50:00 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
  ExprList *pList,      /* List of values to be inserted */
  Select *pSelect,      /* A SELECT statement to use as the data source */
  IdList *pColumn,      /* Column names corresponding to IDLIST. */
  int onError           /* How to handle constraint errors */
){
  Table *pTab;          /* The table to insert into */
  char *zTab;           /* Name of the table into which we are inserting */

  int i, j, idx;        /* Loop counters */
  Vdbe *v;              /* Generate code into this virtual machine */
  Index *pIdx;          /* For looping over indices of the table */
  int nColumn;          /* Number of columns in the data */
  int base;             /* First available cursor */
  int iCont, iBreak;    /* Beginning and end of the loop over srcTab */
  sqlite *db;           /* The main database structure */
................................................................................
  db = pParse->db;

  /* Locate the table into which we will be inserting new information.
  */
  assert( pTabList->nSrc==1 );
  zTab = pTabList->a[0].zName;
  if( zTab==0 ) goto insert_cleanup;
  pTab = sqliteSrcListLookup(pParse, pTabList);

  if( pTab==0 ){
    goto insert_cleanup;
  }
  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0) ){
    goto insert_cleanup;
  }

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
249
250
251
252
253
254
255







256
257
258
259
260
261
262
...
997
998
999
1000
1001
1002
1003
1004

1005
1006
1007
1008
1009
1010
1011
**    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.165 2003/03/27 12:51:25 drh Exp $
*/
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
................................................................................
#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
  int (*xAuth)(void*,int,const char*,const char*); /* Access Auth function */
  void *pAuthArg;               /* 1st argument to the access auth function */
#endif
};








/*
** Possible values for the sqlite.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_Initialized    0x00000002  /* True after initialization */
#define SQLITE_Interrupt      0x00000004  /* Cancel current operation */
#define SQLITE_InTrans        0x00000008  /* True if in a transaction */
................................................................................
void sqliteAddKeyType(Vdbe*, ExprList*);
void sqliteAddIdxKeyType(Vdbe*, Index*);
int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*);
Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
                        int,int,int);
void sqliteSelectDelete(Select*);
void sqliteSelectUnbind(Select*);
Table *sqliteTableNameToTable(Parse*, const char*, const char*);

void sqliteDeleteFrom(Parse*, SrcList*, Expr*);
void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int, ExprList**);
void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int, int);
void sqliteExprIfFalse(Parse*, Expr*, int, int);







|







 







>
>
>
>
>
>
>







 







|
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
....
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
**    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.166 2003/03/27 13:50:00 drh Exp $
*/
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
................................................................................
#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
  int (*xAuth)(void*,int,const char*,const char*); /* Access Auth function */
  void *pAuthArg;               /* 1st argument to the access auth function */
#endif
};

/*
** The following are the indices of in sqlite.aDb[] of the main database
** file and the file used to store TEMP tables.
*/
#define DB_TMP     0
#define DB_MAIN    1

/*
** Possible values for the sqlite.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_Initialized    0x00000002  /* True after initialization */
#define SQLITE_Interrupt      0x00000004  /* Cancel current operation */
#define SQLITE_InTrans        0x00000008  /* True if in a transaction */
................................................................................
void sqliteAddKeyType(Vdbe*, ExprList*);
void sqliteAddIdxKeyType(Vdbe*, Index*);
int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*);
Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
                        int,int,int);
void sqliteSelectDelete(Select*);
void sqliteSelectUnbind(Select*);
Table *sqliteSrcListLookup(Parse*, SrcList*);
int sqliteIsReadOnly(Parse*, Table*);
void sqliteDeleteFrom(Parse*, SrcList*, Expr*);
void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int, ExprList**);
void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int, int);
void sqliteExprIfFalse(Parse*, Expr*, int, int);

Changes to src/trigger.c.

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
...
352
353
354
355
356
357
358

359
360
361
362
363
364
365
366
367
  ** 2. the table (or view) does exist.
  ** 3. that we are not trying to create a trigger on the sqlite_master table
  ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
  ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
  */
  if( sqlite_malloc_failed ) goto trigger_cleanup;
  assert( pTableName->nSrc==1 );
  tab = sqliteTableNameToTable(pParse, pTableName->a[0].zName,
                                pTableName->a[0].zDatabase);
  if( !tab ){
    goto trigger_cleanup;
  }
  if( tab->iDb>=2 ){
    sqliteSetString(&pParse->zErrMsg, "triggers may not be added to "
       "auxiliary database \"", db->aDb[tab->iDb].zName, "\"", 0);
    pParse->nErr++;
................................................................................

  if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
  assert( pName->nSrc==1 );
  zDb = pName->a[0].zDatabase;
  zName = pName->a[0].zName;
  nName = strlen(zName);
  for(i=0; i<db->nDb; i++){

    if( zDb && sqliteStrICmp(db->aDb[i].zName, zDb) ) continue;
    pTrigger = sqliteHashFind(&(db->aDb[i].trigHash), zName, nName+1);
    if( pTrigger ) break;
  }
  if( !pTrigger ){
    sqliteSetString(&pParse->zErrMsg, "no such trigger: ", zName, 0);
    goto drop_trigger_cleanup;
  }
  assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb );







|
<







 







>
|
|







57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
  ** 2. the table (or view) does exist.
  ** 3. that we are not trying to create a trigger on the sqlite_master table
  ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
  ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
  */
  if( sqlite_malloc_failed ) goto trigger_cleanup;
  assert( pTableName->nSrc==1 );
  tab = sqliteSrcListLookup(pParse, pTableName);

  if( !tab ){
    goto trigger_cleanup;
  }
  if( tab->iDb>=2 ){
    sqliteSetString(&pParse->zErrMsg, "triggers may not be added to "
       "auxiliary database \"", db->aDb[tab->iDb].zName, "\"", 0);
    pParse->nErr++;
................................................................................

  if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
  assert( pName->nSrc==1 );
  zDb = pName->a[0].zDatabase;
  zName = pName->a[0].zName;
  nName = strlen(zName);
  for(i=0; i<db->nDb; i++){
    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue;
    pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1);
    if( pTrigger ) break;
  }
  if( !pTrigger ){
    sqliteSetString(&pParse->zErrMsg, "no such trigger: ", zName, 0);
    goto drop_trigger_cleanup;
  }
  assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb );

Changes to src/update.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
**    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.56 2003/03/27 12:51:25 drh Exp $
*/
#include "sqliteInt.h"

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

  /* Locate the table which we want to update.  This table has to be
  ** put in an SrcList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an SrcList* parameter instead of just a Table* parameter.
  */
  pTab = pTabList->a[0].pTab = sqliteTableNameToTable(pParse, zTab, zDb);
  if( pTab==0 ) goto update_cleanup;
  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;

  /* If there are FOR EACH ROW triggers, allocate temp tables */
  if( row_triggers_exist ){







|







 







|
|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
**    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.57 2003/03/27 13:50:00 drh Exp $
*/
#include "sqliteInt.h"

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

  /* Locate the table which we want to update.  This table has to be
  ** put in an SrcList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an SrcList* parameter instead of just a Table* parameter.
  */
  pTab = sqliteSrcListLookup(pParse, pTabList);
  if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ) goto update_cleanup;
  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;

  /* If there are FOR EACH ROW triggers, allocate temp tables */
  if( row_triggers_exist ){