]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Added support for the "sqlite_temp_master" table. Increased the version
authordrh <drh@noemail.net>
Tue, 25 Jun 2002 01:09:11 +0000 (01:09 +0000)
committerdrh <drh@noemail.net>
Tue, 25 Jun 2002 01:09:11 +0000 (01:09 +0000)
number to 2.5.2. (CVS 640)

FossilOrigin-Name: 9c1432bf7485258e485bd652e3acdaeabbfe8850

17 files changed:
VERSION
manifest
manifest.uuid
src/build.c
src/main.c
src/parse.y
src/shell.c
src/sqliteInt.h
src/trigger.c
src/vdbe.c
src/where.c
test/temptable.test
test/trigger3.test
www/changes.tcl
www/faq.tcl
www/lang.tcl
www/sqlite.tcl

diff --git a/VERSION b/VERSION
index 73462a5a13445f66009e00988279d30e55aa8363..f225a78adf0534ad898ee7521a19aa40897f53ba 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.5.1
+2.5.2
index 1c509bdb709d970191ac087c4332fa2dac26a4a1..98a3774ad3c26d755e083ba89da57754e4b020bd 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Partial\sfix\sfor\sa\sproblem\swith\sLEFT\sOUTER\sJOIN.\s\sIt\sused\sto\sbe\sthat\sthe\stest\nfor\sthe\sright-hand\stable\snot\smatching\sthe\sleft\stable\soccurred\safter\sall\nON,\sUSING,\sWHERE\sclause\sprocessing.\s\sThe\stest\sshould\soccur\safter\sON\sand\nUSING\sclauses\sare\schecked\sbut\sbefore\sthe\sWHERE\sclause\sis\scheck.\s\sThis\sfix\nworks\sas\slong\sas\sthe\stotal\snumber\sof\s"AND"\sseparated\sterms\sin\sthe\sON,\sUSING,\nand\sWHERE\sclause\sdoes\snot\sexceed\s32.\s\sTo\sdo:\smake\sthis\swork\sfor\sany\snumber\nof\sterms\sand\sadd\stest\scases.\nthat\s(CVS\s639)
-D 2002-06-24T22:01:58
+C Added\ssupport\sfor\sthe\s"sqlite_temp_master"\stable.\s\sIncreased\sthe\sversion\nnumber\sto\s2.5.2.\s(CVS\s640)
+D 2002-06-25T01:09:11
 F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
 F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
-F VERSION 9a1a4bc4ca9e44b3ccf4c764cb670aae41b078a0
+F VERSION 2ca20d4461e9496d4ae27191e7273a12369ff17c
 F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
 F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
 F config.sub f14b07d544ca26b5d698259045136b783e18fc7f
@@ -20,7 +20,7 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c 6aaa67d7eab70c2531dc13e5d9eb87e626c0b4d7
 F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
-F src/build.c 95eac6ce4ae2871388d49066c78dd0657ce40a1f
+F src/build.c 846eb3ee0e160e691766108a7136e196f8f8231b
 F src/delete.c 44c45460b1e03033756e35adc6d569ffbf30b725
 F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
 F src/expr.c cb50a72c491954d58be2f182366e45a1e252bf2e
@@ -28,20 +28,20 @@ F src/func.c 5eae8227a8b0d276a64d51a3880a6e86f238fedf
 F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
 F src/insert.c 4bb40ed9dbaba4516fc2abbcff3f08d5687b073c
-F src/main.c 0e922ecfe4ce58c3e5c49f111d86003607d2114b
+F src/main.c 43d5f4e38108129a13cf42c59087e6e20b3596ad
 F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
 F src/os.c 9cc40c5384baba4a85e160e67807645ca98ba3cc
 F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
 F src/pager.c 1e41053c949cea1f09d8dafada5fe8f90785e650
 F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
-F src/parse.y 2285d8967d7334d52a2188089e5a881d73ba56f6
+F src/parse.y c75ea2580de675bcb80ff8b7c10c0a15e02a21ab
 F src/printf.c 236ed7a79386feed4456fa728fff8be793f1547c
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
 F src/select.c f7d74f20f5ecc335fbccba367eda727b9d6fb299
-F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
+F src/shell.c 7b9d98ef3976ff5e44c18620dd17d32af83fbdd6
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 7c8882e352cb70818cfaf9bdb5b1b3bee81ef144
-F src/sqliteInt.h d3c1448890ba65e6be381b50b7e7ce7fca142322
+F src/sqliteInt.h 3d1d86cb9ea4f06e49af855267478e3661abcd1b
 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
 F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
 F src/test1.c 5cc4f0bbf38237e04e1b2077e285b41bfb4c4cbf
@@ -49,12 +49,12 @@ F src/test2.c 669cc22781c6461a273416ec1a7414d25c081730
 F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
 F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
 F src/tokenize.c ac4c46f190346b87da54ec3e2605d160af80c619
-F src/trigger.c 21342af6ac031fece39c8fc6eabd1739ca5327c1
+F src/trigger.c d88ab4d68d68955c217b38fb6717e090fbbf54a4
 F src/update.c 6f6a4dcd71cd9ff730b7f12c83de5498cde4924f
 F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95
-F src/vdbe.c 774f79483ce809b27c3bdb02afd7295cc3c7acd4
+F src/vdbe.c 0b1ad7c3cbc638d1f73725bbc4e667c3ee8f7081
 F src/vdbe.h a9292f2b5fcecef924fa255fb74609e9cbc776c2
-F src/where.c 259d7fb77191b13718c271926b7c14afbbe7346b
+F src/where.c 913fa33977c8dddfc259d9b2c38504b475738c43
 F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
 F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
@@ -98,12 +98,12 @@ F test/subselect.test f3bc1dcbddddcea08d818fcff75228ad3464fc83
 F test/table.test 42511f98a3e9bbee62913e3ae1774777faa23d35
 F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
 F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533
-F test/temptable.test ae58694c0fdd2d0b781508b64adc5aee3416aeed
+F test/temptable.test 9ed7ec0288f887e132de66d90c428ad109105f67
 F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6
 F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee
 F test/trigger1.test bb63749fa8a395a60541100607d86381604b7194
 F test/trigger2.test c12759a0d7ba6488d9d24c96a1352ddee995c1ab
-F test/trigger3.test b4aca721ba92956c7fa16bb0158254f3c1b73efa
+F test/trigger3.test 7dfe798d7e72c13720394685fe353112e3f31adf
 F test/unique.test 572aa791327c1e8d797932263e9d67f176cfdb44
 F test/update.test a0aa0bf83e6fad8407d0e4ad25ebb09b513f5bf4
 F test/vacuum.test 059871b312eb910bbe49dafde1d01490cc2c6bbe
@@ -122,22 +122,22 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
 F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
 F www/c_interface.tcl 58cf4d128dcae08d91d0011c6d4d11de323f470f
-F www/changes.tcl 31a8fec4f078a60b7de5f19859297f375e9ec8da
+F www/changes.tcl 08de0b1b50d3651ac3bd6b0d44c9ebe0072b55b3
 F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
 F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49
 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
-F www/faq.tcl 45bdb18b75ac3aa1befec42985fb892413aac0bb
+F www/faq.tcl 06e95342a101fde3ce59dbf128233a178502587e
 F www/formatchng.tcl f604cde78f1ac9c29420136109b04407408e876e
 F www/index.tcl d0c52fbf031d0a3ee6d9d77aa669d5a4b24b6130
-F www/lang.tcl cf22bf18dbd6bec3b7d0b00ad998dd1f88193ea2
+F www/lang.tcl 8c3d0bda030f110c754b5edbad75eddf5dbe2ed1
 F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
 F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
 F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
-F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
+F www/sqlite.tcl ac64065d0c5e2de0f71238d55b2c14bb5c5c194c
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P d861489e1f7dffd1105c271fe8597f73e5b1703c
-R d718b83d86c9331bc69c93f673a44be9
+P 8b6574cfa86daaae910f8f3ee3c4723a21fb9e53
+R c96fc24249eaf46c6e1d5e0a79495140
 U drh
-Z b9b5d0f63e47642b79ff89410dec8a4b
+Z 421a17002ac6e743396eaf770c048af4
index 9fc9568e12c8950defd8caaa04cb77fb69abce90..69eb0f6e9160d2c5221f53897377e0afba6fc645 100644 (file)
@@ -1 +1 @@
-8b6574cfa86daaae910f8f3ee3c4723a21fb9e53
\ No newline at end of file
+9c1432bf7485258e485bd652e3acdaeabbfe8850
\ No newline at end of file
index 7e7920278e0dddfb2f86132102acaf70ca1ba38a..3d4909741e8f59393e6fbc8668d1e5fb987bf872 100644 (file)
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.97 2002/06/20 11:36:49 drh Exp $
+** $Id: build.c,v 1.98 2002/06/25 01:09:11 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
 
+/*
+** This routine is called when a new SQL statement is beginning to
+** be parsed.  Check to see if the schema for the database needs
+** to be read from the SQLITE_MASTER and SQLITE_TEMP_MASTER tables.
+** If it does, then read it.
+*/
+void sqliteBeginParse(Parse *pParse, int explainFlag){
+  sqlite *db = pParse->db;
+  pParse->explain = explainFlag;
+  if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){
+    int rc = sqliteInit(db, &pParse->zErrMsg);
+    if( rc!=SQLITE_OK ){
+      pParse->rc = rc;
+      pParse->nErr++;
+    }
+  }
+}
+
 /*
 ** This routine is called after a single SQL statement has been
 ** parsed and we want to execute the VDBE code to implement 
@@ -48,6 +66,7 @@ void sqliteExec(Parse *pParse){
     if( pParse->explain ){
       rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
                           &pParse->zErrMsg);
+      db->next_cookie = db->schema_cookie;
     }else{
       FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
       sqliteVdbeTrace(pParse->pVdbe, trace);
@@ -70,7 +89,8 @@ void sqliteExec(Parse *pParse){
 ** of that table.  Return NULL if not found.
 */
 Table *sqliteFindTable(sqlite *db, const char *zName){
-  Table *p = sqliteHashFind(&db->tblHash, zName, strlen(zName)+1);
+  Table *p;
+  p = sqliteHashFind(&db->tblHash, zName, strlen(zName)+1);
   return p;
 }
 
