]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Support for temporary tables added. Still need more testing. (CVS 279)
authordrh <drh@noemail.net>
Mon, 8 Oct 2001 13:22:32 +0000 (13:22 +0000)
committerdrh <drh@noemail.net>
Mon, 8 Oct 2001 13:22:32 +0000 (13:22 +0000)
FossilOrigin-Name: 9368c62e4097aae3081a325962c1dec167fd253d

18 files changed:
manifest
manifest.uuid
src/build.c
src/delete.c
src/insert.c
src/main.c
src/os.c
src/pager.c
src/parse.y
src/sqliteInt.h
src/tokenize.c
src/update.c
src/vdbe.c
src/vdbe.h
src/where.c
test/temptable.test [new file with mode: 0644]
www/changes.tcl
www/lang.tcl

index ba3a348a84f7fb97358e1b4e586ff13164f13cd4..c99767764f912d9bd0248b2e3ffb9b444115a81f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Adding\stable\scolumn\squery\scapability\sto\ssupport\sODBC.\s(CVS\s278)
-D 2001-10-06T16:33:02
+C Support\sfor\stemporary\stables\sadded.\s\sStill\sneed\smore\stesting.\s(CVS\s279)
+D 2001-10-08T13:22:32
 F Makefile.in 98d4627cb364537e4c3a29ee806171f3abf5211a
 F Makefile.template 1e54087c0390c4ce0bb5be43e14ba028283751e6
 F README 93d2977cc5c6595c448de16bdefc312b9d401533
@@ -21,37 +21,37 @@ F publish.sh 502b907fa9e0214309406fa5f520b3d3c14f9c1d
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c 7e9c33a714ed1630562f89ad19847f5f28bd6d4d
 F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7
-F src/build.c 7cbac6c3a5d35e56f8d57bb6b07fba5e8a41c806
-F src/delete.c 81002d889aae874decf507627207c5d1b3599dc2
+F src/build.c 55ca22cd7af59b7f8895c601ed9cf006adf50f05
+F src/delete.c 93c9d5e160395020a25d59371625db74c97c7c4d
 F src/expr.c 2f68829d983ec3f92eeb8b89ce4b9e5704169a80
 F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1
 F src/hash.h 5f6e7c04c46ed015ab4e01797c2049b4af5b006d
-F src/insert.c 01dd6ddee901a8a55c9b05a62b30023ec43de9ce
-F src/main.c 6db4ba7ed8f1c1866b04eab6d0f9b46455e152c8
+F src/insert.c a48ba850461b203fb8dbc7add83fc6b6a9cf47f3
+F src/main.c 87b2fca50cbe8b400e1443b2c73693e18d9911cb
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
-F src/os.c 45376582c41dc8829330816d56b8e9e6cd1b7972
+F src/os.c d3f435d89241e06d4230b6f79a4e9d49102eb0a4
 F src/os.h 0f478e2fef5ec1612f94b59b163d4807d4c77d6d
-F src/pager.c 592c16b06ad07c715240e382028e29b0e83378be
+F src/pager.c 3445bd7c18cbfdffd8d6d1077f0b2bdf788da4fe
 F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
-F src/parse.y fcd3452640cf5ae2304ce430668112e0da07745a
+F src/parse.y e88f1efe096a1a01c9076099fe1d81deedfa11de
 F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
 F src/random.c 708a23f69f40d6f2ae5ce1a04e6a4055d4a6ecec
 F src/select.c 0ef8ca1b7de2467fe082bcb35a5ab3b5be56153c
 F src/shell.c cb8c41f1b2173efd212dab3f35f1fc6bf32ead76
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in b95c161abf1d58bceb05290fa3f657d8f388fc11
-F src/sqliteInt.h 78b1890c4b61d35f33941cf9a2aae366b32b3dd3
+F src/sqliteInt.h d75506e003b508d8e2501217648f045496813f2c
 F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
 F src/tclsqlite.c 765599686c19ed777ac379928d732c8bfc63ebac
 F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
 F src/test2.c 0168b39225b768cfdadd534406f9dec58c27879e
 F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
