Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -23,11 +23,11 @@ ** BEGIN TRANSACTION ** COMMIT ** 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 /* @@ -115,12 +115,13 @@ */ Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; for(i=0; inDb; 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; } @@ -131,12 +132,13 @@ */ Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){ Index *p = 0; int i; for(i=0; inDb; 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; } @@ -1442,12 +1444,11 @@ ** 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); + pTab = sqliteSrcListLookup(pParse, pTable); }else{ assert( pName==0 ); pTab = pParse->pNewTable; } if( pTab==0 || pParse->nErr ) goto exit_create_index; @@ -1983,13 +1984,12 @@ 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; + 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; Index: src/delete.c ================================================================== --- src/delete.c +++ src/delete.c @@ -10,42 +10,55 @@ ** ************************************************************************* ** 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); - } - 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; +Table *sqliteSrcListLookup(Parse *pParse, SrcList *pSrc){ + Table *pTab = 0; + int i; + for(i=0; inSrc; 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( @@ -99,12 +112,12 @@ /* 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 ){ + 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; Index: src/insert.c ================================================================== --- src/insert.c +++ src/insert.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** 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" /* ** This routine is call to handle SQL of the following forms: @@ -91,11 +91,10 @@ 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 */ @@ -119,12 +118,11 @@ /* 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); + pTab = sqliteSrcListLookup(pParse, pTabList); if( pTab==0 ){ goto insert_cleanup; } if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0) ){ goto insert_cleanup; Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -9,11 +9,11 @@ ** 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 $ +** @(#) $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" @@ -251,10 +251,17 @@ 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 */ @@ -999,11 +1006,12 @@ 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*); +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*); Index: src/trigger.c ================================================================== --- src/trigger.c +++ src/trigger.c @@ -59,12 +59,11 @@ ** 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); + tab = sqliteSrcListLookup(pParse, pTableName); if( !tab ){ goto trigger_cleanup; } if( tab->iDb>=2 ){ sqliteSetString(&pParse->zErrMsg, "triggers may not be added to " @@ -354,12 +353,13 @@ assert( pName->nSrc==1 ); zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; nName = strlen(zName); for(i=0; inDb; 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 ){ sqliteSetString(&pParse->zErrMsg, "no such trigger: ", zName, 0); goto drop_trigger_cleanup; Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** 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" /* ** Process an UPDATE statement. @@ -82,12 +82,12 @@ /* 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; + 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; inCol; i++) aXRef[i] = -1;