@@ -80,7 +100,8 @@ Table *sqliteFindTable(sqlite *db, const char *zName){
 ** Return NULL if not found.
 */
 Index *sqliteFindIndex(sqlite *db, const char *zName){
-  Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1);
+  Index *p;
+  p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1);
   return p;
 }
 
@@ -99,7 +120,6 @@ static void sqliteDeleteIndex(sqlite *db, Index *p){
   if( pOld!=0 && pOld!=p ){
     sqliteHashInsert(&db->idxHash, pOld->zName, strlen(pOld->zName)+1, pOld);
   }
-  sqliteHashInsert(&db->idxDrop, p, 0, 0);
   sqliteFree(p);
 }
 
@@ -122,26 +142,51 @@ void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){
 }
 
 /*
-** Move the given index to the pending DROP INDEX queue if it has
-** been committed.  If this index was never committed, then just
-** delete it.
-**
-** Indices on the pending drop queue are deleted when a COMMIT is
-** executed.  If a ROLLBACK occurs, the indices are moved back into
-** the main index hash table.
+** Erase all schema information from the in-memory hash tables of
+** database connection.  This routine is called to reclaim memory
+** before the connection closes.  It is also called during a rollback
+** if there were schema changes during the transaction.
 */
-static void sqlitePendingDropIndex(sqlite *db, Index *p){
-  if( !p->isCommit ){
-    sqliteUnlinkAndDeleteIndex(db, p);
-  }else{
-    Index *pOld;
-    pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, 0);
-    if( pOld!=0 && pOld!=p ){
-      sqliteHashInsert(&db->idxHash, pOld->zName, strlen(pOld->zName)+1, pOld);
-    }
-    sqliteHashInsert(&db->idxDrop, p, 0, p);
-    p->isDropped = 1;
+void sqliteResetInternalSchema(sqlite *db){
+  HashElem *pElem;
+  Hash temp1;
+  Hash temp2;
+
+  temp1 = db->tblHash;
+  temp2 = db->trigHash;
+  sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
+  sqliteHashClear(&db->idxHash);
+  for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
+    Trigger *pTrigger = sqliteHashData(pElem);
+    sqliteDeleteTrigger(pTrigger);
   }
+  sqliteHashClear(&temp2);
+  sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
+  for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
+    Table *pTab = sqliteHashData(pElem);
+    sqliteDeleteTable(db, pTab);
+  }
+  sqliteHashClear(&temp1);
+  db->flags &= ~(SQLITE_Initialized|SQLITE_InternChanges);
+}
+
+/*
+** This routine is called whenever a rollback occurs.  If there were
+** schema changes during the transaction, then we have to reset the
+** internal hash tables and reload them from disk.
+*/
+void sqliteRollbackInternalChanges(sqlite *db){
+  if( db->flags & SQLITE_InternChanges ){
+    sqliteResetInternalSchema(db);
+  }
+}
+
+/*
+** This routine is called when a commit occurs.
+*/
+void sqliteCommitInternalChanges(sqlite *db){
+  db->schema_cookie = db->next_cookie;
+  db->flags &= ~SQLITE_InternChanges;
 }
 
 /*
@@ -185,185 +230,9 @@ static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){
   assert( db!=0 );
   pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0);
   assert( pOld==0 || pOld==p );
-  sqliteHashInsert(&db->tblDrop, p, 0, 0);
   sqliteDeleteTable(db, p);
 }
 
-/*
-** Move the given table to the pending DROP TABLE queue if it has
-** been committed.  If this table was never committed, then just
-** delete it.  Do the same for all its indices.
-**
-** Table on the drop queue are not actually deleted until a COMMIT
-** statement is executed.  If a ROLLBACK occurs instead of a COMMIT,
-** then the tables on the drop queue are moved back into the main
-** hash table.
-*/
-static void sqlitePendingDropTable(sqlite *db, Table *pTbl){
-  if( !pTbl->isCommit ){
-    sqliteUnlinkAndDeleteTable(db, pTbl);
-  }else{
-    Table *pOld;
-    Index *pIndex, *pNext;
-    pOld = sqliteHashInsert(&db->tblHash, pTbl->zName, strlen(pTbl->zName)+1,0);
-    assert( pOld==pTbl );
-    sqliteHashInsert(&db->tblDrop, pTbl, 0, pTbl);
-    for(pIndex = pTbl->pIndex; pIndex; pIndex=pNext){
-      pNext = pIndex->pNext;
-      sqlitePendingDropIndex(db, pIndex);
-    }
-  }
-}
-
-/*
-** Check all Tables and Indexes in the internal hash table and commit
-** any additions or deletions to those hash tables.
-**
-** When executing CREATE TABLE and CREATE INDEX statements, the Table
-** and Index structures are created and added to the hash tables, but
-** the "isCommit" field is not set.  This routine sets those fields.
-** When executing DROP TABLE and DROP INDEX, the table or index structures
-** are moved out of tblHash and idxHash into tblDrop and idxDrop.  This
-** routine deletes the structure in tblDrop and idxDrop.
-**
-** See also: sqliteRollbackInternalChanges()
-*/
-void sqliteCommitInternalChanges(sqlite *db){
-  HashElem *pElem;
-  if( (db->flags & SQLITE_InternChanges)==0 ) return;
-  db->schema_cookie = db->next_cookie;
-  for(pElem=sqliteHashFirst(&db->tblHash); pElem; pElem=sqliteHashNext(pElem)){
-    Table *pTable = sqliteHashData(pElem);
-    pTable->isCommit = 1;
-  }
-  for(pElem=sqliteHashFirst(&db->tblDrop); pElem; pElem=sqliteHashNext(pElem)){
-    Table *pTable = sqliteHashData(pElem);
-    sqliteDeleteTable(db, pTable);
-  }
-  sqliteHashClear(&db->tblDrop);
-  for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
-    Index *pIndex = sqliteHashData(pElem);
-    pIndex->isCommit = 1;
-  }
-  while( (pElem=sqliteHashFirst(&db->idxDrop))!=0 ){
-    Index *pIndex = sqliteHashData(pElem);
-    sqliteUnlinkAndDeleteIndex(db, pIndex);
-  }
-  sqliteHashClear(&db->idxDrop);
-
-  /* Set the commit flag on all triggers added this transaction */
-  for(pElem=sqliteHashFirst(&db->trigHash); pElem; pElem=sqliteHashNext(pElem)){
-    Trigger *pTrigger = sqliteHashData(pElem);
-    pTrigger->isCommit = 1;
-  }
-
-  /* Delete the structures for triggers removed this transaction */
-  pElem = sqliteHashFirst(&db->trigDrop);
-  while( pElem ){
-    Trigger *pTrigger = sqliteHashData(pElem);
-    sqliteDeleteTrigger(pTrigger);
-    pElem = sqliteHashNext(pElem);
-  }
-  sqliteHashClear(&db->trigDrop);
-
-  db->flags &= ~SQLITE_InternChanges;
-}
-
-/*
-** This routine runs when one or more CREATE TABLE, CREATE INDEX,
-** 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.
-**
-** See also: sqliteCommitInternalChanges()
-*/
-void sqliteRollbackInternalChanges(sqlite *db){
-  Hash toDelete;
-  HashElem *pElem;
-  if( (db->flags & SQLITE_InternChanges)==0 ) return;
-  sqliteHashInit(&toDelete, SQLITE_HASH_POINTER, 0);
-  db->next_cookie = db->schema_cookie;
-  for(pElem=sqliteHashFirst(&db->tblHash); pElem; pElem=sqliteHashNext(pElem)){
-    Table *pTable = sqliteHashData(pElem);
-    if( !pTable->isCommit ){
-      sqliteHashInsert(&toDelete, pTable, 0, pTable);
-    }
-  }
-  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
-    Table *pTable = sqliteHashData(pElem);
-    sqliteUnlinkAndDeleteTable(db, pTable);
-  }
-  sqliteHashClear(&toDelete);
-  for(pElem=sqliteHashFirst(&db->tblDrop); pElem; pElem=sqliteHashNext(pElem)){
-    Table *pOld, *p = sqliteHashData(pElem);
-    assert( p->isCommit );
-    pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
-    assert( pOld==0 || pOld==p );
-  }
-  sqliteHashClear(&db->tblDrop);
-  for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
-    Index *pIndex = sqliteHashData(pElem);
-    if( !pIndex->isCommit ){
-      sqliteHashInsert(&toDelete, pIndex, 0, pIndex);
-    }
-  }
-  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
-    Index *pIndex = sqliteHashData(pElem);
-    sqliteUnlinkAndDeleteIndex(db, pIndex);
-  }
-  sqliteHashClear(&toDelete);
-  for(pElem=sqliteHashFirst(&db->idxDrop); pElem; pElem=sqliteHashNext(pElem)){
-    Index *pOld, *p = sqliteHashData(pElem);
-    assert( p->isCommit );
-    p->isDropped = 0;
-    pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, p);
-    assert( pOld==0 || pOld==p );
-  }
-  sqliteHashClear(&db->idxDrop);
-
-  /* Remove any triggers that haven't been commited yet */
-  for(pElem = sqliteHashFirst(&db->trigHash); pElem; 
-      pElem = (pElem?sqliteHashNext(pElem):0)){
-    Trigger *pTrigger = sqliteHashData(pElem);
-    if( !pTrigger->isCommit ){
-      Table *pTbl = sqliteFindTable(db, pTrigger->table);
-      if( pTbl ){
-        if( pTbl->pTrigger == pTrigger ){
-          pTbl->pTrigger = pTrigger->pNext;
-        }else{
-          Trigger *cc = pTbl->pTrigger;
-          while( cc ){
-            if( cc->pNext == pTrigger ){
-              cc->pNext = cc->pNext->pNext;
-              break;
-            }
-            cc = cc->pNext;
-          }
-          assert(cc);
-        }
-      }
-      sqliteHashInsert(&db->trigHash, pTrigger->name,
-              1 + strlen(pTrigger->name), 0);
-      sqliteDeleteTrigger(pTrigger);
-      pElem = sqliteHashFirst(&db->trigHash);
-    }
-  }
-
-  /* Any triggers that were dropped - put 'em back in place */
-  for(pElem = sqliteHashFirst(&db->trigDrop); pElem; 
-      pElem = sqliteHashNext(pElem)){
-    Trigger *pTrigger = sqliteHashData(pElem);
-    Table *pTbl = sqliteFindTable(db, pTrigger->table);
-    sqliteHashInsert(&db->trigHash, pTrigger->name, 
-        strlen(pTrigger->name) + 1, pTrigger);
-    pTrigger->pNext = pTbl->pTrigger;
-    pTbl->pTrigger = pTrigger;
-  }
-
-  sqliteHashClear(&db->trigDrop);
-  db->flags &= ~SQLITE_InternChanges;
-}
-
 /*
 ** Construct the name of a user table or index from a token.
 **
@@ -376,13 +245,31 @@ char *sqliteTableNameFromToken(Token *pName){
   return zName;
 }
 
+/*
+** Generate code to open the appropriate master table.  The table
+** opened will be SQLITE_MASTER for persistent tables and 
+** SQLITE_TEMP_MASTER for temporary tables.  The table is opened
+** on cursor 0.
+*/
+void sqliteOpenMasterTable(Vdbe *v, int isTemp){
+  if( isTemp ){
+    sqliteVdbeAddOp(v, OP_OpenWrAux, 0, 2);
+    sqliteVdbeChangeP3(v, -1, TEMP_MASTER_NAME, P3_STATIC);
+  }else{
+    sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
+    sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
+  }
+}
+
 /*
 ** Begin constructing a new table representation in memory.  This is
 ** 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.  The isTemp
-** flag is true if the "TEMP" or "TEMPORARY" keyword occurs in between
+** flag is true if the table should be stored in the auxiliary database
+** file instead of in the main database file.  This is normally the case
+** when the "TEMP" or "TEMPORARY" keyword occurs in between
 ** CREATE and TABLE.
 **
 ** The new table record is initialized and put in pParse->pNewTable.
@@ -408,7 +295,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
   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 "
+      sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database "
         "file for storing temporary tables", 0);
       pParse->nErr++;
       return;
@@ -482,13 +369,12 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
     if( !isTemp ){
       sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
       sqliteVdbeAddOp(v, OP_SetCookie, 0, 1);
-      sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
-      sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
-      sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
-      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
-      sqliteVdbeAddOp(v, OP_String, 0, 0);
-      sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
     }
+    sqliteOpenMasterTable(v, isTemp);
+    sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
+    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
+    sqliteVdbeAddOp(v, OP_String, 0, 0);
+    sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
   }
 }
 
@@ -725,10 +611,12 @@ void sqliteAddCollateType(Parse *pParse, int collType){
 ** and the probability of hitting the same cookie value is only
 ** 1 chance in 2^32.  So we're safe enough.
 */