-F src/tokenize.c 8a2aa0443f8bb1a02d021604377e2783e8e45f42
-F src/update.c 0449af173b5f2f0b26e2f0e4545ee0e0429763cb
+F src/tokenize.c 5bd2dd048d77f4c683f0551a73d2fa5e964b53f0
+F src/update.c 49a1edb1a3e44dfff3f799e00f2a3319f2393cd8
 F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387
-F src/vdbe.c 5c865988f8b33dcb8c5282f24bde404ab5d96899
-F src/vdbe.h c543a58f52fb654c90dd31d0d0c31309f4d838de
-F src/where.c cce952b6a2459ac2296e3432876a4252d2fe3b87
+F src/vdbe.c 469c36ce2ef72a10447796dc5b5d61317e47fff2
+F src/vdbe.h 7eb7e9e6c58fe9430efab35e168f96cb4bd6cb45
+F src/where.c b676765ad0360769173b09f46265ddec8d48367a
 F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd
 F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0
 F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce
@@ -83,6 +83,7 @@ F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
 F test/table.test 3ef4254d62ece31a3872ab11cdaec846f6fa8fd1
 F test/tableapi.test 162840153191a91a7dce6395f2334f9aef713b37
 F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a
+F test/temptable.test 99611832cdef52a30e62b091eaf941dbc934f303
 F test/tester.tcl c7ddeebc14cc841abb37134cd5d40c1e3ad367c1
 F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9
 F test/unique.test ef1f67607a7109e9c0842cd8557550fb121d7ec6
@@ -100,19 +101,19 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
 F www/arch.tcl 03b521d252575f93b9c52f7c8b0007011512fcfb
 F www/c_interface.tcl 8e8d9e66e8467c5751116c3427296bde77f474a6
-F www/changes.tcl 8c2ecc905283cfe3221722d8e8bcb660af2297b2
+F www/changes.tcl b42f68ebc6a590ab3dd4f16e389faad2a7f2d541
 F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
 F www/download.tcl 3e51c9ff1326b0a182846134987301310dff7d60
 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
 F www/index.tcl 68c815d64b35b2dcc4d4f6845827df71c6869f9f
-F www/lang.tcl 33a74d727615ccbee8be7c8efd5876ce008c4b0e
+F www/lang.tcl 3a7900e3f80cab50f322d925e573bd9f0acd57e1
 F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
 F www/opcode.tcl 4365ad9798872491dbd7d3071510ebe461785ac3
 F www/speed.tcl ab7d6d3bc898472bd94320a5d3c63de928d4804b
 F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
 F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
 F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
-P e4980849403a8d7bd63753c9b7f275519bd7df4f
-R 7502c066a19df2a451414aa8e23b0cac
+P b63b3f3684a3d584ef99f54cde76b6c483bbfef7
+R 9a90e6e0cf1a1b0f9063fbb657761a98
 U drh
-Z 47fec5ca7cd29a261f31f63e809cee33
+Z 4e9556749f24d361b6f8c2df79fd7c4c
index 586cbaeb4e3fa08d2085633af3f1060081242a20..2afa3e0dceef05238b20c906d5a086ee2adf059d 100644 (file)
@@ -1 +1 @@
-b63b3f3684a3d584ef99f54cde76b6c483bbfef7
\ No newline at end of file
+9368c62e4097aae3081a325962c1dec167fd253d
\ No newline at end of file
index e8d213b43b0e9d9bd270a031f4a3e4f720fecc9e..ef59bb03c117c91d2d03171b972822831e789104 100644 (file)
@@ -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);
 }
