diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 295 | ||||
-rw-r--r-- | src/delete.c | 13 | ||||
-rw-r--r-- | src/insert.c | 8 | ||||
-rw-r--r-- | src/main.c | 28 | ||||
-rw-r--r-- | src/os.c | 3 | ||||
-rw-r--r-- | src/pager.c | 12 | ||||
-rw-r--r-- | src/parse.y | 9 | ||||
-rw-r--r-- | src/sqliteInt.h | 12 | ||||
-rw-r--r-- | src/tokenize.c | 4 | ||||
-rw-r--r-- | src/update.c | 8 | ||||
-rw-r--r-- | src/vdbe.c | 163 | ||||
-rw-r--r-- | src/vdbe.h | 224 | ||||
-rw-r--r-- | src/where.c | 12 |
13 files changed, 498 insertions, 293 deletions
diff --git a/src/build.c b/src/build.c index e8d213b43..ef59bb03c 100644 --- a/src/build.c +++ b/src/build.c @@ -25,7 +25,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.44 2001/10/06 16:33:03 drh Exp $ +** $Id: build.c,v 1.45 2001/10/08 13:22:32 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -65,7 +65,9 @@ void sqliteExec(Parse *pParse){ } /* -** Construct a new expression node and return a pointer to it. +** Construct a new expression node and return a pointer to it. Memory +** for this node is obtained from sqliteMalloc(). The calling function +** is responsible for making sure the node eventually gets freed. */ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){ Expr *pNew; @@ -131,8 +133,8 @@ void sqliteExprDelete(Expr *p){ } /* -** Locate the in-memory structure that describes the -** format of a particular database table given the name +** Locate the in-memory structure that describes +** a particular database table given the name ** of that table. Return NULL if not found. */ Table *sqliteFindTable(sqlite *db, char *zName){ @@ -141,9 +143,9 @@ Table *sqliteFindTable(sqlite *db, char *zName){ } /* -** Locate the in-memory structure that describes the -** format of a particular index given the name -** of that index. Return NULL if not found. +** 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, char *zName){ Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1); @@ -155,7 +157,7 @@ Index *sqliteFindIndex(sqlite *db, char *zName){ ** its memory structures. ** ** The index is removed from the database hash table if db!=NULL. -** But it is not unlinked from the Table that is being indexed. +** But the index is not unlinked from the Table that it indexes. ** Unlinking from the Table must be done by the calling function. */ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){ @@ -167,7 +169,7 @@ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){ /* ** Unlink the given index from its table, then remove -** the index from the index hash table, and free its memory +** the index from the index hash table and free its memory ** structures. */ static void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){ @@ -276,7 +278,7 @@ void sqliteCommitInternalChanges(sqlite *db){ /* ** This routine runs when one or more CREATE TABLE, CREATE INDEX, -** DROP TABLE, or DROP INDEX statements get rolled back. The +** DROP TABLE, or DROP INDEX statements gets rolled back. The ** additions or deletions of Table and Index structures in the ** internal hash tables are undone. ** @@ -334,14 +336,19 @@ char *sqliteTableNameFromToken(Token *pName){ ** the first of several action routines that get called in response ** to a CREATE TABLE statement. In particular, this routine is called ** after seeing tokens "CREATE" and "TABLE" and the table name. The -** pStart token is the CREATE and pName is the table name. +** pStart token is the CREATE and pName is the table name. The isTemp +** flag is true if the "TEMP" or "TEMPORARY" keyword occurs in between +** CREATE and TABLE. ** -** The new table is constructed in fields of the pParse structure. As -** more of the CREATE TABLE statement is parsed, additional action -** routines are called to build up more of the table. +** The new table record is initialized and put in pParse->pNewTable. +** As more of the CREATE TABLE statement is parsed, additional action +** routines will be called to add more information to this record. +** At the end of the CREATE TABLE statement, the sqliteEndTable() routine +** is called to complete the construction of the new table record. */ -void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ +void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){ Table *pTable; + Index *pIdx; char *zName; sqlite *db = pParse->db; Vdbe *v; @@ -349,15 +356,54 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ pParse->sFirstToken = *pStart; zName = sqliteTableNameFromToken(pName); if( zName==0 ) return; + + /* Before trying to create a temporary table, make sure the Btree for + ** holding temporary tables is open. + */ + if( isTemp && db->pBeTemp==0 ){ + int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->pBeTemp); + if( rc!=SQLITE_OK ){ + sqliteSetNString(&pParse->zErrMsg, "unable to open a temporary database " + "file for storing temporary tables", 0); + pParse->nErr++; + return; + } + if( db->flags & SQLITE_InTrans ){ + rc = sqliteBtreeBeginTrans(db->pBeTemp); + if( rc!=SQLITE_OK ){ + sqliteSetNString(&pParse->zErrMsg, "unable to get a write lock on " + "the temporary datbase file", 0); + pParse->nErr++; + return; + } + } + } + + /* Make sure the new table name does not collide with an existing + ** index or table name. Issue an error message if it does. + ** + ** If we are re-reading the sqlite_master table because of a schema + ** change and a new permanent table is found whose name collides with + ** an existing temporary table, then ignore the new permanent table. + ** We will continue parsing, but the pParse->nameClash flag will be set + ** so we will know to discard the table record once parsing has finished. + */ pTable = sqliteFindTable(db, zName); if( pTable!=0 ){ - sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, - " already exists", 0, 0); - sqliteFree(zName); - pParse->nErr++; - return; + if( pTable->isTemp && pParse->initFlag ){ + pParse->nameClash = 1; + }else{ + sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, + " already exists", 0, 0); + sqliteFree(zName); + pParse->nErr++; + return; + } + }else{ + pParse->nameClash = 0; } - if( sqliteFindIndex(db, zName) ){ + if( (pIdx = sqliteFindIndex(db, zName))!=0 && + (!pIdx->pTable->isTemp || !pParse->initFlag) ){ sqliteSetString(&pParse->zErrMsg, "there is already an index named ", zName, 0); sqliteFree(zName); @@ -370,6 +416,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ pTable->nCol = 0; pTable->aCol = 0; pTable->pIndex = 0; + pTable->isTemp = isTemp; if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ @@ -378,7 +425,9 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); pParse->schemaVerified = 1; } - sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0); + if( !isTemp ){ + sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0); + } } } @@ -418,7 +467,7 @@ void sqliteAddNotNull(Parse *pParse){ int i; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; - p->aCol[i].notNull = 1; + if( i>=0 ) p->aCol[i].notNull = 1; } /* @@ -437,10 +486,12 @@ void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){ char *z, **pz; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; + if( i<0 ) return; pz = &p->aCol[i].zType; n = pLast->n + ((int)pLast->z) - (int)pFirst->z; sqliteSetNString(pz, pFirst->z, n, 0); z = *pz; + if( z==0 ) return; for(i=j=0; z[i]; i++){ int c = z[i]; if( isspace(c) ) continue; @@ -463,6 +514,7 @@ void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){ char **pz; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; + if( i<0 ) return; pz = &p->aCol[i].zDflt; if( minusFlag ){ sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0); @@ -500,13 +552,16 @@ static void changeCookie(sqlite *db){ ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. ** -** The table structure is added to the internal hash tables. +** The table structure that other action routines have been building +** is added to the internal hash tables, assuming no errors have +** occurred. ** ** An entry for the table is made in the master table on disk, -** unless initFlag==1. When initFlag==1, it means we are reading -** the master table because we just connected to the database, so -** the entry for this table already exists in the master table. -** We do not want to create it again. +** unless this is a temporary table or initFlag==1. When initFlag==1, +** it means we are reading the sqlite_master table because we just +** connected to the database or because the sqlite_master table has +** recently changes, so the entry for this table already exists in +** the sqlite_master table. We do not want to create it again. */ void sqliteEndTable(Parse *pParse, Token *pEnd){ Table *p; @@ -516,9 +571,10 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){ p = pParse->pNewTable; if( p==0 ) return; - /* Add the table to the in-memory representation of the database + /* Add the table to the in-memory representation of the database. */ - if( pParse->explain==0 ){ + assert( pParse->nameClash==0 || pParse->initFlag==0 ); + if( pParse->explain==0 && pParse->nameClash==0 ){ sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p); pParse->pNewTable = 0; db->nTable++; @@ -537,6 +593,9 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){ /* If not initializing, then create a record for the new table ** in the SQLITE_MASTER table of the database. + ** + ** If this is a TEMPORARY table, then just create the table. Do not + ** make an entry in SQLITE_MASTER. */ if( !pParse->initFlag ){ int n, addr; @@ -545,20 +604,24 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){ v = sqliteGetVdbe(pParse); if( v==0 ) return; n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1; - sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0); - sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0); - sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0); - sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0); + if( !p->isTemp ){ + sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0); + sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0); + } addr = sqliteVdbeAddOp(v, OP_CreateTable, 0, 0, 0, 0); sqliteVdbeChangeP3(v, addr, (char *)&p->tnum, -1); p->tnum = 0; - addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0); - sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n); - sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0); - sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0); - changeCookie(db); - sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0); - sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); + if( !p->isTemp ){ + addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0); + sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n); + sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0); + changeCookie(db); + sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); + } if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } @@ -619,8 +682,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){ { OP_Ne, 0, ADDR(3), 0}, { OP_Delete, 0, 0, 0}, { OP_Goto, 0, ADDR(3), 0}, - { OP_Destroy, 0, 0, 0}, /* 9 */ - { OP_SetCookie, 0, 0, 0}, /* 10 */ + { OP_SetCookie, 0, 0, 0}, /* 9 */ { OP_Close, 0, 0, 0}, }; Index *pIdx; @@ -629,13 +691,15 @@ void sqliteDropTable(Parse *pParse, Token *pName){ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); pParse->schemaVerified = 1; } - base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); - sqliteVdbeChangeP3(v, base+2, pTable->zName, 0); - sqliteVdbeChangeP1(v, base+9, pTable->tnum); - changeCookie(db); - sqliteVdbeChangeP1(v, base+10, db->next_cookie); + if( !pTable->isTemp ){ + base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); + sqliteVdbeChangeP3(v, base+2, pTable->zName, 0); + changeCookie(db); + sqliteVdbeChangeP1(v, base+9, db->next_cookie); + } + sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->isTemp, 0, 0); for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ - sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->isTemp, 0, 0); } if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); @@ -679,8 +743,9 @@ void sqliteCreateIndex( Index *pIndex; /* The index to be created */ char *zName = 0; int i, j; - Token nullId; /* Fake token for an empty ID list */ + Token nullId; /* Fake token for an empty ID list */ sqlite *db = pParse->db; + int hideName = 0; /* Do not put table name in the hash table */ if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; @@ -702,26 +767,56 @@ void sqliteCreateIndex( goto exit_create_index; } + /* If this index is created while re-reading the schema from sqlite_master + ** but the table associated with this index is a temporary table, it can + ** only mean that the table this index is really associated with is one + ** whose name is hidden behind a temporary table with the same name. + ** Since its table has been suppressed, we need to also suppress the + ** index. + */ + if( pParse->initFlag && pTab->isTemp ){ + goto exit_create_index; + } + /* ** Find the name of the index. Make sure there is not already another - ** index or table with the same name. If pName==0 it means that we are + ** index or table with the same name. + ** + ** Exception: If we are reading the names of permanent indices from the + ** sqlite_master table (because some other process changed the schema) and + ** one of the index names collides with the name of a temporary table or + ** index, then we will continue to process this index, but we will not + ** store its name in the hash table. Set the hideName flag to accomplish + ** this. + ** + ** If pName==0 it means that we are ** dealing with a primary key or UNIQUE constraint. We have to invent our ** own name. */ if( pName ){ + Index *pISameName; /* Another index with the same name */ + Table *pTSameName; /* A table with same name as the index */ zName = sqliteTableNameFromToken(pName); if( zName==0 ) goto exit_create_index; - if( sqliteFindIndex(db, zName) ){ - sqliteSetString(&pParse->zErrMsg, "index ", zName, - " already exists", 0); - pParse->nErr++; - goto exit_create_index; + if( (pISameName = sqliteFindIndex(db, zName))!=0 ){ + if( pISameName->pTable->isTemp && pParse->initFlag ){ + hideName = 1; + }else{ + sqliteSetString(&pParse->zErrMsg, "index ", zName, + " already exists", 0); + pParse->nErr++; + goto exit_create_index; + } } - if( sqliteFindTable(db, zName) ){ - sqliteSetString(&pParse->zErrMsg, "there is already a table named ", - zName, 0); - pParse->nErr++; - goto exit_create_index; + if( (pTSameName = sqliteFindTable(db, zName))!=0 ){ + if( pTSameName->isTemp && pParse->initFlag ){ + hideName = 1; + }else{ + sqliteSetString(&pParse->zErrMsg, "there is already a table named ", + zName, 0); + pParse->nErr++; + goto exit_create_index; + } } }else{ char zBuf[30]; @@ -781,7 +876,7 @@ void sqliteCreateIndex( */ pIndex->pNext = pTab->pIndex; pTab->pIndex = pIndex; - if( !pParse->explain ){ + if( !pParse->explain && !hideName ){ sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex); db->flags |= SQLITE_InternChanges; } @@ -815,6 +910,7 @@ void sqliteCreateIndex( int lbl1, lbl2; int i; int addr; + int isTemp = pTab->isTemp; v = sqliteGetVdbe(pParse); if( v==0 ) goto exit_create_index; @@ -824,28 +920,39 @@ void sqliteCreateIndex( sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); pParse->schemaVerified = 1; } - sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0); + if( !isTemp ){ + sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0); + } } - sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0); - sqliteVdbeAddOp(v, OP_String, 0, 0, "index", 0); - sqliteVdbeAddOp(v, OP_String, 0, 0, pIndex->zName, 0); - sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->zName, 0); - addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0); + if( !isTemp ){ + sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0, "index", 0); + sqliteVdbeAddOp(v, OP_String, 0, 0, pIndex->zName, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->zName, 0); + } + addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp, 0, 0); sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, -1); pIndex->tnum = 0; if( pTable ){ - sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); - sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0, 0, 0); + if( isTemp ){ + sqliteVdbeAddOp(v, OP_OpenWrAux, 1, 0, 0, 0); + }else{ + sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0, 0, 0); + } } - addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0); - if( pStart && pEnd ){ - n = (int)pEnd->z - (int)pStart->z + 1; - sqliteVdbeChangeP3(v, addr, pStart->z, n); + if( !isTemp ){ + addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0); + if( pStart && pEnd ){ + n = (int)pEnd->z - (int)pStart->z + 1; + sqliteVdbeChangeP3(v, addr, pStart->z, n); + } + sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0); } - sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0); - sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0); if( pTable ){ - sqliteVdbeAddOp(v, OP_Open, 2, pTab->tnum, pTab->zName, 0); + sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, + 2, pTab->tnum, pTab->zName, 0); lbl1 = sqliteVdbeMakeLabel(v); lbl2 = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, 2, 0, 0, 0); @@ -859,12 +966,14 @@ void sqliteCreateIndex( sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2); sqliteVdbeAddOp(v, OP_Close, 2, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0); } - sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0); if( pTable!=0 ){ - changeCookie(db); - sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0); - sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); + if( !isTemp ){ + changeCookie(db); + sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); + } if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } @@ -916,17 +1025,20 @@ void sqliteDropIndex(Parse *pParse, Token *pName){ { OP_Close, 0, 0, 0}, }; int base; + Table *pTab = pIndex->pTable; if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); pParse->schemaVerified = 1; } - base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); - sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0); - sqliteVdbeChangeP1(v, base+8, pIndex->tnum); - changeCookie(db); - sqliteVdbeChangeP1(v, base+9, db->next_cookie); + if( !pTab->isTemp ){ + base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); + sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0); + changeCookie(db); + sqliteVdbeChangeP1(v, base+9, db->next_cookie); + } + sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp, 0, 0); if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } @@ -1091,6 +1203,7 @@ void sqliteCopy( } v = sqliteGetVdbe(pParse); if( v ){ + int openOp; if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); @@ -1099,9 +1212,10 @@ void sqliteCopy( addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0); sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n); sqliteVdbeDequoteP3(v, addr); - sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum, pTab->zName, 0); + openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite; + sqliteVdbeAddOp(v, openOp, 0, pTab->tnum, pTab->zName, 0); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ - sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum, pIdx->zName, 0); + sqliteVdbeAddOp(v, openOp, i, pIdx->tnum, pIdx->zName, 0); } end = sqliteVdbeMakeLabel(v); addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0); @@ -1374,6 +1488,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ }else #endif - if( zLeft ) sqliteFree(zLeft); - if( zRight ) sqliteFree(zRight); + {} + sqliteFree(zLeft); + sqliteFree(zRight); } diff --git a/src/delete.c b/src/delete.c index 120295b5f..6b02eb59a 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.15 2001/09/23 02:35:53 drh Exp $ +** $Id: delete.c,v 1.16 2001/10/08 13:22:32 drh Exp $ */ #include "sqliteInt.h" @@ -91,9 +91,9 @@ void sqliteDeleteFrom( ** It is easier just to erase the whole table. */ if( pWhere==0 ){ - sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->isTemp, 0, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pTab->isTemp, 0, 0); } } @@ -101,6 +101,8 @@ void sqliteDeleteFrom( ** the table an pick which records to delete. */ else{ + int openOp; + /* Begin the database scan */ sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0); @@ -121,9 +123,10 @@ void sqliteDeleteFrom( */ base = pParse->nTab; sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); - sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, 0, 0); + openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite; + sqliteVdbeAddOp(v, openOp, base, pTab->tnum, 0, 0); for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ - sqliteVdbeAddOp(v, OP_OpenWrite, base+i, pIdx->tnum, 0, 0); + sqliteVdbeAddOp(v, openOp, base+i, pIdx->tnum, 0, 0); } end = sqliteVdbeMakeLabel(v); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0); diff --git a/src/insert.c b/src/insert.c index 9529a1f9f..711f8eb94 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.21 2001/10/06 16:33:03 drh Exp $ +** $Id: insert.c,v 1.22 2001/10/08 13:22:33 drh Exp $ */ #include "sqliteInt.h" @@ -48,6 +48,7 @@ void sqliteInsert( int base; /* First available cursor */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */ sqlite *db; /* The main database structure */ + int openOp; /* Opcode used to open cursors */ if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; db = pParse->db; @@ -155,9 +156,10 @@ void sqliteInsert( ** all indices of that table. */ base = pParse->nTab; - sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, 0); + openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite; + sqliteVdbeAddOp(v, openOp, base, pTab->tnum, pTab->zName, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ - sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum, pIdx->zName, 0); + sqliteVdbeAddOp(v, openOp, idx+base, pIdx->tnum, pIdx->zName, 0); } /* If the data source is a SELECT statement, then we have to create diff --git a/src/main.c b/src/main.c index d96aad914..184c49ff7 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.43 2001/10/06 16:33:03 drh Exp $ +** $Id: main.c,v 1.44 2001/10/08 13:22:33 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -309,7 +309,9 @@ no_mem_on_open: } /* -** Erase all schema information from the schema hash table. +** Erase all schema information from the schema hash table. Except +** tables that are created using CREATE TEMPORARY TABLE are preserved +** if the preserverTemps flag is true. ** ** The database schema is normally read in once when the database ** is first opened and stored in a hash table in the sqlite structure. @@ -317,15 +319,24 @@ no_mem_on_open: ** either the database is being closed or because some other process ** changed the schema and this process needs to reread it. */ -static void clearHashTable(sqlite *db){ +static void clearHashTable(sqlite *db, int preserveTemps){ HashElem *pElem; Hash temp1; temp1 = db->tblHash; sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0); sqliteHashClear(&db->idxHash); for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ - Table *pTbl = sqliteHashData(pElem); - sqliteDeleteTable(db, pTbl); + Table *pTab = sqliteHashData(pElem); + if( preserveTemps && pTab->isTemp ){ + Index *pIdx; + sqliteHashInsert(&db->tblHash, pTab->zName, strlen(pTab->zName)+1, pTab); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int n = strlen(pIdx->zName)+1; + sqliteHashInsert(&db->idxHash, pIdx->zName, n, pIdx); + } + }else{ + sqliteDeleteTable(db, pTab); + } } sqliteHashClear(&temp1); db->flags &= ~SQLITE_Initialized; @@ -336,7 +347,10 @@ static void clearHashTable(sqlite *db){ */ void sqlite_close(sqlite *db){ sqliteBtreeClose(db->pBe); - clearHashTable(db); + clearHashTable(db, 0); + if( db->pBeTemp ){ + sqliteBtreeClose(db->pBeTemp); + } sqliteFree(db); } @@ -429,7 +443,7 @@ int sqlite_exec( } sqliteStrRealloc(pzErrMsg); if( sParse.rc==SQLITE_SCHEMA ){ - clearHashTable(db); + clearHashTable(db, 1); } return sParse.rc; } @@ -397,6 +397,9 @@ int sqliteOsLock(OsFile id, int wrlock){ lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; rc = fcntl(id, F_SETLK, &lock); + if( rc ){ + fcntl(id, F_GETLK, &lock); /* For debugging */ + } return rc==0 ? SQLITE_OK : SQLITE_BUSY; #endif #if OS_WIN diff --git a/src/pager.c b/src/pager.c index 6bb71efc7..4584ffdb2 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.25 2001/10/06 16:33:03 drh Exp $ +** @(#) $Id: pager.c,v 1.26 2001/10/08 13:22:33 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -640,12 +640,16 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ /* If a journal file exists, try to play it back. */ if( sqliteOsFileExists(pPager->zJournal) ){ - int rc; + int rc, dummy; /* Open the journal for exclusive access. Return SQLITE_BUSY if - ** we cannot get exclusive access to the journal file + ** we cannot get exclusive access to the journal file. + ** + ** Even though we will only be reading from the journal, not writing, + ** we have to open the journal for writing in order to obtain an + ** exclusive access lock. */ - rc = sqliteOsOpenReadOnly(pPager->zJournal, &pPager->jfd); + rc = sqliteOsOpenReadWrite(pPager->zJournal, &pPager->jfd, &dummy); if( rc==SQLITE_OK ){ pPager->journalOpen = 1; } diff --git a/src/parse.y b/src/parse.y index 56e6af75a..a190751e0 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.34 2001/10/06 16:33:03 drh Exp $ +** @(#) $Id: parse.y,v 1.35 2001/10/08 13:22:33 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -62,7 +62,11 @@ cmd ::= ROLLBACK trans_opt. {sqliteRollbackTransaction(pParse);} ///////////////////// The CREATE TABLE statement //////////////////////////// // cmd ::= create_table create_table_args. -create_table ::= CREATE(X) TABLE ids(Y). {sqliteStartTable(pParse,&X,&Y);} +create_table ::= CREATE(X) temp(T) TABLE ids(Y). + {sqliteStartTable(pParse,&X,&Y,T);} +%type temp {int} +temp(A) ::= TEMP. {A = 1;} +temp(A) ::= . {A = 0;} create_table_args ::= LP columnlist conslist_opt RP(X). {sqliteEndTable(pParse,&X);} columnlist ::= columnlist COMMA column. @@ -91,6 +95,7 @@ id(A) ::= END(X). {A = X;} id(A) ::= PRAGMA(X). {A = X;} id(A) ::= CLUSTER(X). {A = X;} id(A) ::= ID(X). {A = X;} +id(A) ::= TEMP(X). {A = X;} // And "ids" is an identifer-or-string. // diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 59f0a2557..90c1869c8 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.57 2001/10/06 16:33:03 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.58 2001/10/08 13:22:33 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -139,6 +139,7 @@ typedef struct AggExpr AggExpr; */ struct sqlite { Btree *pBe; /* The B*Tree backend */ + Btree *pBeTemp; /* Backend for session temporary tables */ int flags; /* Miscellanous flags. See below */ int file_format; /* What file format version is this database? */ int schema_cookie; /* Magic number that changes with the schema */ @@ -195,6 +196,7 @@ struct Table { u8 readOnly; /* True if this table should not be written by the user */ u8 isCommit; /* True if creation of this table has been committed */ u8 isDelete; /* True if this table is being deleted */ + u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */ }; /* @@ -355,7 +357,9 @@ struct AggExpr { }; /* -** An SQL parser context +** An SQL parser context. A copy of this structure is passed through +** the parser and down into all the parser action routine in order to +** carry around information that is global to the entire parse. */ struct Parse { sqlite *db; /* The main database structure */ @@ -372,8 +376,8 @@ struct Parse { int colNamesSet; /* TRUE after OP_ColumnCount has been issued to pVdbe */ int explain; /* True if the EXPLAIN flag is found on the query */ int initFlag; /* True if reparsing CREATE TABLEs */ + int nameClash; /* A permanent table name clashes with temp table name */ int newTnum; /* Table number to use when reparsing CREATE TABLEs */ - int newKnum; /* Primary key number when reparsing CREATE TABLEs */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated cursors */ int nMem; /* Number of memory cells used so far */ @@ -423,7 +427,7 @@ void sqliteExprListDelete(ExprList*); void sqlitePragma(Parse*,Token*,Token*,int); void sqliteCommitInternalChanges(sqlite*); void sqliteRollbackInternalChanges(sqlite*); -void sqliteStartTable(Parse*,Token*,Token*); +void sqliteStartTable(Parse*,Token*,Token*,int); void sqliteAddColumn(Parse*,Token*); void sqliteAddNotNull(Parse*); void sqliteAddColumnType(Parse*,Token*,Token*); diff --git a/src/tokenize.c b/src/tokenize.c index 619ae6ea9..0ad771150 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.24 2001/10/06 16:33:03 drh Exp $ +** $Id: tokenize.c,v 1.25 2001/10/08 13:22:33 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -84,6 +84,8 @@ static Keyword aKeywordTable[] = { { "SELECT", 0, TK_SELECT, 0 }, { "SET", 0, TK_SET, 0 }, { "TABLE", 0, TK_TABLE, 0 }, + { "TEMP", 0, TK_TEMP, 0 }, + { "TEMPORARY", 0, TK_TEMP, 0 }, { "TRANSACTION", 0, TK_TRANSACTION, 0 }, { "UNION", 0, TK_UNION, 0 }, { "UNIQUE", 0, TK_UNIQUE, 0 }, diff --git a/src/update.c b/src/update.c index 164a360c0..db23bb6e8 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.16 2001/09/27 03:22:34 drh Exp $ +** $Id: update.c,v 1.17 2001/10/08 13:22:33 drh Exp $ */ #include "sqliteInt.h" @@ -39,6 +39,7 @@ void sqliteUpdate( int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ + int openOp; /* Opcode used to open tables */ if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; db = pParse->db; @@ -159,9 +160,10 @@ void sqliteUpdate( */ sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); base = pParse->nTab; - sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, 0, 0); + openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite; + sqliteVdbeAddOp(v, openOp, base, pTab->tnum, 0, 0); for(i=0; i<nIdx; i++){ - sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, apIdx[i]->tnum, 0, 0); + sqliteVdbeAddOp(v, openOp, base+i+1, apIdx[i]->tnum, 0, 0); } /* Loop over every record that needs updating. We have to load diff --git a/src/vdbe.c b/src/vdbe.c index 0e2614bcb..63adee761 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.80 2001/10/06 16:33:03 drh Exp $ +** $Id: vdbe.c,v 1.81 2001/10/08 13:22:33 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -793,30 +793,31 @@ void sqliteVdbeDelete(Vdbe *p){ static char *zOpName[] = { 0, "Transaction", "Commit", "Rollback", "ReadCookie", "SetCookie", "VerifyCookie", "Open", "OpenTemp", - "OpenWrite", "Close", "MoveTo", "Fcnt", - "NewRecno", "Put", "Distinct", "Found", - "NotFound", "Delete", "Column", "KeyAsData", - "Recno", "FullKey", "Rewind", "Next", - "Destroy", "Clear", "CreateIndex", "CreateTable", - "Reorganize", "BeginIdx", "NextIdx", "PutIdx", - "DeleteIdx", "MemLoad", "MemStore", "ListOpen", - "ListWrite", "ListRewind", "ListRead", "ListClose", - "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey", - "Sort", "SortNext", "SortKey", "SortCallback", - "SortClose", "FileOpen", "FileRead", "FileColumn", - "FileClose", "AggReset", "AggFocus", "AggIncr", - "AggNext", "AggSet", "AggGet", "SetInsert", - "SetFound", "SetNotFound", "SetClear", "MakeRecord", - "MakeKey", "MakeIdxKey", "Goto", "If", - "Halt", "ColumnCount", "ColumnName", "Callback", - "Integer", "String", "Null", "Pop", - "Dup", "Pull", "Add", "AddImm", - "Subtract", "Multiply", "Divide", "Min", - "Max", "Like", "Glob", "Eq", - "Ne", "Lt", "Le", "Gt", - "Ge", "IsNull", "NotNull", "Negative", - "And", "Or", "Not", "Concat", - "Noop", "Strlen", "Substr", + "OpenWrite", "OpenAux", "OpenWrAux", "Close", + "MoveTo", "Fcnt", "NewRecno", "Put", + "Distinct", "Found", "NotFound", "Delete", + "Column", "KeyAsData", "Recno", "FullKey", + "Rewind", "Next", "Destroy", "Clear", + "CreateIndex", "CreateTable", "Reorganize", "BeginIdx", + "NextIdx", "PutIdx", "DeleteIdx", "MemLoad", + "MemStore", "ListOpen", "ListWrite", "ListRewind", + "ListRead", "ListClose", "SortOpen", "SortPut", + "SortMakeRec", "SortMakeKey", "Sort", "SortNext", + "SortKey", "SortCallback", "SortClose", "FileOpen", + "FileRead", "FileColumn", "FileClose", "AggReset", + "AggFocus", "AggIncr", "AggNext", "AggSet", + "AggGet", "SetInsert", "SetFound", "SetNotFound", + "SetClear", "MakeRecord", "MakeKey", "MakeIdxKey", + "Goto", "If", "Halt", "ColumnCount", + "ColumnName", "Callback", "Integer", "String", + "Null", "Pop", "Dup", "Pull", + "Add", "AddImm", "Subtract", "Multiply", + "Divide", "Min", "Max", "Like", + "Glob", "Eq", "Ne", "Lt", + "Le", "Gt", "Ge", "IsNull", + "NotNull", "Negative", "And", "Or", + "Not", "Concat", "Noop", "Strlen", + "Substr", }; /* @@ -1920,6 +1921,12 @@ case OP_MakeIdxKey: { */ case OP_Transaction: { int busy = 0; + if( db->pBeTemp ){ + rc = sqliteBtreeBeginTrans(db->pBeTemp); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } + } do{ rc = sqliteBtreeBeginTrans(pBt); switch( rc ){ @@ -1951,7 +1958,9 @@ case OP_Transaction: { ** A read lock continues to be held if there are still cursors open. */ case OP_Commit: { - rc = sqliteBtreeCommit(pBt); + if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){ + rc = sqliteBtreeCommit(pBt); + } if( rc==SQLITE_OK ){ sqliteCommitInternalChanges(db); }else{ @@ -1971,6 +1980,9 @@ case OP_Commit: { ** the read and write locks on the database. */ case OP_Rollback: { + if( db->pBeTemp ){ + sqliteBtreeRollback(db->pBeTemp); + } rc = sqliteBtreeRollback(pBt); sqliteRollbackInternalChanges(db); break; @@ -2065,6 +2077,16 @@ case OP_VerifyCookie: { ** The P3 value is not actually used by this opcode and may be ** omitted. But the code generator usually inserts the index or ** table name into P3 to make the code easier to read. +** +** See also OpenAux and OpenWrite. +*/ +/* Opcode: OpenAux P1 P2 P3 +** +** Open a read-only cursor in the auxiliary table set. This opcode +** works exactly like OP_Open except that it opens the cursor on the +** auxiliary table set (the file used to store tables created using +** CREATE TEMPORARY TABLE) instead of in the main database file. +** See OP_Open for additional information. */ /* Opcode: OpenWrite P1 P2 P3 ** @@ -2074,13 +2096,33 @@ case OP_VerifyCookie: { ** This instruction works just like Open except that it opens the cursor ** in read/write mode. For a given table, there can be one or more read-only ** cursors or a single read/write cursor but not both. +** +** See also OpWrAux. +*/ +/* Opcode: OpenWrAux P1 P2 P3 +** +** Open a read/write cursor in the auxiliary table set. This opcode works +** just like OpenWrite except that the auxiliary table set (the file used +** to store tables created using CREATE TEMPORARY TABLE) is used in place +** of the main database file. */ +case OP_OpenAux: +case OP_OpenWrAux: case OP_OpenWrite: case OP_Open: { int busy = 0; int i = pOp->p1; int tos = p->tos; int p2 = pOp->p2; + int wrFlag; + Btree *pX; + switch( pOp->opcode ){ + case OP_Open: wrFlag = 0; pX = pBt; break; + case OP_OpenWrite: wrFlag = 1; pX = pBt; break; + case OP_OpenAux: wrFlag = 0; pX = db->pBeTemp; break; + case OP_OpenWrAux: wrFlag = 1; pX = db->pBeTemp; break; + } + assert( pX!=0 ); if( p2<=0 ){ if( tos<0 ) goto not_enough_stack; Integerify(p, tos); @@ -2105,8 +2147,7 @@ case OP_Open: { cleanupCursor(&p->aCsr[i]); memset(&p->aCsr[i], 0, sizeof(Cursor)); do{ - int wrFlag = pOp->opcode==OP_OpenWrite; - rc = sqliteBtreeCursor(pBt, p2, wrFlag, &p->aCsr[i].pCursor); + rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor); switch( rc ){ case SQLITE_BUSY: { if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){ @@ -2133,6 +2174,13 @@ case OP_Open: { ** file. The temporary file is opened read/write even if the main ** database is read-only. The temporary file is deleted when the ** cursor is closed. +** +** This opcode is used for tables that exist for the duration of a single +** SQL statement only. Tables created using CREATE TEMPORARY TABLE +** are opened using OP_OpenAux or OP_OpenWrAux. "Temporary" in the +** context of this opcode means for the duration of a single SQL statement +** whereas "Temporary" in the context of CREATE TABLE means for the duration +** of the connection to the database. Same word; different meanings. */ case OP_OpenTemp: { int i = pOp->p1; @@ -2765,34 +2813,43 @@ case OP_DeleteIdx: { break; } -/* Opcode: Destroy P1 * * +/* Opcode: Destroy P1 P2 * ** ** Delete an entire database table or index whose root page in the database ** file is given by P1. ** +** The table being destroyed is in the main database file if P2==0. If +** P2==1 then the table to be clear is in the auxiliary database file +** that is used to store tables create using CREATE TEMPORARY TABLE. +** ** See also: Clear */ case OP_Destroy: { - sqliteBtreeDropTable(pBt, pOp->p1); + sqliteBtreeDropTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1); break; } -/* Opcode: Clear P1 * * +/* Opcode: Clear P1 P2 * ** ** Delete all contents of the database table or index whose root page ** in the database file is given by P1. But, unlike Destroy, do not ** remove the table or index from the database file. ** +** The table being clear is in the main database file if P2==0. If +** P2==1 then the table to be clear is in the auxiliary database file +** that is used to store tables create using CREATE TEMPORARY TABLE. +** ** See also: Destroy */ case OP_Clear: { - sqliteBtreeClearTable(pBt, pOp->p1); + sqliteBtreeClearTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1); break; } -/* Opcode: CreateTable * * P3 +/* Opcode: CreateTable * P2 P3 ** -** Allocate a new table in the main database file. Push the page number +** Allocate a new table in the main database file if P2==0 or in the +** auxiliary database file if P2==1. Push the page number ** for the root page of the new table onto the stack. ** ** The root page number is also written to a memory location that P3 @@ -2802,39 +2859,20 @@ case OP_Clear: { ** ** See also: CreateIndex */ -case OP_CreateTable: { - int i = ++p->tos; - int pgno; - VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) - assert( pOp->p3!=0 && pOp->p3dyn==0 ); - rc = sqliteBtreeCreateTable(pBt, &pgno); - if( rc==SQLITE_OK ){ - aStack[i].i = pgno; - aStack[i].flags = STK_Int; - *(u32*)pOp->p3 = pgno; - pOp->p3 = 0; - } - break; -} - -/* Opcode: CreateIndex * * P3 +/* Opcode: CreateIndex * P2 P3 ** -** Allocate a new Index in the main database file. Push the page number -** for the root page of the new table onto the stack. -** -** The root page number is also written to a memory location that P3 -** points to. This is the mechanism is used to write the root page -** number into the parser's internal data structures that describe the -** new index. +** This instruction does exactly the same thing as CreateTable. It +** has a different name for historical reasons. ** ** See also: CreateTable */ -case OP_CreateIndex: { +case OP_CreateIndex: +case OP_CreateTable: { int i = ++p->tos; int pgno; VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) assert( pOp->p3!=0 && pOp->p3dyn==0 ); - rc = sqliteBtreeCreateTable(pBt, &pgno); + rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno); if( rc==SQLITE_OK ){ aStack[i].i = pgno; aStack[i].flags = STK_Int; @@ -3164,6 +3202,7 @@ case OP_SortNext: { break; } +#if 0 /* NOT USED */ /* Opcode: SortKey P1 * * ** ** Push the key for the topmost element of the sorter onto the stack. @@ -3182,6 +3221,7 @@ case OP_SortKey: { } break; } +#endif /* NOT USED */ /* Opcode: SortCallback P1 P2 * ** @@ -3245,6 +3285,7 @@ case OP_FileOpen: { break; } +#if 0 /* NOT USED */ /* Opcode: FileClose * * * ** ** Close a file previously opened using FileOpen. This is a no-op @@ -3267,6 +3308,7 @@ case OP_FileClose: { p->nLineAlloc = 0; break; } +#endif /* Opcode: FileRead P1 P2 P3 ** @@ -3597,6 +3639,7 @@ case OP_AggNext: { break; } +#if 0 /* NOT USED */ /* Opcode: SetClear P1 * * ** ** Remove all elements from the P1-th Set. @@ -3608,6 +3651,7 @@ case OP_SetClear: { } break; } +#endif /* NOT USED */ /* Opcode: SetInsert P1 * P3 ** @@ -3874,6 +3918,7 @@ cleanup: if( rc!=SQLITE_OK ){ closeAllCursors(p); sqliteBtreeRollback(pBt); + if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp); sqliteRollbackInternalChanges(db); db->flags &= ~SQLITE_InTrans; } diff --git a/src/vdbe.h b/src/vdbe.h index 211d6ede5..b1fde29cb 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.25 2001/09/27 15:11:55 drh Exp $ +** $Id: vdbe.h,v 1.26 2001/10/08 13:22:33 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -71,116 +71,118 @@ typedef struct VdbeOp VdbeOp; #define OP_Open 7 #define OP_OpenTemp 8 #define OP_OpenWrite 9 -#define OP_Close 10 -#define OP_MoveTo 11 -#define OP_Fcnt 12 -#define OP_NewRecno 13 -#define OP_Put 14 -#define OP_Distinct 15 -#define OP_Found 16 -#define OP_NotFound 17 -#define OP_Delete 18 -#define OP_Column 19 -#define OP_KeyAsData 20 -#define OP_Recno 21 -#define OP_FullKey 22 -#define OP_Rewind 23 -#define OP_Next 24 - -#define OP_Destroy 25 -#define OP_Clear 26 -#define OP_CreateIndex 27 -#define OP_CreateTable 28 -#define OP_Reorganize 29 - -#define OP_BeginIdx 30 -#define OP_NextIdx 31 -#define OP_PutIdx 32 -#define OP_DeleteIdx 33 - -#define OP_MemLoad 34 -#define OP_MemStore 35 - -#define OP_ListOpen 36 -#define OP_ListWrite 37 -#define OP_ListRewind 38 -#define OP_ListRead 39 -#define OP_ListClose 40 - -#define OP_SortOpen 41 -#define OP_SortPut 42 -#define OP_SortMakeRec 43 -#define OP_SortMakeKey 44 -#define OP_Sort 45 -#define OP_SortNext 46 -#define OP_SortKey 47 -#define OP_SortCallback 48 -#define OP_SortClose 49 - -#define OP_FileOpen 50 -#define OP_FileRead 51 -#define OP_FileColumn 52 -#define OP_FileClose 53 - -#define OP_AggReset 54 -#define OP_AggFocus 55 -#define OP_AggIncr 56 -#define OP_AggNext 57 -#define OP_AggSet 58 -#define OP_AggGet 59 - -#define OP_SetInsert 60 -#define OP_SetFound 61 -#define OP_SetNotFound 62 -#define OP_SetClear 63 - -#define OP_MakeRecord 64 -#define OP_MakeKey 65 -#define OP_MakeIdxKey 66 - -#define OP_Goto 67 -#define OP_If 68 -#define OP_Halt 69 - -#define OP_ColumnCount 70 -#define OP_ColumnName 71 -#define OP_Callback 72 - -#define OP_Integer 73 -#define OP_String 74 -#define OP_Null 75 -#define OP_Pop 76 -#define OP_Dup 77 -#define OP_Pull 78 - -#define OP_Add 79 -#define OP_AddImm 80 -#define OP_Subtract 81 -#define OP_Multiply 82 -#define OP_Divide 83 -#define OP_Min 84 -#define OP_Max 85 -#define OP_Like 86 -#define OP_Glob 87 -#define OP_Eq 88 -#define OP_Ne 89 -#define OP_Lt 90 -#define OP_Le 91 -#define OP_Gt 92 -#define OP_Ge 93 -#define OP_IsNull 94 -#define OP_NotNull 95 -#define OP_Negative 96 -#define OP_And 97 -#define OP_Or 98 -#define OP_Not 99 -#define OP_Concat 100 -#define OP_Noop 101 - -#define OP_Strlen 102 -#define OP_Substr 103 - -#define OP_MAX 103 +#define OP_OpenAux 10 +#define OP_OpenWrAux 11 +#define OP_Close 12 +#define OP_MoveTo 13 +#define OP_Fcnt 14 +#define OP_NewRecno 15 +#define OP_Put 16 +#define OP_Distinct 17 +#define OP_Found 18 +#define OP_NotFound 19 +#define OP_Delete 20 +#define OP_Column 21 +#define OP_KeyAsData 22 +#define OP_Recno 23 +#define OP_FullKey 24 +#define OP_Rewind 25 +#define OP_Next 26 + +#define OP_Destroy 27 +#define OP_Clear 28 +#define OP_CreateIndex 29 +#define OP_CreateTable 30 +#define OP_Reorganize 31 + +#define OP_BeginIdx 32 +#define OP_NextIdx 33 +#define OP_PutIdx 34 +#define OP_DeleteIdx 35 + +#define OP_MemLoad 36 +#define OP_MemStore 37 + +#define OP_ListOpen 38 +#define OP_ListWrite 39 +#define OP_ListRewind 40 +#define OP_ListRead 41 +#define OP_ListClose 42 + +#define OP_SortOpen 43 +#define OP_SortPut 44 +#define OP_SortMakeRec 45 +#define OP_SortMakeKey 46 +#define OP_Sort 47 +#define OP_SortNext 48 +#define OP_SortKey 49 +#define OP_SortCallback 50 +#define OP_SortClose 51 + +#define OP_FileOpen 52 +#define OP_FileRead 53 +#define OP_FileColumn 54 +#define OP_FileClose 55 + +#define OP_AggReset 56 +#define OP_AggFocus 57 +#define OP_AggIncr 58 +#define OP_AggNext 59 +#define OP_AggSet 60 +#define OP_AggGet 61 + +#define OP_SetInsert 62 +#define OP_SetFound 63 +#define OP_SetNotFound 64 +#define OP_SetClear 65 + +#define OP_MakeRecord 66 +#define OP_MakeKey 67 +#define OP_MakeIdxKey 68 + +#define OP_Goto 69 +#define OP_If 70 +#define OP_Halt 71 + +#define OP_ColumnCount 72 +#define OP_ColumnName 73 +#define OP_Callback 74 + +#define OP_Integer 75 +#define OP_String 76 +#define OP_Null 77 +#define OP_Pop 78 +#define OP_Dup 79 +#define OP_Pull 80 + +#define OP_Add 81 +#define OP_AddImm 82 +#define OP_Subtract 83 +#define OP_Multiply 84 +#define OP_Divide 85 +#define OP_Min 86 +#define OP_Max 87 +#define OP_Like 88 +#define OP_Glob 89 +#define OP_Eq 90 +#define OP_Ne 91 +#define OP_Lt 92 +#define OP_Le 93 +#define OP_Gt 94 +#define OP_Ge 95 +#define OP_IsNull 96 +#define OP_NotNull 97 +#define OP_Negative 98 +#define OP_And 99 +#define OP_Or 100 +#define OP_Not 101 +#define OP_Concat 102 +#define OP_Noop 103 + +#define OP_Strlen 104 +#define OP_Substr 105 + +#define OP_MAX 105 /* ** Prototypes for the VDBE interface. See comments on the implementation diff --git a/src/where.c b/src/where.c index 6105349db..971e20a2c 100644 --- a/src/where.c +++ b/src/where.c @@ -13,7 +13,7 @@ ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** -** $Id: where.c,v 1.21 2001/09/18 02:02:23 drh Exp $ +** $Id: where.c,v 1.22 2001/10/08 13:22:33 drh Exp $ */ #include "sqliteInt.h" @@ -285,15 +285,19 @@ WhereInfo *sqliteWhereBegin( /* Open all tables in the pTabList and all indices in aIdx[]. */ for(i=0; i<pTabList->nId; i++){ - sqliteVdbeAddOp(v, OP_Open, base+i, pTabList->a[i].pTab->tnum, - pTabList->a[i].pTab->zName, 0); + int openOp; + Table *pTab; + + pTab = pTabList->a[i].pTab; + openOp = pTab->isTemp ? OP_OpenAux : OP_Open; + sqliteVdbeAddOp(v, openOp, base+i, pTab->tnum, pTab->zName, 0); if( i==0 && !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0); pParse->schemaVerified = 1; } if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){ - sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, aIdx[i]->tnum, + sqliteVdbeAddOp(v, openOp, base+pTabList->nId+i, aIdx[i]->tnum, aIdx[i]->zName, 0); } } |