-void sqliteChangeCookie(sqlite *db){
+void sqliteChangeCookie(sqlite *db, Vdbe *v){
   if( db->next_cookie==db->schema_cookie ){
     db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
     db->flags |= SQLITE_InternChanges;
+    sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
+    sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
   }
 }
 
@@ -791,11 +679,10 @@ static char *createTableStmt(Table *p){
     zSep2 = ",\n  ";
     zEnd = "\n)";
   }
-  n += 25 + 6*p->nCol;
+  n += 35 + 6*p->nCol;
   zStmt = sqliteMalloc( n );
   if( zStmt==0 ) return 0;
-  assert( !p->isTemp );
-  strcpy(zStmt, "CREATE TABLE ");
+  strcpy(zStmt, p->isTemp ? "CREATE TEMP TABLE " : "CREATE TABLE ");
   k = strlen(zStmt);
   identPut(zStmt, &k, p->zName);
   zStmt[k++] = '(';
@@ -867,10 +754,10 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
   }
 
   /* If the initFlag is 1 it means we are reading the SQL off the
-  ** "sqlite_master" table on the disk.  So do not write to the disk
-  ** again.  Extract the root page number for the table from the 
-  ** pParse->newTnum field.  (The page number should have been put
-  ** there by the sqliteOpenCb routine.)
+  ** "sqlite_master" or "sqlite_temp_master" table on the disk.
+  ** So do not write to the disk again.  Extract the root page number
+  ** for the table from the pParse->newTnum field.  (The page number
+  ** should have been put there by the sqliteOpenCb routine.)
   */
   if( pParse->initFlag ){
     p->tnum = pParse->newTnum;
@@ -880,8 +767,8 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
   ** in the SQLITE_MASTER table of the database.  The record number
   ** for the new table entry should already be on the stack.
   **
-  ** If this is a TEMPORARY table, then just create the table.  Do not
-  ** make an entry in SQLITE_MASTER.
+  ** If this is a TEMPORARY table, write the entry into the auxiliary
+  ** file instead of into the main database file.
   */
   if( !pParse->initFlag ){
     int n;
@@ -898,37 +785,35 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
       sqliteVdbeAddOp(v, OP_Integer, 0, 0);
     }
     p->tnum = 0;
+    sqliteVdbeAddOp(v, OP_Pull, 1, 0);
+    sqliteVdbeAddOp(v, OP_String, 0, 0);
+    if( p->pSelect==0 ){
+      sqliteVdbeChangeP3(v, -1, "table", P3_STATIC);
+    }else{
+      sqliteVdbeChangeP3(v, -1, "view", P3_STATIC);
+    }
+    sqliteVdbeAddOp(v, OP_String, 0, 0);
+    sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
+    sqliteVdbeAddOp(v, OP_String, 0, 0);
+    sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
+    sqliteVdbeAddOp(v, OP_Dup, 4, 0);
+    sqliteVdbeAddOp(v, OP_String, 0, 0);
+    if( pSelect ){
+      char *z = createTableStmt(p);
+      n = z ? strlen(z) : 0;
+      sqliteVdbeChangeP3(v, -1, z, n);
+      sqliteFree(z);
+    }else{
+      assert( pEnd!=0 );
+      n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
+      sqliteVdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
+    }
+    sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
+    sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
     if( !p->isTemp ){
-      sqliteVdbeAddOp(v, OP_Pull, 1, 0);
-      sqliteVdbeAddOp(v, OP_String, 0, 0);
-      if( p->pSelect==0 ){
-        sqliteVdbeChangeP3(v, -1, "table", P3_STATIC);
-      }else{
-        sqliteVdbeChangeP3(v, -1, "view", P3_STATIC);
-      }
-      sqliteVdbeAddOp(v, OP_String, 0, 0);
-      sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
-      sqliteVdbeAddOp(v, OP_String, 0, 0);
-      sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
-      sqliteVdbeAddOp(v, OP_Dup, 4, 0);
-      sqliteVdbeAddOp(v, OP_String, 0, 0);
-      if( pSelect ){
-        char *z = createTableStmt(p);
-        n = z ? strlen(z) : 0;
-        sqliteVdbeChangeP3(v, -1, z, n);
-        sqliteFree(z);
-      }else{
-        assert( pEnd!=0 );
-        n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
-        sqliteVdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
-      }
-      sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
-      sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
-      sqliteChangeCookie(db);
-      sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
-      sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
-      sqliteVdbeAddOp(v, OP_Close, 0, 0);
+      sqliteChangeCookie(db, v);
     }
+    sqliteVdbeAddOp(v, OP_Close, 0, 0);
     if( pSelect ){
       int op = p->isTemp ? OP_OpenWrAux : OP_OpenWrite;
       sqliteVdbeAddOp(v, op, 1, 0);
@@ -1151,34 +1036,38 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
   v = sqliteGetVdbe(pParse);
   if( v ){
     static VdbeOp dropTable[] = {
-      { OP_OpenWrite,  0, 2,        MASTER_NAME},
-      { OP_Rewind,     0, ADDR(9),  0},
-      { OP_String,     0, 0,        0}, /* 2 */
+      { OP_Rewind,     0, ADDR(8),  0},
+      { OP_String,     0, 0,        0}, /* 1 */
       { OP_MemStore,   1, 1,        0},
-      { OP_MemLoad,    1, 0,        0}, /* 4 */
+      { OP_MemLoad,    1, 0,        0}, /* 3 */
       { OP_Column,     0, 2,        0},
-      { OP_Ne,         0, ADDR(8),  0},
+      { OP_Ne,         0, ADDR(7),  0},
       { OP_Delete,     0, 0,        0},
-      { OP_Next,       0, ADDR(4),  0}, /* 8 */
-      { OP_Integer,    0, 0,        0}, /* 9 */
-      { OP_SetCookie,  0, 0,        0},
-      { OP_Close,      0, 0,        0},
+      { OP_Next,       0, ADDR(3),  0}, /* 7 */
     };
     Index *pIdx;
+    Trigger *pTrigger;
     sqliteBeginWriteOperation(pParse, 0);
+    sqliteOpenMasterTable(v, pTable->isTemp);
     /* Drop all triggers associated with the table being dropped */
-    while( pTable->pTrigger ){
+    pTrigger = pTable->pTrigger;
+    while( pTrigger ){
       Token tt;
       tt.z = pTable->pTrigger->name;
       tt.n = strlen(pTable->pTrigger->name);
       sqliteDropTrigger(pParse, &tt, 1);
+      if( pParse->explain ){
+        pTrigger = pTrigger->pNext;
+      }else{
+        pTrigger = pTable->pTrigger;
+      }
     }
+    base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
+    sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
     if( !pTable->isTemp ){
-      base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
-      sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
-      sqliteChangeCookie(db);
-      sqliteVdbeChangeP1(v, base+9, db->next_cookie);
+      sqliteChangeCookie(db, v);
     }
+    sqliteVdbeAddOp(v, OP_Close, 0, 0);
     if( !isView ){
       sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->isTemp);
       for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
@@ -1188,16 +1077,13 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
     sqliteEndWriteOperation(pParse);
   }
 
-  /* Move the table (and all its indices) to the pending DROP queue.
-  ** Or, if the table was never committed, just delete it.  If the table
-  ** has been committed and is placed on the pending DROP queue, then the
-  ** delete will occur when sqliteCommitInternalChanges() executes.
+  /* Delete the in-memory description of the table.
   **
   ** Exception: if the SQL statement began with the EXPLAIN keyword,
   ** then no changes should be made.
   */
   if( !pParse->explain ){
-    sqlitePendingDropTable(db, pTable);
+    sqliteUnlinkAndDeleteTable(db, pTable);
     db->flags |= SQLITE_InternChanges;
   }
   sqliteViewResetAll(db);
@@ -1264,7 +1150,7 @@ void sqliteCreateIndex(
   ** Since its table has been suppressed, we need to also suppress the
   ** index.
   */
-  if( pParse->initFlag && pTab->isTemp ){
+  if( pParse->initFlag && !pParse->isTemp && pTab->isTemp ){
     goto exit_create_index;
   }
 
@@ -1429,40 +1315,33 @@ void sqliteCreateIndex(
     if( v==0 ) goto exit_create_index;
     if( pTable!=0 ){
       sqliteBeginWriteOperation(pParse, 0);
-      if( !isTemp ){
-        sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
-        sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
-      }
-    }
-    if( !isTemp ){
-      sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
-      sqliteVdbeAddOp(v, OP_String, 0, 0);
-      sqliteVdbeChangeP3(v, -1, "index", P3_STATIC);
-      sqliteVdbeAddOp(v, OP_String, 0, 0);
-      sqliteVdbeChangeP3(v, -1, pIndex->zName, P3_STATIC);
-      sqliteVdbeAddOp(v, OP_String, 0, 0);
-      sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
+      sqliteOpenMasterTable(v, isTemp);
     }
+    sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
+    sqliteVdbeAddOp(v, OP_String, 0, 0);
+    sqliteVdbeChangeP3(v, -1, "index", P3_STATIC);
+    sqliteVdbeAddOp(v, OP_String, 0, 0);
+    sqliteVdbeChangeP3(v, -1, pIndex->zName, P3_STATIC);
+    sqliteVdbeAddOp(v, OP_String, 0, 0);
+    sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
     addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp);
     sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, P3_POINTER);
     pIndex->tnum = 0;
     if( pTable ){
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
       if( isTemp ){
         sqliteVdbeAddOp(v, OP_OpenWrAux, 1, 0);
       }else{
-        sqliteVdbeAddOp(v, OP_Dup, 0, 0);
         sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
       }
     }
-    if( !isTemp ){
-      addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
-      if( pStart && pEnd ){
-        n = Addr(pEnd->z) - Addr(pStart->z) + 1;
-        sqliteVdbeChangeP3(v, addr, pStart->z, n);
-      }
-      sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
-      sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
+    addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
+    if( pStart && pEnd ){
+      n = Addr(pEnd->z) - Addr(pStart->z) + 1;
+      sqliteVdbeChangeP3(v, addr, pStart->z, n);
     }
+    sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
+    sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
     if( pTable ){
       sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum);
       sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
@@ -1481,11 +1360,9 @@ void sqliteCreateIndex(
     }
     if( pTable!=0 ){
       if( !isTemp ){
-        sqliteChangeCookie(db);
-        sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
-        sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
-        sqliteVdbeAddOp(v, OP_Close, 0, 0);
+        sqliteChangeCookie(db, v);
       }
+      sqliteVdbeAddOp(v, OP_Close, 0, 0);
       sqliteEndWriteOperation(pParse);
     }
   }
@@ -1523,42 +1400,35 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
   v = sqliteGetVdbe(pParse);
   if( v ){
     static VdbeOp dropIndex[] = {
-      { OP_OpenWrite,  0, 2,       MASTER_NAME},
-      { OP_Rewind,     0, ADDR(10),0}, 
-      { OP_String,     0, 0,       0}, /* 2 */
+      { OP_Rewind,     0, ADDR(9), 0}, 
+      { OP_String,     0, 0,       0}, /* 1 */
       { OP_MemStore,   1, 1,       0},
-      { OP_MemLoad,    1, 0,       0}, /* 4 */
+      { OP_MemLoad,    1, 0,       0}, /* 3 */
       { OP_Column,     0, 1,       0},
-      { OP_Eq,         0, ADDR(9), 0},
-      { OP_Next,       0, ADDR(4), 0},
-      { OP_Goto,       0, ADDR(10),0},
-      { OP_Delete,     0, 0,       0}, /* 9 */
-      { OP_Integer,    0, 0,       0}, /* 10 */
-      { OP_SetCookie,  0, 0,       0},
-      { OP_Close,      0, 0,       0},
+      { OP_Eq,         0, ADDR(8), 0},
+      { OP_Next,       0, ADDR(3), 0},
+      { OP_Goto,       0, ADDR(9), 0},
+      { OP_Delete,     0, 0,       0}, /* 8 */
     };
     int base;
     Table *pTab = pIndex->pTable;
 
     sqliteBeginWriteOperation(pParse, 0);
+    sqliteOpenMasterTable(v, pTab->isTemp);
+    base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
+    sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0);
     if( !pTab->isTemp ){
-      base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
-      sqliteVdbeChangeP3(v, base+2, pIndex->zName, P3_STATIC);
-      sqliteChangeCookie(db);
-      sqliteVdbeChangeP1(v, base+10, db->next_cookie);
+      sqliteChangeCookie(db, v);
     }
+    sqliteVdbeAddOp(v, OP_Close, 0, 0);
     sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp);
     sqliteEndWriteOperation(pParse);
   }
 
-  /* Move the index onto the pending DROP queue.  Or, if the index was
-  ** never committed, just delete it.  Indices on the pending DROP queue
-  ** get deleted by sqliteCommitInternalChanges() when the user executes
-  ** a COMMIT.  Or if a rollback occurs, the elements of the DROP queue
-  ** are moved back into the main hash table.
+  /* Delete the in-memory description of this index.
   */
   if( !pParse->explain ){
-    sqlitePendingDropIndex(db, pIndex);
+    sqliteUnlinkAndDeleteIndex(db, pIndex);
     db->flags |= SQLITE_InternChanges;
   }
 }
index 436afc848ea216f30db7c6caa2801a2860abfc10..e6877b38faf41b833561e6c8610d7a6284c18eee 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.83 2002/06/22 02:33:38 drh Exp $
+** $Id: main.c,v 1.84 2002/06/25 01:09:11 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -30,6 +30,7 @@
 **     argv[1] = table or index name or meta statement type.
 **     argv[2] = root page number for table or index.  NULL for meta.
 **     argv[3] = SQL create statement for the table or index
+**     argv[4] = "1" for temporary files, "0" for main database
 **
 */
 int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
@@ -41,29 +42,8 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
   ** make sure fields do not contain NULLs. Otherwise we might core
   ** when attempting to initialize from a corrupt database file. */
 
-  assert( argc==4 );
+  assert( argc==5 );
   switch( argv[0][0] ){
-    case 'c': {  /* Recommended pager cache size */
-      int size = atoi(argv[3]);
-      if( size==0 ){ size = MAX_PAGES; }
-      db->cache_size = size;
-      sqliteBtreeSetCacheSize(db->pBe, size);
-      break;
-    }
-    case 'f': {  /* File format */
-      /*
-      ** file_format==1  Version 2.1.0.
-      ** file_format==2  Version 2.2.0.  Integer primary key.
-      ** file_format==3  Version 2.6.0.  Separate text and numeric datatypes.
-      */
-      db->file_format = atoi(argv[3]);
-      break;
-    }
-    case 's': { /* Schema cookie */
-      db->schema_cookie = atoi(argv[3]);
-      db->next_cookie = db->schema_cookie;
-      break;
-    }
     case 'v':
     case 'i':
     case 't': {  /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
@@ -76,6 +56,7 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
         memset(&sParse, 0, sizeof(sParse));
         sParse.db = db;
         sParse.initFlag = 1;
+        sParse.isTemp = argv[4][0] - '0';
         sParse.newTnum = atoi(argv[2]);
         sqliteRunParser(&sParse, argv[3], 0);
       }else{
@@ -120,15 +101,29 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
 ** has the sqlite_master table locked) than another attempt
 ** is made the first time the database is accessed.
 */
-static int sqliteInit(sqlite *db, char **pzErrMsg){
-  Vdbe *vdbe;
+int sqliteInit(sqlite *db, char **pzErrMsg){
   int rc;
+  BtCursor *curMain;
+  int size;
+  Table *pTab;
+  char *azArg[6];
+  int meta[SQLITE_N_BTREE_META];
+  Parse sParse;
 
   /*
   ** The master database table has a structure like this
   */
   static char master_schema[] = 
-     "CREATE TABLE " MASTER_NAME " (\n"
+     "CREATE TABLE sqlite_master(\n"
+     "  type text,\n"
+     "  name text,\n"
+     "  tbl_name text,\n"
+     "  rootpage integer,\n"
+     "  sql text\n"
+     ")"
+  ;
+  static char temp_master_schema[] = 
+     "CREATE TEMP TABLE sqlite_temp_master(\n"
      "  type text,\n"
      "  name text,\n"
      "  tbl_name text,\n"
@@ -137,165 +132,117 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
      ")"
   ;
 
-  /* The following VDBE program is used to initialize the internal
-  ** structure holding the tables and indexes of the database.
-  ** The database contains a special table named "sqlite_master"
-  ** defined as follows:
+  /* The following SQL will read the schema from the master tables.
+  ** The first version works with SQLite file formats 2 or greater.
+  ** The second version is for format 1 files.
   **
-  **    CREATE TABLE sqlite_master (
-  **        type       text,    --  Either "table" or "index" or "meta"
-  **        name       text,    --  Name of table or index
-  **        tbl_name   text,    --  Associated table 
-  **        rootpage   integer, --  The integer page number of root page
-  **        sql        text     --  The CREATE statement for this object
-  **    );
-  **
-  ** The sqlite_master table contains a single entry for each table
-  ** and each index.  The "type" column tells whether the entry is
-  ** a table or index.  The "name" column is the name of the object.
-  ** The "tbl_name" is the name of the associated table.  For tables,
-  ** the tbl_name column is always the same as name.  For indices, the
-  ** tbl_name column contains the name of the table that the index
-  ** indexes.  The "rootpage" column holds the number of the root page
-  ** for the b-tree for the table or index.  Finally, the "sql" column
-  ** contains the complete text of the CREATE TABLE or CREATE INDEX
-  ** statement that originally created the table or index.  If an index
-  ** was created to fulfill a PRIMARY KEY or UNIQUE constraint on a table,
-  ** then the "sql" column is NULL.
-  **
-  ** In format 1, entries in the sqlite_master table are in a random
-  ** order.  Two passes must be made through the table to initialize
-  ** internal data structures.  The first pass reads table definitions
-  ** and the second pass read index definitions.  Having two passes
-  ** insures that indices appear after their tables.
-  **
-  ** In format 2, entries appear in chronological order.  Only a single
-  ** pass needs to be made through the table since everything will be
-  ** in the write order.  VIEWs may only occur in format 2.
-  **
-  ** The following program invokes its callback on the SQL for each
-  ** table then goes back and invokes the callback on the
-  ** SQL for each index.  The callback will invoke the
-  ** parser to build the internal representation of the
-  ** database scheme.
+  ** Beginning with file format 2, the rowid for new table entries
+  ** (including entries in sqlite_master) is an increasing integer.
+  ** So for file format 2 and later, we can play back sqlite_master
+  ** and all the CREATE statements will appear in the right order.
+  ** But with file format 1, table entries were random and so we
+  ** have to make sure the CREATE TABLEs occur before their corresponding
+  ** CREATE INDEXs.  (We don't have to deal with CREATE VIEW or
+  ** CREATE TRIGGER in file format 1 because those constructs did
+  ** not exist then.) 
   */
-  static VdbeOp initProg[] = {
-    /* Send the file format to the callback routine
-    */
-    { OP_Open,       0, 2,  0},
-    { OP_String,     0, 0,  "file-format"},
-    { OP_String,     0, 0,  0},
-    { OP_String,     0, 0,  0},
-    { OP_ReadCookie, 0, 1,  0},
-    { OP_Callback,   4, 0,  0},
-
-    /* Send the recommended pager cache size to the callback routine
-    */
-    { OP_String,     0, 0,  "cache-size"},
-    { OP_String,     0, 0,  0},
-    { OP_String,     0, 0,  0},
-    { OP_ReadCookie, 0, 2,  0},
-    { OP_Callback,   4, 0,  0},
-
-    /* Send the initial schema cookie to the callback
-    */
-    { OP_String,     0, 0,  "schema_cookie"},
-    { OP_String,     0, 0,  0},
-    { OP_String,     0, 0,  0},
-    { OP_ReadCookie, 0, 0,  0},
-    { OP_Callback,   4, 0,  0},
-
-    /* Check the file format.  If the format number is 2 or more,
-    ** then do a single pass through the SQLITE_MASTER table.  For
-    ** a format number of less than 2, jump forward to a different
-    ** algorithm that makes two passes through the SQLITE_MASTER table,
-    ** once for tables and a second time for indices.
-    */
-    { OP_ReadCookie, 0, 1,  0},
-    { OP_Integer,    2, 0,  0},
-    { OP_Lt,         0, 28, 0},
-
-    /* This is the code for doing a single scan through the SQLITE_MASTER
-    ** table.  This code runs for format 2 and greater.
-    */
-    { OP_Rewind,     0, 26, 0},
-    { OP_Column,     0, 0,  0},           /* 20 */
-    { OP_Column,     0, 1,  0},
-    { OP_Column,     0, 3,  0},
-    { OP_Column,     0, 4,  0},
-    { OP_Callback,   4, 0,  0},
-    { OP_Next,       0, 20, 0},
-    { OP_Close,      0, 0,  0},           /* 26 */
-    { OP_Halt,       0, 0,  0},
-
-    /* This is the code for doing two passes through SQLITE_MASTER.  This
-    ** code runs for file format 1.
-    */
-    { OP_Rewind,     0, 48, 0},           /* 28 */
-    { OP_Column,     0, 0,  0},           /* 29 */
-    { OP_String,     0, 0,  "table"},
-    { OP_Ne,         0, 37, 0},
-    { OP_Column,     0, 0,  0},
-    { OP_Column,     0, 1,  0},
-    { OP_Column,     0, 3,  0},
-    { OP_Column,     0, 4,  0},
-    { OP_Callback,   4, 0,  0},
-    { OP_Next,       0, 29, 0},           /* 37 */
-    { OP_Rewind,     0, 48, 0},           /* 38 */
-    { OP_Column,     0, 0,  0},           /* 39 */
-    { OP_String,     0, 0,  "index"},
-    { OP_Ne,         0, 47, 0},
-    { OP_Column,     0, 0,  0},
-    { OP_Column,     0, 1,  0},
-    { OP_Column,     0, 3,  0},
-    { OP_Column,     0, 4,  0},
-    { OP_Callback,   4, 0,  0},
-    { OP_Next,       0, 39, 0},           /* 47 */
-    { OP_Close,      0, 0,  0},           /* 48 */
-    { OP_Halt,       0, 0,  0},
-  };
-
-  /* Create a virtual machine to run the initialization program.  Run
-  ** the program.  Then delete the virtual machine.
+  static char init_script[] = 
+     "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master "
+     "UNION ALL "
+     "SELECT type, name, rootpage, sql, 0 FROM sqlite_master";
+  static char older_init_script[] = 
+     "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master "
+     "UNION ALL "
+     "SELECT type, name, rootpage, sql, 0 FROM sqlite_master "
+     "WHERE type='table' "
+     "UNION ALL "
+     "SELECT type, name, rootpage, sql, 0 FROM sqlite_master "
+     "WHERE type='index'";
+
+
+  /* Construct the schema tables: sqlite_master and sqlite_temp_master
   */
-  vdbe = sqliteVdbeCreate(db);
-  if( vdbe==0 ){
-    sqliteSetString(pzErrMsg, "out of memory", 0);
-    return SQLITE_NOMEM;
+  azArg[0] = "table";
+  azArg[1] = MASTER_NAME;
+  azArg[2] = "2";
+  azArg[3] = master_schema;
+  azArg[4] = "0";
+  azArg[5] = 0;
+  sqliteInitCallback(db, 5, azArg, 0);
+  pTab = sqliteFindTable(db, MASTER_NAME);
+  if( pTab ){
+    pTab->readOnly = 1;
   }
-  sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
-  rc = sqliteVdbeExec(vdbe, sqliteInitCallback, db, pzErrMsg, 
-                      db->pBusyArg, db->xBusyCallback);
-  sqliteVdbeDelete(vdbe);
-  if( rc==SQLITE_OK && db->nTable==0 ){
-    db->file_format = 2;
+  azArg[1] = TEMP_MASTER_NAME;
+  azArg[3] = temp_master_schema;
+  azArg[4] = "1";
+  sqliteInitCallback(db, 5, azArg, 0);
+  pTab = sqliteFindTable(db, TEMP_MASTER_NAME);
+  if( pTab ){
+    pTab->readOnly = 1;
+  }
+
+  /* Create a cursor to hold the database open
+  */
+  if( db->pBe==0 ) return SQLITE_OK;
+  rc = sqliteBtreeCursor(db->pBe, 2, 0, &curMain);
+  if( rc ) return rc;
+
+  /* Get the database meta information
+  */
+  rc = sqliteBtreeGetMeta(db->pBe, meta);
+  if( rc ){
+    sqliteBtreeCloseCursor(curMain);
+    return rc;
   }
-  if( rc==SQLITE_OK && db->file_format>2 ){
+  db->schema_cookie = meta[1];
+  db->next_cookie = db->schema_cookie;
+  db->file_format = meta[2];
+  size = meta[3];
+  if( size==0 ){ size = MAX_PAGES; }
+  db->cache_size = size;
+  sqliteBtreeSetCacheSize(db->pBe, size);
+
+  /*
+  **     file_format==1    Version 2.1.0.
+  **     file_format==2    Version 2.2.0. Add support for INTEGER PRIMARY KEY.
+  **     file_format==3    Version 2.6.0. Add support for separate numeric and
+  **                       text datatypes.
+  */
+  if( db->file_format==0 ){
+    db->file_format = 2;
+  }else if( db->file_format>2 ){
+    sqliteBtreeCloseCursor(curMain);
     sqliteSetString(pzErrMsg, "unsupported file format", 0);
     rc = SQLITE_ERROR;
   }
 
-  /* The schema for the SQLITE_MASTER table is not stored in the
-  ** database itself.  We have to invoke the callback one extra
-  ** time to get it to process the SQLITE_MASTER table defintion.
+  /* Read the schema information out of the schema tables
   */
-  if( rc==SQLITE_OK ){
-    Table *pTab;
-    char *azArg[6];
-    azArg[0] = "table";
-    azArg[1] = MASTER_NAME;
-    azArg[2] = "2";
-    azArg[3] = master_schema;
-    azArg[4] = 0;
-    sqliteInitCallback(db, 4, azArg, 0);
-    pTab = sqliteFindTable(db, MASTER_NAME);
-    if( pTab ){
-      pTab->readOnly = 1;
-    }
+  memset(&sParse, 0, sizeof(sParse));
+  sParse.db = db;
+  sParse.pBe = db->pBe;
+  sParse.xCallback = sqliteInitCallback;
+  sParse.pArg = (void*)db;
+  sParse.initFlag = 1;
+  sqliteRunParser(&sParse,
+      db->file_format>=2 ? init_script : older_init_script,
+      pzErrMsg);
+  if( sqlite_malloc_failed ){
+    sqliteSetString(pzErrMsg, "out of memory", 0);
+    sParse.rc = SQLITE_NOMEM;
+    sqliteBtreeRollback(db->pBe);
+    sqliteResetInternalSchema(db);
+  }
+  if( sParse.rc==SQLITE_OK ){
     db->flags |= SQLITE_Initialized;
     sqliteCommitInternalChanges(db);
+  }else{
+    db->flags &= ~SQLITE_Initialized;
+    sqliteResetInternalSchema(db);
   }
-  return rc;
+  sqliteBtreeCloseCursor(curMain);
+  return sParse.rc;
 }
 
 /*
@@ -333,9 +280,6 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
   sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
   sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
   sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
-  sqliteHashInit(&db->trigDrop, SQLITE_HASH_STRING, 0);
-  sqliteHashInit(&db->tblDrop, SQLITE_HASH_POINTER, 0);
-  sqliteHashInit(&db->idxDrop, SQLITE_HASH_POINTER, 0);
   sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
   sqliteRegisterBuiltinFunctions(db);
   db->onError = OE_Default;
@@ -377,74 +321,6 @@ no_mem_on_open:
   return 0;
 }
 
-/*
-** Erase all schema information from the schema hash table.  Except
-** tables that are created using CREATE TEMPORARY TABLE are preserved
-** if the preserveTemps 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.
-** This routine erases the stored schema.  This erasure occurs because
-** 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, int preserveTemps){
-  HashElem *pElem;
-  Hash temp1;
-  Hash temp2;
-
-  /* Make sure there are no uncommited DROPs */
-  assert( sqliteHashFirst(&db->tblDrop)==0 || sqlite_malloc_failed );
-  assert( sqliteHashFirst(&db->idxDrop)==0 || sqlite_malloc_failed );
-  assert( sqliteHashFirst(&db->trigDrop)==0 || sqlite_malloc_failed );
-  temp1 = db->tblHash;
-  temp2 = db->trigHash;
-  sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
-  sqliteHashClear(&db->idxHash);
-
-  for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
-    Trigger * pTrigger = sqliteHashData(pElem);
-    Table *pTab = sqliteFindTable(db, pTrigger->table);
-    assert(pTab);
-    if( pTab->isTemp && preserveTemps ){ 
-      sqliteHashInsert(&db->trigHash, pTrigger->name, strlen(pTrigger->name), 
-          pTrigger);
-    }else{
-      sqliteDeleteTrigger(pTrigger);
-    }
-  }
-  sqliteHashClear(&temp2);
-
-  sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
-
-  for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
-    Table *pTab = sqliteHashData(pElem);
-    if( preserveTemps && pTab->isTemp ){
-      Index *pIdx;
-      int nName = strlen(pTab->zName);
-      Table *pOld = sqliteHashInsert(&db->tblHash, pTab->zName, nName+1, pTab);
-      if( pOld!=0 ){
-        assert( pOld==pTab );   /* Malloc failed on the HashInsert */
-        sqliteDeleteTable(db, pOld);
-        continue;
-      }
-      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
-        int n = strlen(pIdx->zName)+1;
-        Index *pOldIdx;
-        pOldIdx = sqliteHashInsert(&db->idxHash, pIdx->zName, n, pIdx);
-        if( pOld ){
-          assert( pOldIdx==pIdx );
-          sqliteUnlinkAndDeleteIndex(db, pOldIdx);
-        }
-      }
-    }else{
-      sqliteDeleteTable(db, pTab);
-    }
-  }
-  sqliteHashClear(&temp1);
-  db->flags &= ~SQLITE_Initialized;
-}
-
 /*
 ** Return the ROWID of the most recent insert
 */
@@ -467,8 +343,7 @@ void sqlite_close(sqlite *db){
   if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ return; }
   db->magic = SQLITE_MAGIC_CLOSED;
   sqliteBtreeClose(db->pBe);
-  sqliteRollbackInternalChanges(db);
-  clearHashTable(db, 0);
+  sqliteResetInternalSchema(db);
   if( db->pBeTemp ){
     sqliteBtreeClose(db->pBeTemp);
   }
@@ -638,11 +513,11 @@ int sqlite_exec(
     sqliteBtreeRollback(db->pBe);
     if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
     db->flags &= ~SQLITE_InTrans;
-    clearHashTable(db, 0);
+    sqliteResetInternalSchema(db);
   }
   sqliteStrRealloc(pzErrMsg);
   if( sParse.rc==SQLITE_SCHEMA ){
-    clearHashTable(db, 1);
+    sqliteResetInternalSchema(db);
   }
   db->recursionDepth--;
   if( sqliteSafetyOff(db) ) goto exec_misuse;
index 725ea06a296099cb1899373ce0e64c06ca2280df..5ea48dfe3ab00b3c504953db0e8b35b2f57b4f5c 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.74 2002/06/17 17:07:20 drh Exp $
+** @(#) $Id: parse.y,v 1.75 2002/06/25 01:09:12 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -65,9 +65,9 @@ input ::= cmdlist.
 cmdlist ::= ecmd.
 cmdlist ::= cmdlist ecmd.
 ecmd ::= explain cmd SEMI.  {sqliteExec(pParse);}
-ecmd ::= cmd SEMI.          {sqliteExec(pParse);}
 ecmd ::= SEMI.
-explain ::= EXPLAIN.    {pParse->explain = 1;}
+explain ::= EXPLAIN.    { sqliteBeginParse(pParse, 1); }
+explain ::= .           { sqliteBeginParse(pParse, 0); }
 
 ///////////////////// Begin and end transactions. ////////////////////////////
 //
@@ -87,8 +87,8 @@ 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;}
+temp(A) ::= TEMP.  {A = pParse->isTemp || !pParse->initFlag;}
+temp(A) ::= .      {A = pParse->isTemp;}
 create_table_args ::= LP columnlist conslist_opt RP(X). {
   sqliteEndTable(pParse,&X,0);
 }
index 63567c4f80282906f538440499481830f94a93dc..d8ee2108e0fe6d0c13e635bd5e344b2825bee948 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.57 2002/05/21 13:02:24 drh Exp $
+** $Id: shell.c,v 1.58 2002/06/25 01:09:12 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -660,8 +660,11 @@ static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
     sqlite_exec_printf(db,
       "SELECT name FROM sqlite_master "
       "WHERE type='index' AND tbl_name LIKE '%q' "
-      "ORDER BY name",
-      callback, &data, &zErrMsg, azArg[1]
+      "UNION ALL "
+      "SELECT name FROM sqlite_temp_master "
+      "WHERE type='index' AND tbl_name LIKE '%q' "
+      "ORDER BY 1",
+      callback, &data, &zErrMsg, azArg[1], azArg[1]
     );
     if( zErrMsg ){
       fprintf(stderr,"Error: %s\n", zErrMsg);
@@ -796,18 +799,35 @@ static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
         new_colv[0] = "sql";
         new_colv[1] = 0;
         callback(&data, 1, new_argv, new_colv);
+      }else if( sqliteStrICmp(azArg[1],"sqlite_temp_master")==0 ){
+        char *new_argv[2], *new_colv[2];
+        new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
+                      "  type text,\n"
+                      "  name text,\n"
+                      "  tbl_name text,\n"
+                      "  rootpage integer,\n"
+                      "  sql text\n"
+                      ")";
+        new_argv[1] = 0;
+        new_colv[0] = "sql";
+        new_colv[1] = 0;
+        callback(&data, 1, new_argv, new_colv);
       }else{
         sqlite_exec_printf(db,
-          "SELECT sql FROM sqlite_master "
+          "SELECT sql FROM "
+          "  (SELECT * FROM sqlite_master UNION ALL"
+          "   SELECT * FROM sqlite_temp_master) "
           "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOTNULL "
-          "ORDER BY type DESC, name",
+          "ORDER BY substr(type,2,1), name",
           callback, &data, &zErrMsg, azArg[1]);
       }
     }else{
       sqlite_exec(db,
-         "SELECT sql FROM sqlite_master "
+         "SELECT sql FROM "
+         "  (SELECT * FROM sqlite_master UNION ALL"
+         "   SELECT * FROM sqlite_temp_master) "
          "WHERE type!='meta' AND sql NOTNULL "
-         "ORDER BY tbl_name, type DESC, name",
+         "ORDER BY substr(type,2,1), name",
          callback, &data, &zErrMsg
       );
     }
@@ -846,15 +866,21 @@ static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
       rc = sqlite_get_table(db,
         "SELECT name FROM sqlite_master "
         "WHERE type IN ('table','view') "
-        "ORDER BY name",
+        "UNION ALL "
+        "SELECT name FROM sqlite_temp_master "
+        "WHERE type IN ('table','view') "
+        "ORDER BY 1",
         &azResult, &nRow, 0, &zErrMsg
       );
     }else{
       rc = sqlite_get_table_printf(db,
         "SELECT name FROM sqlite_master "
         "WHERE type IN ('table','view') AND name LIKE '%%%q%%' "
-        "ORDER BY name",
-        &azResult, &nRow, 0, &zErrMsg, azArg[1]
+        "UNION ALL "
+        "SELECT name FROM sqlite_temp_master "
+        "WHERE type IN ('table','view') AND name LIKE '%%%q%%' "
+        "ORDER BY 1",
+        &azResult, &nRow, 0, &zErrMsg, azArg[1], azArg[1]
       );
     }
     if( zErrMsg ){
index 67e7ad6cf996dc7d6967384904af5ab62241ecad..3f1d801177f58029b49698e251664ad402f5ca77 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.130 2002/06/24 22:01:58 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.131 2002/06/25 01:09:12 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -145,7 +145,8 @@ extern int sqlite_iMallocFail;   /* Fail sqliteMalloc() after this many calls */
 ** is a special table that holds the names and attributes of all
 ** user tables and indices.
 */
-#define MASTER_NAME   "sqlite_master"
+#define MASTER_NAME       "sqlite_master"
+#define TEMP_MASTER_NAME  "sqlite_temp_master"
 
 /*
 ** A convenience macro that returns the number of elements in
@@ -202,8 +203,7 @@ struct sqlite {
   int (*xBusyCallback)(void *,const char*,int);  /* The busy callback */
   Hash tblHash;                 /* All tables indexed by name */
   Hash idxHash;                 /* All (named) indices indexed by name */
-  Hash tblDrop;                 /* Uncommitted DROP TABLEs */
-  Hash idxDrop;                 /* Uncommitted DROP INDEXs */
+  Hash trigHash;                /* All triggers indexed by name */
   Hash aFunc;                   /* All functions that can be in SQL exprs */
   int lastRowid;                /* ROWID of most recent insert */
   int priorNewRowid;            /* Last randomly generated ROWID */
@@ -211,9 +211,6 @@ struct sqlite {
   int magic;                    /* Magic number for detect library misuse */
   int nChange;                  /* Number of rows changed */
   int recursionDepth;           /* Number of nested calls to sqlite_exec() */
-
-  Hash trigHash;                /* All triggers indexed by name */
-  Hash trigDrop;                /* Uncommited dropped triggers */
 };
 
 /*
@@ -325,12 +322,10 @@ struct Table {
   int tnum;        /* Root BTree node for this table (see note above) */
   Select *pSelect; /* NULL for tables.  Points to definition if a view. */
   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 isTemp;       /* True if stored in db->pBeTemp instead of db->pBe */
   u8 isTransient;  /* True if automatically deleted when VDBE finishes */
   u8 hasPrimKey;   /* True if there exists a primary key */
   u8 keyConf;      /* What to do in case of uniqueness conflict on iPKey */
-
   Trigger *pTrigger; /* List of SQL triggers on this table */
 };
 
@@ -386,8 +381,6 @@ struct Index {
   Table *pTable;   /* The SQL table being indexed */
   int tnum;        /* Page containing root of this index in database file */
   u8 isUnique;     /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
-  u8 isCommit;     /* True if creation of this index has been committed */
-  u8 isDropped;    /* True if a DROP INDEX has executed on this index */
   u8 onError;      /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
   Index *pNext;    /* The next index associated with the same table */
 };
@@ -648,10 +641,15 @@ struct Parse {
   Token sLastToken;    /* The last token parsed */
   Table *pNewTable;    /* A table being constructed by CREATE TABLE */
   Vdbe *pVdbe;         /* An engine for executing database bytecode */
-  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 */
+  u8 colNamesSet;      /* TRUE after OP_ColumnCount has been issued to pVdbe */
+  u8 explain;          /* True if the EXPLAIN flag is found on the query */
+  u8 initFlag;         /* True if reparsing CREATE TABLEs */
+  u8 nameClash;        /* A permanent table name clashes with temp table name */
+  u8 useAgg;           /* If true, extract field values from the aggregator
+                       ** while generating expressions.  Normally false */
+  u8 schemaVerified;   /* True if an OP_VerifySchema has been coded someplace
+                       ** other than after an OP_Transaction */
+  u8 isTemp;           /* True if parsing temporary tables */
   int newTnum;         /* Table number to use when reparsing CREATE TABLEs */
   int nErr;            /* Number of errors seen */
   int nTab;            /* Number of previously allocated VDBE cursors */
@@ -659,10 +657,6 @@ struct Parse {
   int nSet;            /* Number of sets used so far */
   int nAgg;            /* Number of aggregate expressions */
   AggExpr *aAgg;       /* An array of aggregate expressions */
-  int useAgg;          /* If true, extract field values from the aggregator
-                       ** while generating expressions.  Normally false */
-  int schemaVerified;  /* True if an OP_VerifySchema has been coded someplace
-                       ** other than after an OP_Transaction */
   TriggerStack *trigStack;
 };
 
@@ -711,7 +705,6 @@ struct Trigger {
   TriggerStep *step_list; /* Link list of trigger program steps             */
   char *strings;          /* pointer to allocation of Token strings */
   Trigger *pNext;         /* Next trigger associated with the table */
-  int isCommit;           /* Set to TRUE once the trigger has been committed */
 };
 
 /*
@@ -847,9 +840,13 @@ void sqliteExprDelete(Expr*);
 ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*);
 void sqliteExprListDelete(ExprList*);
 void sqlitePragma(Parse*,Token*,Token*,int);
-void sqliteCommitInternalChanges(sqlite*);
+void sqliteResetInternalSchema(sqlite*);
+int sqliteInit(sqlite*, char**);
+void sqliteBeginParse(Parse*,int);
 void sqliteRollbackInternalChanges(sqlite*);
+void sqliteCommitInternalChanges(sqlite*);
 Table *sqliteResultSetOfSelect(Parse*,char*,Select*);
+void sqliteOpenMasterTable(Vdbe *v, int);
 void sqliteStartTable(Parse*,Token*,Token*,int);
 void sqliteAddColumn(Parse*,Token*);
 void sqliteAddNotNull(Parse*, int);
@@ -929,7 +926,7 @@ void sqliteRegisterBuiltinFunctions(sqlite*);
 int sqliteSafetyOn(sqlite*);
 int sqliteSafetyOff(sqlite*);
 int sqliteSafetyCheck(sqlite*);
-void sqliteChangeCookie(sqlite *);
+void sqliteChangeCookie(sqlite*, Vdbe*);
 void sqliteCreateTrigger(Parse*, Token*, int, int, IdList*, Token*, 
                          int, Expr*, TriggerStep*, char const*,int);
 void sqliteDropTrigger(Parse*, Token*, int);
index 95e8fc9f81f76a1a14c73e788e763cb9f53a6f9f..53eff0c41d0ed94855f5b1153a7a0a8ffb0aab3e 100644 (file)
@@ -70,6 +70,12 @@ void sqliteCreateTrigger(
       pParse->nErr++;
       goto trigger_cleanup;
     }
+    if( sqliteStrICmp(tab->zName, TEMP_MASTER_NAME)==0 ){
+      sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system "
+         "table: " TEMP_MASTER_NAME, 0);
+      pParse->nErr++;
+      goto trigger_cleanup;
+    }
     if( tab->pSelect && tr_tm != TK_INSTEAD ){
       sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1,
          (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1
@@ -100,7 +106,6 @@ void sqliteCreateTrigger(
   nt->pColumns = pColumns;
   nt->foreach = foreach;
   nt->step_list = pStepList;
-  nt->isCommit = 0;
   offset = (int)(nt->strings - zData);
   sqliteExprMoveStrings(nt->pWhen, offset);
 
@@ -119,20 +124,16 @@ void sqliteCreateTrigger(
   /* if we are not initializing, and this trigger is not on a TEMP table, 
   ** build the sqlite_master entry
   */
-  if( !pParse->initFlag && !tab->isTemp ){
+  if( !pParse->initFlag ){
     static VdbeOp insertTrig[] = {
-      { OP_OpenWrite,  0, 2,  MASTER_NAME},
       { OP_NewRecno,   0, 0,  0          },
       { OP_String,     0, 0,  "trigger"  },
-      { OP_String,     0, 0,  0          },  /* 3: trigger name */
-      { OP_String,     0, 0,  0          },  /* 4: table name */
+      { OP_String,     0, 0,  0          },  /* 2: trigger name */
+      { OP_String,     0, 0,  0          },  /* 3: table name */
       { OP_Integer,    0, 0,  0          },
-      { OP_String,     0, 0,  0          },  /* 6: SQL */
+      { OP_String,     0, 0,  0          },  /* 5: SQL */
       { OP_MakeRecord, 5, 0,  0          },
       { OP_PutIntKey,  0, 0,  0          },
-      { OP_Integer,    0, 0,  0          },  /* 9: Next cookie */
-      { OP_SetCookie,  0, 0,  0          },
-      { OP_Close,      0, 0,  0          },
     };
     int addr;
     Vdbe *v;
@@ -141,12 +142,17 @@ void sqliteCreateTrigger(
     v = sqliteGetVdbe(pParse);
     if( v==0 ) goto trigger_cleanup;
     sqliteBeginWriteOperation(pParse, 0);
+    sqliteOpenMasterTable(v, tab->isTemp);
     addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
-    sqliteVdbeChangeP3(v, addr+3, nt->name, 0); 
-    sqliteVdbeChangeP3(v, addr+4, nt->table, 0); 
-    sqliteVdbeChangeP3(v, addr+6, nt->strings, 0);
-    sqliteChangeCookie(pParse->db);
-    sqliteVdbeChangeP1(v, addr+9, pParse->db->next_cookie);
+    sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME,
+                       P3_STATIC);
+    sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 
+    sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 
+    sqliteVdbeChangeP3(v, addr+5, nt->strings, 0);
+    if( !tab->isTemp ){
+      sqliteChangeCookie(pParse->db, v);
+    }
+    sqliteVdbeAddOp(v, OP_Close, 0, 0);
     sqliteEndWriteOperation(pParse);
   }
 
@@ -312,11 +318,11 @@ void sqliteDeleteTrigger(Trigger *pTrigger){
  * table. This is so that the trigger can be restored into the database schema
  * if the transaction is rolled back.
  */
-void sqliteDropTrigger(Parse *pParse, Token *pName, int nested)
-{
+void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
   char *zName;
   Trigger *pTrigger;
   Table   *pTable;
+  Vdbe *v;
 
   zName = sqliteStrNDup(pName->z, pName->n);
 
@@ -330,12 +336,9 @@ void sqliteDropTrigger(Parse *pParse, Token *pName, int nested)
   }
 
   /*
-   * If this is not an "explain", do the following:
-   * 1. Remove the trigger from its associated table structure
-   * 2. Move the trigger from the trigHash hash to trigDrop
+   * If this is not an "explain", then delete the trigger structure.
    */
   if( !pParse->explain ){
-    /* 1 */
     pTable = sqliteFindTable(pParse->db, pTrigger->table);
     assert(pTable);
     if( pTable->pTrigger == pTrigger ){
@@ -351,46 +354,34 @@ void sqliteDropTrigger(Parse *pParse, Token *pName, int nested)
       }
       assert(cc);
     }
-
-    /* 2 */
-    sqliteHashInsert(&(pParse->db->trigHash), zName, 
-        pName->n + 1, NULL);
-    sqliteHashInsert(&(pParse->db->trigDrop), pTrigger->name, 
-        pName->n + 1, pTrigger);
+    sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL);
+    sqliteDeleteTrigger(pTrigger);
   }
 
-  /* Unless this is a trigger on a TEMP TABLE, generate code to destroy the
-   * database record of the trigger */
-  if( !pTable->isTemp ){
+  /* Generate code to destroy the database record of the trigger.
+  */
+  if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
     int base;
     static VdbeOp dropTrigger[] = {
-      { OP_OpenWrite,  0, 2,        MASTER_NAME},
-      { OP_Rewind,     0, ADDR(9),  0},
-      { OP_String,     0, 0,        0}, /* 2 */
+      { OP_Rewind,     0, ADDR(8),  0},
+      { OP_String,     0, 0,        0}, /* 1 */
       { OP_MemStore,   1, 1,        0},
-      { OP_MemLoad,    1, 0,        0}, /* 4 */
+      { OP_MemLoad,    1, 0,        0}, /* 3 */
       { OP_Column,     0, 1,        0},
-      { OP_Ne,         0, ADDR(8),  0},
+      { OP_Ne,         0, ADDR(7),  0},
       { OP_Delete,     0, 0,        0},
-      { OP_Next,       0, ADDR(4),  0}, /* 8 */
-      { OP_Integer,    0, 0,        0}, /* 9 */
-      { OP_SetCookie,  0, 0,        0},
-      { OP_Close,      0, 0,        0},
+      { OP_Next,       0, ADDR(3),  0}, /* 7 */
     };
 
-    if( !nested ){
-      sqliteBeginWriteOperation(pParse, 0);
-    }
-    base = sqliteVdbeAddOpList(pParse->pVdbe, 
-        ArraySize(dropTrigger), dropTrigger);
-    sqliteVdbeChangeP3(pParse->pVdbe, base+2, zName, 0);
-    if( !nested ){
-      sqliteChangeCookie(pParse->db);
-    }
-    sqliteVdbeChangeP1(pParse->pVdbe, base+9, pParse->db->next_cookie);
-    if( !nested ){
-      sqliteEndWriteOperation(pParse);
+    sqliteBeginWriteOperation(pParse, 0);
+    sqliteOpenMasterTable(v, pTable->isTemp);
+    base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
+    sqliteVdbeChangeP3(v, base+1, zName, 0);
+    if( !pTable->isTemp ){
+      sqliteChangeCookie(pParse->db, v);
     }
+    sqliteVdbeAddOp(v, OP_Close, 0, 0);
+    sqliteEndWriteOperation(pParse);
   }
 
   sqliteFree(zName);
index 74978b2414e0d4a44587d9e58ab54b64c3e8b2a4..a706669b6b387a039df2453fc80624c76667b89c 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.158 2002/06/21 23:01:50 drh Exp $
+** $Id: vdbe.c,v 1.159 2002/06/25 01:09:12 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -3021,7 +3021,6 @@ case OP_Open: {
     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);
@@ -3047,6 +3046,7 @@ case OP_Open: {
   cleanupCursor(&p->aCsr[i]);
   memset(&p->aCsr[i], 0, sizeof(Cursor));
   p->aCsr[i].nullRow = 1;
+  if( pX==0 ) break;
   do{
     rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
     switch( rc ){
index d0eb170ab7b8179784d587530e566d650f9dfc4e..9a90f6269d50bc6e2d2d8917014a44f0157d5971 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.55 2002/06/24 22:01:59 drh Exp $
+** $Id: where.c,v 1.56 2002/06/25 01:09:12 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -479,7 +479,6 @@ WhereInfo *sqliteWhereBegin(
       int inMask = 0;  /* Index columns covered by an x IN .. term */
       int nEq, m, score;
 
-      if( pIdx->isDropped ) continue;   /* Ignore dropped indices */
       if( pIdx->nColumn>32 ) continue;  /* Ignore indices too many columns */
       for(j=0; j<nExpr; j++){
         if( aExpr[j].idxLeft==idx 
index 7e7d9b59e324f24b311a5ac1162c3ea3696998c4..e74c8bed25c73a8f4dde48a71089f97318824005 100644 (file)
@@ -12,7 +12,7 @@
 #
 # This file implements tests for temporary tables and indices.
 #
-# $Id: temptable.test,v 1.6 2002/06/06 23:16:06 drh Exp $
+# $Id: temptable.test,v 1.7 2002/06/25 01:09:12 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -115,7 +115,6 @@ do_test temptable-2.5 {
   lappend r $msg
 } {1 {no such table: t2}}
 
-
 # Make sure indices on temporary tables are also temporary.
 #
 do_test temptable-3.1 {
index bb08c71bedc3b36c7502e88032c141aeac17340f..4544d96177df1017df6e6795e2fa733a11af8874 100644 (file)
@@ -158,6 +158,6 @@ do_test trig-raise-7.3 {
 
 catchsql { DROP TABLE tbl; } 
 catchsql { DROP TABLE tbl2; } 
-catchsql { DROP VIEW tbl_view; } 
-
+catchsql { DROP VIEW tbl_view; }
 
+finish_test
index f05c3d0ca78e2ab13327633b848976ff65b7c37d..955797a0d98f60280855f0e31928231f81bf66c7 100644 (file)
@@ -25,6 +25,19 @@ proc chng {date desc} {
   puts "<DD><P><UL>$desc</UL></P></DD>"
 }
 
+chng {2002 Jun 24 (2.5.2)} {
+<li>Added the new <b>SQLITE_TEMP_MASTER</b> table which records the schema
+    for temporary tables in the same way that <b>SQLITE_MASTER</b> does for
+    persistent tables.</li>
+<li>Added an optimization to UNION ALL</li>
+<li>Fixed a bug in the processing of LEFT OUTER JOIN</li>
+<li>The LIMIT clause now works on subselects</li>
+<li>ORDER BY works on subselects</li>
+<li>There is a new TypeOf() function used to determine if an expression
+    is numeric or text.</li>
+<li>Autoincrement now works for INSERT from a SELECT.</li>
+}
+
 chng {2002 Jun 19 (2.5.1)} {
 <li>The query optimizer now attempts to implement the ORDER BY clause
     using an index.  Sorting is still used if not suitable index is
index 98024bfe98f30486db6422ff310e90f13101de64..68e332b716b2d3593e20cd9eb062a83f798e73a5 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this script to generated a faq.html output file
 #
-set rcsid {$Id: faq.tcl,v 1.10 2002/04/25 00:21:50 drh Exp $}
+set rcsid {$Id: faq.tcl,v 1.11 2002/06/25 01:09:13 drh Exp $}
 
 puts {<html>
 <head>
@@ -276,8 +276,19 @@ ORDER BY name;
   using UPDATE, INSERT, or DELETE.  The table is automatically updated by
   CREATE TABLE, CREATE INDEX, DROP TABLE, and DROP INDEX commands.</p>
 
-  <p>Temporary tables do not appear in the SQLITE_MASTER table.  At this time
-  there is no way to get a listing of temporary tables and indices.</p>
+  <p>Temporary tables do not appear in the SQLITE_MASTER table.  Temporary
+  tables and their indices and triggers occur in another special table
+  named SQLITE_TEMP_MASTER.  SQLITE_TEMP_MASTER works just like SQLITE_MASTER
+  except that it is only visible to the application that created the 
+  temporary tables.  To get a list of all tables, both permanent and
+  temporary, one can use a command similar to the following:
+</blockquote><pre>
+SELECT name FROM 
+   (SELECT * FROM sqlite_master UNION ALL
+    SELECT * FROM sqlite_temp_master)
+WHERE type='table'
+ORDER BY name
+</pre></blockquote>
 }
 
 faq {
index 35bb60721b32ba3d70b6df004fa0e3ce06571bd5..f5d3099c959ecbe59e5c8810d8ededd8270eedf3 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this Tcl script to generate the sqlite.html file.
 #
-set rcsid {$Id: lang.tcl,v 1.40 2002/06/12 22:33:54 drh Exp $}
+set rcsid {$Id: lang.tcl,v 1.41 2002/06/25 01:09:13 drh Exp $}
 
 puts {<html>
 <head>
@@ -236,7 +236,9 @@ See the section titled
 
 <p>The exact text
 of each CREATE INDEX statement is stored in the <b>sqlite_master</b>
-table.  Everytime the database is opened, all CREATE INDEX statements
+or <b>sqlite_temp_master</b> table, depending on whether the table
+being indexed is temporary.  Everytime the database is opened,
+all CREATE INDEX statements
 are read from the <b>sqlite_master</b> table and used to regenerate
 SQLite's internal representation of the index layout.</p>
 }
@@ -275,8 +277,8 @@ puts {
 <p>A CREATE TABLE statement is basically the keywords "CREATE TABLE"
 followed by the name of a new table and a parenthesized list of column
 definitions and constraints.  The table name can be either an identifier
-or a string.  The only reserved table name is "<b>sqlite_master</b>" which
-is the name of the table that records the database schema.</p>
+or a string.  Tables names that begin with "<b>sqlite_</b>" are reserved
+for use by the engine.</p>
 
 <p>Each column definition is the name of the column followed by the
 datatype for that column, then one or more optional column constraints.
@@ -343,6 +345,8 @@ SQLite's internal representation of the table layout.
 If the original command was a CREATE TABLE AS then then an equivalent
 CREATE TABLE statement is synthesized and store in <b>sqlite_master</b>
 in place of the original command.
+The text of CREATE TEMPORARY TABLE statements are stored in the
+<b>sqlite_temp_master</b> table.
 </p>
 }
 Section {CREATE TRIGGER} createtrigger
index 5d4fb06acccea10a0edbcbb67d74701ec93a4694..4954180441230180bb81a80a500b63e23bfd282b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this Tcl script to generate the sqlite.html file.
 #
-set rcsid {$Id: sqlite.tcl,v 1.16 2001/11/24 13:23:05 drh Exp $}
+set rcsid {$Id: sqlite.tcl,v 1.17 2002/06/25 01:09:13 drh Exp $}
 
 puts {<html>
 <head>
@@ -117,6 +117,14 @@ indices from the database.  You can not make manual changes
 to the sqlite_master table.
 </p>
 
+<p>
+The schema for TEMPORARY tables is not stored in the "sqlite_master" table
+since TEMPORARY tables are not visible to applications other than the
+application that created the table.  The schema for TEMPORARY tables
+is stored in another special table named "sqlite_temp_master".  The
+"sqlite_temp_master" table is temporary itself.
+</p>
+
 <h2>Special commands to sqlite</h2>
 
 <p>
@@ -335,8 +343,8 @@ puts {
 executing the following query:</p>
 
 <blockquote><pre>
-SELECT name FROM sqlite_master 
-WHERE type='table' 
+SELECT name FROM sqlite_master WHERE type='table' 
+UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table'
 ORDER BY name;
 </pre></blockquote>
 
@@ -376,7 +384,9 @@ puts {
 list mode, then entering the following query:</p>
 
 <blockquote><pre>
-SELECT sql FROM sqlite_master
+SELECT sql FROM 
+   (SELECT * FROM sqlite_master UNION ALL
+    SELECT * FROM sqlite_temp_master)
 WHERE type!='meta'
 ORDER BY tbl_name, type DESC, name
 </pre></blockquote>
@@ -385,7 +395,9 @@ ORDER BY tbl_name, type DESC, name
 want the schema for a single table, the query looks like this:</p>
 
 <blockquote><pre>
-SELECT sql FROM sqlite_master
+SELECT sql FROM
+   (SELECT * FROM sqlite_master UNION ALL
+    SELECT * FROM sqlite_temp_master)
 WHERE tbl_name LIKE '%s' AND type!='meta'
 ORDER BY type DESC, name
 </pre></blockquote>