index 120295b5f3c5ed475cf8f1134042b377f3d33032..6b02eb59a8710dae1b4d65f6638c31c7de9329fc 100644 (file)
@@ -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);
index 9529a1f9ff88f1d758f093d2edc35092f4b0ddcb..711f8eb94075085e0dc8ea9b52b0c2d6da8bd008 100644 (file)
@@ -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
index d96aad914f5beb1331c21193f1d84079c3b27fa0..184c49ff70bfa2a93c87ef4aa861d724d8a204e9 100644 (file)
@@ -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;
 }
index 0c0f4b357b2938b82fc8a3318709bb84279da67b..e1d0ebc6c4fea551cc2337de65f621a8d241395c 100644 (file)
--- a/src/os.c
+++ b/src/os.c
@@ -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
index 6bb71efc7b50e77949b5088f12987f6077a39156..4584ffdb227a5465c5fc4fc1fadad6d29541690c 100644 (file)
@@ -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;
        }
index 56e6af75af5ed8b94736f7ad490e3bc37ff6b17f..a190751e08d1502975c73b050ee7bd2e864eb241 100644 (file)
@@ -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.
 //
index 59f0a2557701044910764f88132e1329950ad441..90c1869c82822df1937d7dbd3a7a2d6000a5ac3f 100644 (file)
@@ -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*);
index 619ae6ea90776ea7c33771d10b69cc0a265026cb..0ad771150e6798a3dca6bb1e44f287e3edb868d7 100644 (file)
@@ -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 },
index 164a360c08ea11dfbc2c65640c437246f87a74ba..db23bb6e8aeaaa1bea4a9f888a31b95abba596af 100644 (file)
@@ -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
index 0e2614bcb40f4c746357bfa062767cfc3022ab2b..63adee76128d36a7cb09dc74c70b6744a150cbe9 100644 (file)
@@ -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;
   }
index 211d6ede5b390e55a68916bc1d3fe4c02bacf288..b1fde29cb2345fa8d07d4aa883de9d49f39cec87 100644 (file)
@@ -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
index 6105349dba6994e1c5c42f4927b5caadadd7969d..971e20a2cf14fa64c3d1a1c81588872fd05ca6f0 100644 (file)
@@ -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);
     }
   }
