Regression tests now work - except for some changes in error message
text.  The library is now safe to use for experimental work. (CVS 885)

FossilOrigin-Name: 8a593e9c2d57e758739a7ef54fa40ca6a0071a9a
diff --git a/src/build.c b/src/build.c
index 4900e92..12f54a5 100644
--- a/src/build.c
+++ b/src/build.c
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.134 2003/03/27 12:51:24 drh Exp $
+** $Id: build.c,v 1.135 2003/03/27 13:50:00 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -117,8 +117,9 @@
   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);
+    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;
@@ -133,8 +134,9 @@
   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);
+    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;
@@ -1444,8 +1446,7 @@
   if( pTable!=0 ){
     assert( pName!=0 );
     assert( pTable->nSrc==1 );
-    pTab =  sqliteTableNameToTable(pParse, 
-                 pTable->a[0].zName, pTable->a[0].zDatabase);
+    pTab =  sqliteSrcListLookup(pParse, pTable);
   }else{
     assert( pName==0 );
     pTab =  pParse->pNewTable;
@@ -1985,9 +1986,8 @@
 
   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;
+  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)
diff --git a/src/delete.c b/src/delete.c
index 770a400..7fc2ddf 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,40 +12,53 @@
 ** 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 $
+** $Id: delete.c,v 1.49 2003/03/27 13:50:00 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.
+** 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 *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);
+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;
     }
-    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;      
+    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(
@@ -101,8 +114,8 @@
   ** 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 ){
+  pTab = sqliteSrcListLookup(pParse, pTabList);
+  if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ){
     goto delete_from_cleanup;
   }
   assert( pTab->pSelect==0 );  /* This table is not a view */
diff --git a/src/insert.c b/src/insert.c
index 14f7824..f9f72f8 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.75 2003/03/27 12:51:25 drh Exp $
+** $Id: insert.c,v 1.76 2003/03/27 13:50:00 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -93,7 +93,6 @@
 ){
   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 */
@@ -121,8 +120,7 @@
   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);
+  pTab = sqliteSrcListLookup(pParse, pTabList);
   if( pTab==0 ){
     goto insert_cleanup;
   }
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 854e255..dcc325f 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.165 2003/03/27 12:51:25 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.166 2003/03/27 13:50:00 drh Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -254,6 +254,13 @@
 };
 
 /*
+** 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 */
@@ -1001,7 +1008,8 @@
                         int,int,int);
 void sqliteSelectDelete(Select*);
 void sqliteSelectUnbind(Select*);
-Table *sqliteTableNameToTable(Parse*, const char*, const char*);
+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**);
diff --git a/src/trigger.c b/src/trigger.c
index c0f0e6c..2b7d35a 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -61,8 +61,7 @@
   */
   if( sqlite_malloc_failed ) goto trigger_cleanup;
   assert( pTableName->nSrc==1 );
-  tab = sqliteTableNameToTable(pParse, pTableName->a[0].zName,
-                                pTableName->a[0].zDatabase);
+  tab = sqliteSrcListLookup(pParse, pTableName);
   if( !tab ){
     goto trigger_cleanup;
   }
@@ -356,8 +355,9 @@
   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);
+    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 ){
diff --git a/src/update.c b/src/update.c
index f76686d..fb06030 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.56 2003/03/27 12:51:25 drh Exp $
+** $Id: update.c,v 1.57 2003/03/27 13:50:00 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -84,8 +84,8 @@
   ** 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;
+  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;