diff --git a/test/temptable.test b/test/temptable.test
new file mode 100644 (file)
index 0000000..211ba25
--- /dev/null
@@ -0,0 +1,124 @@
+# 2001 October 7
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# This file implements tests for temporary tables and indices.
+#
+# $Id: temptable.test,v 1.1 2001/10/08 13:22:33 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Create an alternative connection to the database
+#
+do_test temptable-1.0 {
+  sqlite db2 ./test.db
+} {}
+
+# Create a permanent table.
+#
+do_test temptable-1.1 {
+  execsql {CREATE TABLE t1(a,b,c);}
+  execsql {INSERT INTO t1 VALUES(1,2,3);}
+  execsql {SELECT * FROM t1}
+} {1 2 3}
+do_test temptable-1.2 {
+  catch {db2 eval {SELECT * FROM sqlite_master}}
+  db2 eval {SELECT * FROM t1}
+} {1 2 3}
+do_test testtable-1.3 {
+  execsql {SELECT name FROM sqlite_master}
+} {t1}
+do_test testtable-1.4 {
+  db2 eval {SELECT name FROM sqlite_master}
+} {t1}
+
+# Create a temporary table.  Verify that only one of the two
+# processes can see it.
+#
+do_test testtable-1.5 {
+  db2 eval {
+    CREATE TEMP TABLE t2(x,y,z);
+    INSERT INTO t2 VALUES(4,5,6);
+  }
+  db2 eval {SELECT * FROM t2}
+} {4 5 6}
+do_test testtable-1.6 {
+  catch {execsql {SELECT * FROM sqlite_master}}
+  catchsql {SELECT * FROM t2}
+} {1 {no such table: t2}}
+do_test testtable-1.7 {
+  catchsql {INSERT INTO t2 VALUES(8,9,0);}
+} {1 {no such table: t2}}
+do_test testtable-1.8 {
+  db2 eval {INSERT INTO t2 VALUES(8,9,0);}
+  db2 eval {SELECT * FROM t2 ORDER BY x}
+} {4 5 6 8 9 0}
+do_test testtable-1.9 {
+  db2 eval {DELETE FROM t2 WHERE x==8}
+  db2 eval {SELECT * FROM t2 ORDER BY x}
+} {4 5 6}
+do_test testtable-1.10 {
+  db2 eval {DELETE FROM t2}
+  db2 eval {SELECT * FROM t2}
+} {}
+do_test testtable-1.11 {
+  db2 eval {
+     INSERT INTO t2 VALUES(7,6,5);
+     INSERT INTO t2 VALUES(4,3,2);
+     SELECT * FROM t2 ORDER BY x;
+  }
+} {4 3 2 7 6 5}
+do_test testtable-1.12 {
+  db2 eval {DROP TABLE t2;}
+  set r [catch {db2 eval {SELECT * FROM t2}} msg]
+  lappend r $msg
+} {1 {no such table: t2}}
+
+# Make sure temporary tables work with transactions
+#
+do_test testtable-2.1 {
+  execsql {
+    BEGIN TRANSACTION;
+    CREATE TEMPORARY TABLE t2(x,y);
+    INSERT INTO t2 VALUES(1,2);
+    SELECT * FROM t2;
+  }
+} {1 2}
+do_test testtable-2.2 {
+  execsql {ROLLBACK}
+  catchsql {SELECT * FROM t2}
+} {1 {no such table: t2}}
+do_test testtable-2.3 {
+  execsql {
+    BEGIN TRANSACTION;
+    CREATE TEMPORARY TABLE t2(x,y);
+    INSERT INTO t2 VALUES(1,2);
+    SELECT * FROM t2;
+  }
+} {1 2}
+do_test testtable-2.4 {
+  execsql {COMMIT}
+  catchsql {SELECT * FROM t2}
+} {0 {1 2}}
+do_test testtable-2.5 {
+  set r [catch {db2 eval {SELECT * FROM t2}} msg]
+  lappend r $msg
+} {1 {no such table: t2}}
+
+
+# Check for correct name collision processing. A name collision can
+# occur when process A creates a temporary table T then process B
+# creates a permanent table also named T.  The temp table in process A
+# hides the existance of the permanent table.
+#
+
+finish_test
index b92ee88f412a94489182fee9bd7c252e6811d779..13013959fb67cbf7dcdbd1ae9786c8817d98e604 100644 (file)
@@ -20,8 +20,10 @@ proc chng {date desc} {
 chng {2001 Oct ? (2.0.2)} {
 <li>Removed some unused "#include <unistd.h>" that were causing problems
     for VC++.</li>
+<li>Fixed <b>sqlite.h</b> so that it is usable from C++</li>
 <li>Added the FULL_COLUMN_NAMES pragma.  When set to "ON", the names of
     columns are reported back as TABLE.COLUMN instead of just COLUMN.</li>
+<li>Added support for TEMPORARY tables and indices.</li>
 }
 
 chng {2001 Oct 2 (2.0.1)} {
index 0c9c258323ad2c47ca7baee71a866693342f0a2d..2c1dbb70d169029e3498fea91aa842da3169ce41 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this Tcl script to generate the sqlite.html file.
 #
-set rcsid {$Id: lang.tcl,v 1.10 2001/09/28 17:47:14 drh Exp $}
+set rcsid {$Id: lang.tcl,v 1.11 2001/10/08 13:22:33 drh Exp $}
 
 puts {<html>
 <head>
@@ -119,15 +119,14 @@ ROLLBACK [TRANSACTION [<name>]]
 puts {
 <p>Beginning in version 2.0, SQLite supports transactions with
 rollback and atomic commit.  However, only a single level of
-transaction is allowed.  In other words, transactions
-may not be nested.
+transaction is allowed.  Transactions may not be nested.
 </p>
 
 <p>
 No changes can be made to the database except within a transaction.
 Any command that changes the database (basically, any SQL command
 other than SELECT) will automatically starts a transaction if
-when is not already in effect.  Automatically stared transactions
+one is not already in effect.  Automatically stared transactions
 are committed at the conclusion of the command.
 </p>
 
@@ -206,7 +205,7 @@ SQLite's internal representation of the index layout.</p>
 Section {CREATE TABLE} {createtable}
 
 Syntax {sql-command} {
-CREATE TABLE <table-name> (
+CREATE [TEMP | TEMPORARY] TABLE <table-name> (
   <column-def> [, <column-def>]*
   [, <constraint>]*
 )
@@ -246,6 +245,13 @@ The DEFAULT constraint
 specifies a default value to use when doing an INSERT.
 </p>
 
+<p>If the "TEMP" or "TEMPORARY" keyword occurs in between "CREATE"
+and "TABLE" then the table that is created is only visible to the
+process that opened the database and is automatically deleted when
+the database is closed.  Any indices created on a temporary table
+are also temporary.  Temporary tables and indices are stored in a
+separate file distinct from the main database file.</p>
+
 <p>There are no arbitrary limits on the number
 of columns or on the number of constraints in a table.
 The total amount of data in a single row is limited to 65535 bytes.</p>
@@ -579,20 +585,55 @@ puts {
 <p>The VACUUM command is an SQLite extension modelled after a similar
 command found in PostgreSQL.  If VACUUM is invoked with the name of a
 table or index then it is suppose to clean up the named table or index.
-In the current implementation, VACUUM is a no-op.
+In version 1.0 of SQLite, the VACUUM command would invoke 
+<b>gdbm_reorganize()</b> to clean up the backend database file.
+Beginning with version 2.0 of SQLite, GDBM is no longer used for
+the database backend and VACUUM has become a no-op.
 </p>
 }
 
 Section PRAGMA pragma
 
 Syntax {sql-statement} {
-PRAGMA <name> = <value>
+PRAGMA <name> = <value> |
+PRAGMA <function>(<arg>)
 }
 
 puts {
 <p>The PRAGMA command is used to modify the operation of the SQLite library.
-Additional documentation on the PRAMGA statement is forthcoming.
-</p>
+The pragma command is experimental and specific pragma statements may
+removed or added in future releases of SQLite.  Use this command
+with caution.</p>
+
+<p>The current implementation supports the following pragmas:</p>
+
+<ul>
+<li><p><b>PRAGMA cache_size = </b><i>Number-of-pages</i><b>;</b></p>
+    <p>Change the maximum number of database disk pages that SQLite
+    will hold in memory at once.  Each page uses about 1.5K of RAM.
+    The default cache size is 100.  If you are doing UPDATEs or DELETEs
+    that change many rows of a database and you do not mind if SQLite
+    uses more memory, you can increase the cache size for a possible speed
+    improvement.</p></li>
+
+<li><p><b>PRAGMA full_column_names = ON;
+       <br>PRAGMA full_column_names = OFF;</b></p>
+    <p>The column names reported in an SQLite callback are normally just
+    the name of the column itself, except for joins when "TABLE.COLUMN"
+    is used.  But when full_column_names is turned on, column names are
+    always reported as "TABLE.COLUMN" even for simple queries.</p></li>
+
+<li><p><b>PRAGMA vdbe_trace = ON;<br>PRAGMA vdbe_trace = OFF;</b></p>
+    <p>Turn tracing of the virtual database engine inside of the
+    SQLite library on and off.  This is used for debugging.</p></li>
+
+<li><p><b>PRAGMA parser_trace = ON;<br>PRAGMA parser_trace = OFF;</b></p>
+    <p>Turn tracing of the SQL parser inside of the
+    SQLite library on and off.  This is used for debugging.</p></li>
+</ul>
+
+<p>No error message is generated if an unknown pragma is issued.
+Unknown pragmas are ignored.</p>
 }
 
 puts {