]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Modifications to the VDBE to support more than one database file. (CVS 878)
authordrh <drh@noemail.net>
Wed, 19 Mar 2003 03:14:00 +0000 (03:14 +0000)
committerdrh <drh@noemail.net>
Wed, 19 Mar 2003 03:14:00 +0000 (03:14 +0000)
FossilOrigin-Name: 875da9eed981bfa27b98e95025f9fdbed74b4098

19 files changed:
manifest
manifest.uuid
src/btree.c
src/btree.h
src/build.c
src/delete.c
src/insert.c
src/main.c
src/os.c
src/os.h
src/pager.c
src/pager.h
src/printf.c
src/select.c
src/sqliteInt.h
src/update.c
src/vdbe.c
src/where.c
www/arch.tcl

index 6516711419a01a1d84647ab5851b2ec1d96ae5ad..d9eb81fc87375a21c061d5b26cd358e67affd567 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Do\snot\sallow\san\sempty\sstring\sto\sbe\sinserted\sinto\san\sINTEGER\sPRIMARY\sKEY.\s(CVS\s877)
-D 2003-03-07T19:50:07
+C Modifications\sto\sthe\sVDBE\sto\ssupport\smore\sthan\sone\sdatabase\sfile.\s(CVS\s878)
+D 2003-03-19T03:14:01
 F Makefile.in 6606854b1512f185b8e8c779b8d7fc2750463d64
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -19,30 +19,30 @@ F publish.sh 86b5e8535830a2588f62ce1d5d1ef00e1dede23a
 F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
 F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
 F src/auth.c f37bfc9451b8c1fa52f34adff474560018892729
-F src/btree.c 2a0305ccbe617266ac3524805e0c6ef55a9f9cb7
-F src/btree.h 36a7a26a29382c2b1a519b42bb125880d46d00d4
-F src/build.c 25d5f901c456d6554020a33c4e457b6672181623
-F src/delete.c cbd499f3f9297504c42e328af89bef1a2113d04c
+F src/btree.c 327819bb858d534072f5004973f8bcdd50f133d6
+F src/btree.h 8209bfadf5845d4fdaa60f471bb360f894cd4095
+F src/build.c be6db117e97d8c47596b09480b1aa2626f083ab3
+F src/delete.c d76f767696b0ee3661e937ccf4c6c45857c1b78e
 F src/encode.c faf03741efe921755ec371cf4a6984536de00042
 F src/expr.c bd690b3a6174e97a0f16800e78c8aeae749a4e71
 F src/func.c 90c583f0b91220f7cd411a2407deaf9327245d63
 F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
-F src/insert.c 13c2ef8984ce0f38701a8af89e4ba7a3c86c0701
-F src/main.c 51688c476f02b214b30d57902c6fdea895c1dddd
+F src/insert.c 02ac6147cb360385be94b0e6f572db131505d1c9
+F src/main.c d0418850385895202f9b28e0bd7d0b0fdfd868df
 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
-F src/os.c b12203e1cc4f3be170d312f624df8cc6e0d1e4d2
-F src/os.h afa3e096213bad86845f8bdca81a9e917505e401
-F src/pager.c 47509f6b2dbf1cba46e52602c1dacf04f9d66e10
-F src/pager.h e5b8e301a732007766dc04880c764d7ee1aa34dd
+F src/os.c dfed46091f69cd2d1e601f8a214d41344f2b00b6
+F src/os.h aa52f0c9da321ff6134d19f2ca959e18e33615d0
+F src/pager.c dd1dfa4d929a58b44175f3117360ff1553671173
+F src/pager.h 97d9a8cc5103750efd8037d71ebfb41849ef2f2f
 F src/parse.y 4c4b2ff3d20d4a2afb51f05ac18edde20a173abe
-F src/printf.c f8fd911a8738f9b2eb07aca2870473d34707055d
+F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c d12d4c12d6536deccdede90b482d24f0590f5dc8
+F src/select.c 06ddc007c20862b3beb8c1c2504db664335d6706
 F src/shell.c 0d260a007e0668fc7dda2b0c89bd597ef2966ec6
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 6f648803f2ffb9beb35cb1cfa42b323d55519171
-F src/sqliteInt.h f4428fdb240e343ac913f1123bafb48d61f60a7e
+F src/sqliteInt.h 888faaa05195bcdb24a9aa22108894b778132cbc
 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
 F src/tclsqlite.c 8167d40fd34036701e07492d07a6f9e5c4015241
 F src/test1.c 7ad4e6308dde0bf5a0f0775ce20cb2ec37a328f8
@@ -51,11 +51,11 @@ F src/test3.c c12ea7f1c3fbbd58904e81e6cb10ad424e6fc728
 F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
 F src/tokenize.c bc40937d6666f188037aa3e54f0a2661a6fef6d1
 F src/trigger.c da142decd2808bc39e801f3bb1f161dbc2bd4005
-F src/update.c f06afa9bf1f777d17702e0f6e33cf44c44bc4f75
+F src/update.c c523bf6ef4106ca45761a3e54fc6d09ee273804b
 F src/util.c 73b668d1ed468df650dc00685a5e4ffa6887feb4
-F src/vdbe.c 1b54fc0b5e3ffdcf5dc3da537b597ab354753950
+F src/vdbe.c e2313377c463fdeba2e8eb3d9e3336292c60f51e
 F src/vdbe.h ed43771f1dc2b994d5c484fdf2eab357c6ef0ee3
-F src/where.c ba96cab1fb076f025b6eae3fb0aead769fd2c96f
+F src/where.c 3111c1c209023e4f6b7b7eb0df48cef0010967c3
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/auth.test 33e8b9680eb0ce521c54096fff1c9ab506c7dfb8
 F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678
@@ -132,7 +132,7 @@ F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
-F www/arch.tcl 679a0c48817f71bc91d5911ef386e5ef35d4f178
+F www/arch.tcl 44b589fc01d6829d43447ab40588b00aec5b9734
 F www/audit.tcl 90e09d580f79c7efec0c7d6f447b7ec5c2dce5c0
 F www/c_interface.tcl 5b54a6f65b70b02da2f6df4f8a23a4b10032e89e
 F www/changes.tcl 7eb04deffbe116cdb558443f8f7df74ebd021daa
@@ -155,7 +155,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 13e501d190e327cc6fc16e182819ea9d7bb9c566
-R c4e061e42d78dac00088004a55073ed7
+P 2aba40bea5fc1c4aef8cfd4c790d40808821ca14
+R 5e37bd21e0d92e541d7a5b6e1113c76c
 U drh
-Z 23e79ce4ba202a0d57ab05666f881be6
+Z 586a66fe460de3c14ba71e3472471b48
index 5431fa56430e5b10c01f689cb07f1fa137550d1f..35b85046ec2ac3582372c1ebb44d443e094ad45a 100644 (file)
@@ -1 +1 @@
-2aba40bea5fc1c4aef8cfd4c790d40808821ca14
\ No newline at end of file
+875da9eed981bfa27b98e95025f9fdbed74b4098
\ No newline at end of file
index 9745f6d9086a67adaee8ffe82e71b517b778ed33..a8fd80e4d0585363b8ee1011981970c50821bcdd 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.83 2003/02/12 14:09:43 drh Exp $
+** $Id: btree.c,v 1.84 2003/03/19 03:14:01 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -2874,6 +2874,105 @@ int sqliteBtreeDropTable(Btree *pBt, int iTable){
   return rc;  
 }
 
+#if 0 /* UNTESTED */
+/*
+** Copy all cell data from one database file into another.
+** pages back the freelist.
+*/
+static int copyCell(Btree *pBtFrom, BTree *pBtTo, Cell *pCell){
+  Pager *pFromPager = pBtFrom->pPager;
+  OverflowPage *pOvfl;
+  Pgno ovfl, nextOvfl;
+  Pgno *pPrev;
+  int rc = SQLITE_OK;
+  MemPage *pNew, *pPrevPg;
+  Pgno new;
+
+  if( NKEY(pBtTo, pCell->h) + NDATA(pBtTo, pCell->h) <= MX_LOCAL_PAYLOAD ){
+    return SQLITE_OK;
+  }
+  pPrev = &pCell->ovfl;
+  pPrevPg = 0;
+  ovfl = SWAB32(pBtTo, pCell->ovfl);
+  while( ovfl && rc==SQLITE_OK ){
+    rc = sqlitepager_get(pFromPager, ovfl, (void**)&pOvfl);
+    if( rc ) return rc;
+    nextOvfl = SWAB32(pBtFrom, pOvfl->iNext);
+    rc = allocatePage(pBtTo, &pNew, &new, 0);
+    if( rc==SQLITE_OK ){
+      rc = sqlitepager_write(pNew);
+      if( rc==SQLITE_OK ){
+        memcpy(pNew, pOvfl, SQLITE_PAGE_SIZE);
+        *pPrev = SWAB32(pBtTo, new);
+        if( pPrevPg ){
+          sqlitepager_unref(pPrevPg);
+        }
+        pPrev = &pOvfl->iNext;
+        pPrevPg = pNew;
+      }
+    }
+    sqlitepager_unref(pOvfl);
+    ovfl = nextOvfl;
+  }
+  if( pPrevPg ){
+    sqlitepager_unref(pPrevPg);
+  }
+  return rc;
+}
+#endif
+
+
+#if 0 /* UNTESTED */
+/*
+** Copy a page of data from one database over to another.
+*/
+static int copyDatabasePage(
+  Btree *pBtFrom,
+  Pgno pgnoFrom,
+  Btree *pBtTo,
+  Pgno *pTo
+){
+  MemPage *pPageFrom, *pPage;
+  Pgno to;
+  int rc;
+  Cell *pCell;
+  int idx;
+
+  rc = sqlitepager_get(pBtFrom->pPager, pgno, (void**)&pPageFrom);
+  if( rc ) return rc;
+  rc = allocatePage(pBt, &pPage, pTo, 0);
+  if( rc==SQLITE_OK ){
+    rc = sqlitepager_write(pPage);
+  }
+  if( rc==SQLITE_OK ){
+    memcpy(pPage, pPageFrom, SQLITE_PAGE_SIZE);
+    idx = SWAB16(pBt, pPage->u.hdr.firstCell);
+    while( idx>0 ){
+      pCell = (Cell*)&pPage->u.aDisk[idx];
+      idx = SWAB16(pBt, pCell->h.iNext);
+      if( pCell->h.leftChild ){
+        Pgno newChld;
+        rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pCell->h.leftChild),
+                              pBtTo, &newChld);
+        if( rc ) return rc;
+        pCell->h.leftChild = SWAB32(pBtFrom, newChld);
+      }
+      rc = copyCell(pBtFrom, pBtTo, pCell);
+      if( rc ) return rc;
+    }
+    if( pPage->u.hdr.rightChild ){
+      Pgno newChld;
+      rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pPage->u.hdr.rightChild), 
+                            pBtTo, &newChld);
+      if( rc ) return rc;
+      pPage->u.hdr.rightChild = SWAB32(pBtTo, newChild);
+    }
+  }
+  sqlitepager_unref(pPage);
+  return rc;
+}
+#endif
+
 /*
 ** Read the meta-information out of a database file.
 */
index b92dce6e28205af787e3467adff74409b0692b09..ef6f781277af289888536abee7ba7ae82b2051ec 100644 (file)
@@ -13,7 +13,7 @@
 ** subsystem.  See comments in the source code for a detailed description
 ** of what each interface routine does.
 **
-** @(#) $Id: btree.h,v 1.27 2003/02/12 14:09:44 drh Exp $
+** @(#) $Id: btree.h,v 1.28 2003/03/19 03:14:01 drh Exp $
 */
 #ifndef _BTREE_H_
 #define _BTREE_H_
@@ -37,6 +37,7 @@ int sqliteBtreeCreateTable(Btree*, int*);
 int sqliteBtreeCreateIndex(Btree*, int*);
 int sqliteBtreeDropTable(Btree*, int);
 int sqliteBtreeClearTable(Btree*, int);
+int sqliteBtreeCopyTable(Btree *pFrom, int iFrom, Btree *pTo, int iTo);
 
 int sqliteBtreeCursor(Btree*, int iTable, int wrFlag, BtCursor **ppCur);
 int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes);
index 45b82b0b5e1b4486748b57b315f6df39a86ea513..0c763d07a7def7f763cf7e25e10d225ddcd50f90 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.131 2003/03/01 19:45:34 drh Exp $
+** $Id: build.c,v 1.132 2003/03/19 03:14:01 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -85,7 +85,7 @@ void sqliteExec(Parse *pParse){
     if( pParse->useCallback ){
       if( pParse->explain ){
         rc = sqliteVdbeList(v);
-        db->next_cookie = db->schema_cookie;
+        db->next_cookie = db->aDb[0].schema_cookie;
       }else{
         sqliteVdbeExec(v);
       }
@@ -211,7 +211,7 @@ void sqliteRollbackInternalChanges(sqlite *db){
 ** This routine is called when a commit occurs.
 */
 void sqliteCommitInternalChanges(sqlite *db){
-  db->schema_cookie = db->next_cookie;
+  db->aDb[0].schema_cookie = db->next_cookie;
   db->flags &= ~SQLITE_InternChanges;
 }
 
@@ -310,13 +310,8 @@ char *sqliteTableNameFromToken(Token *pName){
 ** 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);
-  }
+  sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
+  sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
 }
 
 /*
@@ -383,8 +378,8 @@ void sqliteStartTable(
   /* 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( isTemp && db->aDb[1].pBt==0 ){
+    int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->aDb[1].pBt);
     if( rc!=SQLITE_OK ){
       sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database "
         "file for storing temporary tables", 0);
@@ -392,7 +387,7 @@ void sqliteStartTable(
       return;
     }
     if( db->flags & SQLITE_InTrans ){
-      rc = sqliteBtreeBeginTrans(db->pBeTemp);
+      rc = sqliteBtreeBeginTrans(db->aDb[1].pBt);
       if( rc!=SQLITE_OK ){
         sqliteSetNString(&pParse->zErrMsg, "unable to get a write lock on "
           "the temporary database file", 0);
@@ -713,8 +708,8 @@ void sqliteAddCollateType(Parse *pParse, int collType){
 ** 1 chance in 2^32.  So we're safe enough.
 */
 void sqliteChangeCookie(sqlite *db, Vdbe *v){
-  if( db->next_cookie==db->schema_cookie ){
-    db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
+  if( db->next_cookie==db->aDb[0].schema_cookie ){
+    db->next_cookie = db->aDb[0].schema_cookie + sqliteRandomByte() + 1;
     db->flags |= SQLITE_InternChanges;
     sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
     sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
@@ -901,8 +896,8 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
     }
     sqliteVdbeAddOp(v, OP_Close, 0, 0);
     if( pSelect ){
-      int op = p->isTemp ? OP_OpenWrAux : OP_OpenWrite;
-      sqliteVdbeAddOp(v, op, 1, 0);
+      sqliteVdbeAddOp(v, OP_Integer, p->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
       pParse->nTab = 2;
       sqliteSelect(pParse, pSelect, SRT_Table, 1, 0, 0, 0);
     }
@@ -1647,11 +1642,8 @@ void sqliteCreateIndex(
     pIndex->tnum = 0;
     if( pTable ){
       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
-      if( isTemp ){
-        sqliteVdbeAddOp(v, OP_OpenWrAux, 1, 0);
-      }else{
-        sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
-      }
+      sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
     }
     addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
     if( pStart && pEnd ){
@@ -1661,7 +1653,8 @@ void sqliteCreateIndex(
     sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
     sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
     if( pTable ){
-      sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
       sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
       lbl2 = sqliteVdbeMakeLabel(v);
       sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2);
@@ -1940,16 +1933,16 @@ void sqliteCopy(
   }
   v = sqliteGetVdbe(pParse);
   if( v ){
-    int openOp;
     sqliteBeginWriteOperation(pParse, 1, pTab->isTemp);
     addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
     sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
     sqliteVdbeDequoteP3(v, addr);
-    openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
-    sqliteVdbeAddOp(v, openOp, 0, pTab->tnum);
+    sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+    sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum);
     sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
     for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
-      sqliteVdbeAddOp(v, openOp, i, pIdx->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum);
       sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
     }
     if( db->flags & SQLITE_CountRows ){
@@ -2019,7 +2012,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
 void sqliteBeginTransaction(Parse *pParse, int onError){
   sqlite *db;
 
-  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
+  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
   if( pParse->nErr || sqlite_malloc_failed ) return;
   if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0) ) return;
   if( db->flags & SQLITE_InTrans ){
@@ -2039,7 +2032,7 @@ void sqliteBeginTransaction(Parse *pParse, int onError){
 void sqliteCommitTransaction(Parse *pParse){
   sqlite *db;
 
-  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
+  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
   if( pParse->nErr || sqlite_malloc_failed ) return;
   if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0) ) return;
   if( (db->flags & SQLITE_InTrans)==0 ){
@@ -2060,7 +2053,7 @@ void sqliteRollbackTransaction(Parse *pParse){
   sqlite *db;
   Vdbe *v;
 
-  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
+  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
   if( pParse->nErr || sqlite_malloc_failed ) return;
   if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0) ) return;
   if( (db->flags & SQLITE_InTrans)==0 ){
@@ -2077,6 +2070,21 @@ void sqliteRollbackTransaction(Parse *pParse){
   db->onError = OE_Default;
 }
 
+/*
+** Generate VDBE code that will verify the schema cookie for all
+** named database files.
+*/
+void sqliteCodeVerifySchema(Parse *pParse){
+  int i;
+  sqlite *db = pParse->db;
+  Vdbe *v = sqliteGetVdbe(pParse);
+  for(i=0; i<db->nDb; i++){
+    if( db->aDb[i].zName==0 || db->aDb[i].pBt==0 ) continue;
+    sqliteVdbeAddOp(v, OP_VerifyCookie, 0, db->aDb[i].schema_cookie);
+  }
+  pParse->schemaVerified = 1;
+}
+
 /*
 ** Generate VDBE code that prepares for doing an operation that
 ** might change the database.
@@ -2101,13 +2109,14 @@ void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int tempOnly){
   if( v==0 ) return;
   if( pParse->trigStack ) return; /* if this is in a trigger */
   if( (pParse->db->flags & SQLITE_InTrans)==0 ){
-    sqliteVdbeAddOp(v, OP_Transaction, tempOnly, 0);
+    sqliteVdbeAddOp(v, OP_Transaction, 1, 0);
     if( !tempOnly ){
-      sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
-      pParse->schemaVerified = 1;
+      sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
+      sqliteCodeVerifySchema(pParse);
     }
   }else if( setCheckpoint ){
     sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0);
+    sqliteVdbeAddOp(v, OP_Checkpoint, 1, 0);
   }
 }
 
@@ -2254,7 +2263,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
       sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
       sqliteEndWriteOperation(pParse);
       db->cache_size = db->cache_size<0 ? -size : size;
-      sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
+      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
     }
   }else
 
@@ -2287,7 +2296,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
       if( size<0 ) size = -size;
       if( db->cache_size<0 ) size = -size;
       db->cache_size = size;
-      sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
+      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
     }
   }else
 
@@ -2349,8 +2358,8 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
       sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
       sqliteEndWriteOperation(pParse);
       db->cache_size = size;
-      sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
-      sqliteBtreeSetSafetyLevel(db->pBe, db->safety_level);
+      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
+      sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
     }
   }else
 
@@ -2377,8 +2386,8 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
       db->safety_level = getSafetyLevel(zRight)+1;
       if( db->safety_level==1 ) size = -size;
       db->cache_size = size;
-      sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
-      sqliteBtreeSetSafetyLevel(db->pBe, db->safety_level);
+      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
+      sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
     }
   }else
 
@@ -2535,21 +2544,23 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
   if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
     static VdbeOp checkDb[] = {
       { OP_SetInsert,   0, 0,        "2"},
-      { OP_Open,        0, 2,        0},
-      { OP_Rewind,      0, 6,        0},
-      { OP_Column,      0, 3,        0},    /* 3 */
+      { OP_Integer,     0, 0,        0},   
+      { OP_OpenRead,    0, 2,        0},
+      { OP_Rewind,      0, 7,        0},
+      { OP_Column,      0, 3,        0},    /* 4 */
       { OP_SetInsert,   0, 0,        0},
-      { OP_Next,        0, 3,        0},
-      { OP_IntegrityCk, 0, 0,        0},    /* 6 */
+      { OP_Next,        0, 4,        0},
+      { OP_IntegrityCk, 0, 0,        0},    /* 7 */
       { OP_ColumnName,  0, 0,        "integrity_check"},
       { OP_Callback,    1, 0,        0},
       { OP_SetInsert,   1, 0,        "2"},
-      { OP_OpenAux,     1, 2,        0},
-      { OP_Rewind,      1, 15,       0},
-      { OP_Column,      1, 3,        0},    /* 12 */
+      { OP_Integer,     1, 0,        0},
+      { OP_OpenRead,    1, 2,        0},
+      { OP_Rewind,      1, 17,       0},
+      { OP_Column,      1, 3,        0},    /* 14 */
       { OP_SetInsert,   1, 0,        0},
-      { OP_Next,        1, 12,       0},
-      { OP_IntegrityCk, 1, 1,        0},    /* 15 */
+      { OP_Next,        1, 14,       0},
+      { OP_IntegrityCk, 1, 1,        0},    /* 17 */
       { OP_Callback,    1, 0,        0},
     };
     sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
index 65e5075b499038cc3ba236f706e42f42444835fd..62bcf9ca1e697fc5ff0a203370b23e03c69673a8 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.45 2003/01/13 23:27:33 drh Exp $
+** $Id: delete.c,v 1.46 2003/03/19 03:14:01 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -83,7 +83,6 @@ void sqliteDeleteFrom(
   Index *pIdx;           /* For looping over indices of the table */
   int base;              /* Index of the first available table cursor */
   sqlite *db;            /* Main database structure */
-  int openOp;            /* Opcode used to open a cursor to the table */
 
   int row_triggers_exist = 0;
   int oldIdx = -1;
@@ -173,8 +172,8 @@ void sqliteDeleteFrom(
       ** entries in the table. */
       int endOfLoop = sqliteVdbeMakeLabel(v);
       int addr;
-      openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
-      sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
       sqliteVdbeAddOp(v, OP_Rewind, base, sqliteVdbeCurrentAddr(v)+2);
       addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
       sqliteVdbeAddOp(v, OP_Next, base, addr);
@@ -220,9 +219,8 @@ void sqliteDeleteFrom(
     if( row_triggers_exist ){
       addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
-
-      openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
-      sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
       sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
       sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
 
@@ -251,10 +249,11 @@ void sqliteDeleteFrom(
     ** cursors are opened only once on the outside the loop.
     */
     pParse->nTab = base + 1;
-    openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
-    sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
+    sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+    sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
     for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
-      sqliteVdbeAddOp(v, openOp, pParse->nTab++, pIdx->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum);
     }
 
     /* This is the beginning of the delete loop when there are no
index f90e2ab0d198987aefdaa45352f9d42560b3b0d6..5b96f48a1b81824cbe1dfd5bd5e008fbf84fae26 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.72 2003/01/29 18:46:52 drh Exp $
+** $Id: insert.c,v 1.73 2003/03/19 03:14:01 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -100,7 +100,6 @@ 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 */
   int keyColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */
   int endOfLoop;        /* Label for the end of the insertion loop */
   int useTempTable;     /* Store SELECT results in intermediate table */
@@ -198,7 +197,7 @@ void sqliteInsert(
     ** should be written into a temporary table.  Set to FALSE if each
     ** row of the SELECT can be written directly into the result table.
     */
-    opCode = pTab->isTemp ? OP_OpenTemp : OP_Open;
+    opCode = pTab->isTemp ? OP_OpenTemp : OP_OpenRead;
     useTempTable = row_triggers_exist || sqliteVdbeFindOp(v,opCode,pTab->tnum);
 
     if( useTempTable ){
@@ -329,11 +328,12 @@ void sqliteInsert(
   /* Open tables and indices if there are no row triggers */
   if( !row_triggers_exist ){
     base = pParse->nTab;
-    openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
-    sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
+    sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+    sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
     sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
     for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
-      sqliteVdbeAddOp(v, openOp, idx+base, pIdx->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum);
       sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
     }
     pParse->nTab += idx;
@@ -390,11 +390,12 @@ void sqliteInsert(
     /* Open the tables and indices for the INSERT */
     if( !pTab->pSelect ){
       base = pParse->nTab;
-      openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
-      sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
       sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
       for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
-        sqliteVdbeAddOp(v, openOp, idx+base, pIdx->tnum);
+        sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+        sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum);
         sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
       }
       pParse->nTab += idx;
index 8fa81d83c1a5c655e409cf65c45229dedabd39e4..cf1481418d28e8c882a6add1bcfed73a5b1b88df 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.114 2003/02/16 22:21:32 drh Exp $
+** $Id: main.c,v 1.115 2003/03/19 03:14:02 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -249,8 +249,8 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
 
   /* Create a cursor to hold the database open
   */
-  if( db->pBe==0 ) return SQLITE_OK;
-  rc = sqliteBtreeCursor(db->pBe, 2, 0, &curMain);
+  if( db->aDb[0].pBt==0 ) return SQLITE_OK;
+  rc = sqliteBtreeCursor(db->aDb[0].pBt, 2, 0, &curMain);
   if( rc ){
     sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
     sqliteResetInternalSchema(db);
@@ -259,23 +259,22 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
 
   /* Get the database meta information
   */
-  rc = sqliteBtreeGetMeta(db->pBe, meta);
+  rc = sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
   if( rc ){
     sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
     sqliteResetInternalSchema(db);
     sqliteBtreeCloseCursor(curMain);
     return rc;
   }
-  db->schema_cookie = meta[1];
-  db->next_cookie = db->schema_cookie;
+  db->next_cookie = db->aDb[0].schema_cookie = meta[1];
   db->file_format = meta[2];
   size = meta[3];
   if( size==0 ){ size = MAX_PAGES; }
   db->cache_size = size;
-  sqliteBtreeSetCacheSize(db->pBe, size);
+  sqliteBtreeSetCacheSize(db->aDb[0].pBt, size);
   db->safety_level = meta[4];
   if( db->safety_level==0 ) db->safety_level = 2;
-  sqliteBtreeSetSafetyLevel(db->pBe, db->safety_level);
+  sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
 
   /*
   **     file_format==1    Version 2.1.0.
@@ -297,7 +296,6 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
   */
   memset(&sParse, 0, sizeof(sParse));
   sParse.db = db;
-  sParse.pBe = db->pBe;
   sParse.xCallback = sqliteInitCallback;
   sParse.pArg = (void*)&initData;
   sParse.initFlag = 1;
@@ -308,7 +306,7 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
   if( sqlite_malloc_failed ){
     sqliteSetString(pzErrMsg, "out of memory", 0);
     sParse.rc = SQLITE_NOMEM;
-    sqliteBtreeRollback(db->pBe);
+    sqliteBtreeRollback(db->aDb[0].pBt);
     sqliteResetInternalSchema(db);
   }
   if( sParse.rc==SQLITE_OK ){
@@ -363,9 +361,11 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
   db->onError = OE_Default;
   db->priorNewRowid = 0;
   db->magic = SQLITE_MAGIC_BUSY;
+  db->nDb = 2;
+  db->aDb = db->aDbStatic;
   
   /* Open the backend database driver */
-  rc = sqliteBtreeOpen(zFilename, 0, MAX_PAGES, &db->pBe);
+  rc = sqliteBtreeOpen(zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
   if( rc!=SQLITE_OK ){
     switch( rc ){
       default: {
@@ -376,6 +376,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
     sqliteStrRealloc(pzErrMsg);
     return 0;
   }
+  db->aDb[0].zName = "main";
 
   /* Attempt to read the schema */
   sqliteRegisterBuiltinFunctions(db);
@@ -412,9 +413,9 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
       &initData,
       &zErr);
     if( rc==SQLITE_OK ){
-      sqliteBtreeGetMeta(db->pBe, meta);
+      sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
       meta[2] = 4;
-      sqliteBtreeUpdateMeta(db->pBe, meta);
+      sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
       sqlite_exec(db, "COMMIT", 0, 0, 0);
     }
     if( rc!=SQLITE_OK ){
@@ -457,17 +458,22 @@ int sqlite_changes(sqlite *db){
 */
 void sqlite_close(sqlite *db){
   HashElem *i;
+  int j;
   db->want_to_close = 1;
   if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){
     /* printf("DID NOT CLOSE\n"); fflush(stdout); */
     return;
   }
   db->magic = SQLITE_MAGIC_CLOSED;
-  sqliteBtreeClose(db->pBe);
-  sqliteResetInternalSchema(db);
-  if( db->pBeTemp ){
-    sqliteBtreeClose(db->pBeTemp);
+  for(j=0; j<db->nDb; j++){
+    if( db->aDb[j].pBt ){
+      sqliteBtreeClose(db->aDb[j].pBt);
+    }
   }
+  if( db->aDb!=db->aDbStatic ){
+    sqliteFree(db->aDb);
+  }
+  sqliteResetInternalSchema(db);
   for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
     FuncDef *pFunc, *pNext;
     for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
@@ -592,6 +598,20 @@ int sqlite_complete(const char *zSql){
   return seenText && isComplete && requireEnd==0;
 }
 
+/*
+** Rollback all database files.
+*/
+void sqliteRollbackAll(sqlite *db){
+  int i;
+  for(i=0; i<db->nDb; i++){
+    if( db->aDb[i].pBt ){
+      sqliteBtreeRollback(db->aDb[i].pBt);
+      db->aDb[i].inTrans = 0;
+    }
+  }
+  sqliteRollbackInternalChanges(db);
+}
+
 /*
 ** This routine does the work of either sqlite_exec() or sqlite_compile().
 ** It works like sqlite_exec() if pVm==NULL and it works like sqlite_compile()
@@ -632,7 +652,6 @@ static int sqliteMain(
   if( db->pVdbe==0 ){ db->nChange = 0; }
   memset(&sParse, 0, sizeof(sParse));
   sParse.db = db;
-  sParse.pBe = db->pBe;
   sParse.xCallback = xCallback;
   sParse.pArg = pArg;
   sParse.useCallback = ppVm==0;
@@ -643,10 +662,9 @@ static int sqliteMain(
   if( sqlite_malloc_failed ){
     sqliteSetString(pzErrMsg, "out of memory", 0);
     sParse.rc = SQLITE_NOMEM;
-    sqliteBtreeRollback(db->pBe);
-    if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
-    db->flags &= ~SQLITE_InTrans;
+    sqliteRollbackAll(db);
     sqliteResetInternalSchema(db);
+    db->flags &= ~SQLITE_InTrans;
   }
   if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
   if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
@@ -965,10 +983,10 @@ int sqlite_open_aux_file(sqlite *db, const char *zName, char **pzErrMsg){
   if( zName && zName[0]==0 ) zName = 0;
   if( sqliteSafetyOn(db) ) goto openaux_misuse;
   sqliteResetInternalSchema(db);
-  if( db->pBeTemp!=0 ){
-    sqliteBtreeClose(db->pBeTemp);
+  if( db->aDb[1].pBt!=0 ){
+    sqliteBtreeClose(db->aDb[1].pBt);
   }
-  rc = sqliteBtreeOpen(zName, 0, MAX_PAGES, &db->pBeTemp);
+  rc = sqliteBtreeOpen(zName, 0, MAX_PAGES, &db->aDb[1].pBt);
   if( rc ){
     if( zName==0 ) zName = "a temporary file";
     sqliteSetString(pzErrMsg, "unable to open ", zName, 
index d0b50dc4f1c0acb7a77e84b163b7066c5712f0ea..77bdf3ae00eb0bae93d80a870ea3813f7de9b6fb 100644 (file)
--- a/src/os.c
+++ b/src/os.c
@@ -268,6 +268,30 @@ int sqliteOsFileExists(const char *zFilename){
 }
 
 
+/*
+** Change the name of an existing file.
+*/
+int sqliteOsRename(const char *zOldName, const char *zNewName){
+#if OS_UNIX
+  if( link(zOldName, zNewName) ){
+    return SQLITE_ERROR;
+  }
+  unlink(zOldName);
+  return SQLITE_OK;
+#endif
+#if OS_WIN
+  if( !MoveFile(zOldName, zNewName) ){
+    return SQLITE_ERROR;
+  }
+  return SQLITE_OK;
+#endif
+#if OS_MAC
+  /**** FIX ME ***/
+  return SQLITE_ERROR;
+#endif
+}
+
+
 /*
 ** Attempt to open a file for both reading and writing.  If that
 ** fails, try opening it read-only.  If the file does not exist,
index 8491d90dfe524602d111dcd7f0d014e133fe6b75..f9784ef52536b482f54548b1984c0b0e5dfb0739 100644 (file)
--- a/src/os.h
+++ b/src/os.h
 
 int sqliteOsDelete(const char*);
 int sqliteOsFileExists(const char*);
+int sqliteOsFileRename(const char*, const char*);
 int sqliteOsOpenReadWrite(const char*, OsFile*, int*);
 int sqliteOsOpenExclusive(const char*, OsFile*, int);
 int sqliteOsOpenReadOnly(const char*, OsFile*);
index bd191d6e1d68f7e7cdc093f525c3ba4bda97c46e..58eb8cee41070591237cac2883408fc81313d314 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.78 2003/02/16 19:13:37 drh Exp $
+** @(#) $Id: pager.c,v 1.79 2003/03/19 03:14:02 drh Exp $
 */
 #include "os.h"         /* Must be first to enable large file support */
 #include "sqliteInt.h"
@@ -1722,6 +1722,25 @@ int sqlitepager_iswriteable(void *pData){
   return pPg->dirty;
 }
 
+/*
+** Replace the content of a single page with the information in the third
+** argument.
+*/
+int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void *pData){
+  void *pPage;
+  int rc;
+
+  rc = sqlitepager_get(pPager, pgno, &pPage);
+  if( rc==SQLITE_OK ){
+    rc = sqlitepager_write(pPage);
+    if( rc==SQLITE_OK ){
+      memcpy(pPage, pData, SQLITE_PAGE_SIZE);
+    }
+    sqlitepager_unref(pPage);
+  }
+  return rc;
+}
+
 /*
 ** A call to this routine tells the pager that it is not necessary to
 ** write the information on page "pgno" back to the disk, even though
index 4735b82d6b88acd11ff88224a1bba66f4ca6b291..bba8220ace9c8bc4bea8007ec7581e63ecc65c51 100644 (file)
@@ -13,7 +13,7 @@
 ** subsystem.  The page cache subsystem reads and writes a file a page
 ** at a time and provides a journal for rollback.
 **
-** @(#) $Id: pager.h,v 1.20 2003/02/12 14:09:44 drh Exp $
+** @(#) $Id: pager.h,v 1.21 2003/03/19 03:14:02 drh Exp $
 */
 
 /*
@@ -59,6 +59,7 @@ int sqlitepager_unref(void*);
 Pgno sqlitepager_pagenumber(void*);
 int sqlitepager_write(void*);
 int sqlitepager_iswriteable(void*);
+int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void*);
 int sqlitepager_pagecount(Pager*);
 int sqlitepager_begin(void*);
 int sqlitepager_commit(Pager*);
index 387ea1c2da2ba6ad25d26db2725a652094c9662a..8587f80d28204816a18505b6a3e5babf96fa3099 100644 (file)
@@ -687,7 +687,6 @@ static void mout(void *arg, char *zNewText, int nNewChar){
 char *sqliteMPrintf(const char *zFormat, ...){
   va_list ap;
   struct sgMprintf sMprintf;
-  char *zNew;
   char zBuf[200];
 
   sMprintf.nChar = 0;
index 4b462486d4183deea1143c7657351f406300943d..eb2892f24348098ece8bbfc446cb6fa744b61989 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.126 2003/02/02 12:41:26 drh Exp $
+** $Id: select.c,v 1.127 2003/03/19 03:14:02 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -1768,7 +1768,6 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
   Index *pIdx;
   int base;
   Vdbe *v;
-  int openOp;
   int seekOp;
   int cont;
   ExprList eList;
@@ -1828,17 +1827,17 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
   ** or last entry in the main table.
   */
   if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){
-    sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
-    pParse->schemaVerified = 1;
+    sqliteCodeVerifySchema(pParse);
   }
-  openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
   base = p->base;
-  sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
+  sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+  sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
   sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
   if( pIdx==0 ){
     sqliteVdbeAddOp(v, seekOp, base, 0);
   }else{
-    sqliteVdbeAddOp(v, openOp, base+1, pIdx->tnum);
+    sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+    sqliteVdbeAddOp(v, OP_OpenRead, base+1, pIdx->tnum);
     sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
     sqliteVdbeAddOp(v, seekOp, base+1, 0);
     sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0);
index e8f1682046528defa51699fa3c0675bcbea65372..63610ae8ea47fadba8dedacd2f500174d957d2e9 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.162 2003/02/16 22:21:32 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.163 2003/03/19 03:14:02 drh Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -187,6 +187,21 @@ typedef struct Trigger Trigger;
 typedef struct TriggerStep TriggerStep;
 typedef struct TriggerStack TriggerStack;
 typedef struct FKey FKey;
+typedef struct Db Db;
+
+/*
+** Each database file to be accessed by the system is an instance
+** of the following structure.  There are normally two of these structures
+** in the sqlite.aDb[] array.  aDb[0] is the main database file and
+** aDb[1] is the database file used to hold temporary tables.  But
+** additional databases may be attached to the engine.
+*/
+struct Db {
+  char *zName;         /* Name of this database */
+  Btree *pBt;          /* The B*Tree structure for this database file */
+  int schema_cookie;   /* Database schema version number for this file */
+  u8 inTrans;          /* True if a transaction is underway for this backend */
+};
 
 /*
 ** Each database is an instance of the following structure.
@@ -204,14 +219,14 @@ typedef struct FKey FKey;
 **                       text datatypes.
 */
 struct sqlite {
-  Btree *pBe;                   /* The B*Tree backend */
-  Btree *pBeTemp;               /* Backend for session temporary tables */
+  int nDb;                      /* Number of backends currently in use */
+  Db *aDb;                      /* All backends */
+  Db aDbStatic[2];              /* Static space for the 2 default backends */
   int flags;                    /* Miscellanous flags. See below */
   u8 file_format;               /* What file format version is this database? */
   u8 safety_level;              /* How aggressive at synching data to disk */
   u8 want_to_close;             /* Close after all VDBEs are deallocated */
-  int schema_cookie;            /* Magic number that changes with the schema */
-  int next_cookie;              /* Value of schema_cookie after commit */
+  int next_cookie;              /* Next value of aDb[0].schema_cookie */
   int cache_size;               /* Number of pages to use in the cache */
   int nTable;                   /* Number of tables in the database */
   void *pBusyArg;               /* 1st Argument to the busy callback */
@@ -348,7 +363,7 @@ 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 isTemp;       /* True if stored in db->pBeTemp instead of db->pBe */
+  u8 isTemp;       /* Index into sqlite.aDb[] of the backend for this table */
   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 */
@@ -731,7 +746,6 @@ struct AggExpr {
 */
 struct Parse {
   sqlite *db;          /* The main database structure */
-  Btree *pBe;          /* The database backend */
   int rc;              /* Return code from execution */
   sqlite_callback xCallback;  /* The callback function */
   void *pArg;          /* First argument to the callback function */
@@ -1003,6 +1017,8 @@ int sqliteExprAnalyzeAggregates(Parse*, Expr*);
 Vdbe *sqliteGetVdbe(Parse*);
 int sqliteRandomByte(void);
 int sqliteRandomInteger(void);
+void sqliteRollbackAll(sqlite*);
+void sqliteCodeVerifySchema(Parse*);
 void sqliteBeginTransaction(Parse*, int);
 void sqliteCommitTransaction(Parse*);
 void sqliteRollbackTransaction(Parse*);
index fccd86343d73a1c42c8857f82a90c9841ce822d6..c914e61abbdfc1a89361418f355e41644c4d9f2e 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.53 2003/01/13 23:27:33 drh Exp $
+** $Id: update.c,v 1.54 2003/03/19 03:14:02 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -42,7 +42,6 @@ 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 */
   int chngRecno;         /* True if the record number is being changed */
   Expr *pRecnoExpr;      /* Expression defining the new record number */
   int openAll;           /* True if all indices need to be opened */
@@ -232,7 +231,8 @@ void sqliteUpdate(
     sqliteVdbeAddOp(v, OP_Dup, 0, 0);
 
     sqliteVdbeAddOp(v, OP_Dup, 0, 0);
-    sqliteVdbeAddOp(v, (pTab->isTemp?OP_OpenAux:OP_Open), base, pTab->tnum);
+    sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+    sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
     sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
 
     sqliteVdbeAddOp(v, OP_Integer, 13, 0);
@@ -277,8 +277,8 @@ void sqliteUpdate(
   ** action, then we need to open all indices because we might need
   ** to be deleting some records.
   */
-  openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
-  sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
+  sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+  sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
   if( onError==OE_Replace ){
     openAll = 1;
   }else{
@@ -292,7 +292,8 @@ void sqliteUpdate(
   }
   for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
     if( openAll || aIdxUsed[i] ){
-      sqliteVdbeAddOp(v, openOp, base+i+1, pIdx->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, pIdx->tnum);
       assert( pParse->nTab>base+i+1 );
     }
   }
index e7b8732f940e2b42074105dc1211024a215dbbd4..85baf68903a8877f252efdcffe2c162cfc32dca2 100644 (file)
@@ -36,7 +36,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.207 2003/03/07 19:50:07 drh Exp $
+** $Id: vdbe.c,v 1.208 2003/03/19 03:14:02 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -243,7 +243,6 @@ struct Keylist {
 struct Vdbe {
   sqlite *db;         /* The whole database */
   Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
-  Btree *pBt;         /* Opaque context structure used by DB backend */
   FILE *trace;        /* Write an execution trace here, if not NULL */
   int nOp;            /* Number of instructions in the program */
   int nOpAlloc;       /* Number of slots allocated for aOp[] */
@@ -315,7 +314,6 @@ Vdbe *sqliteVdbeCreate(sqlite *db){
   Vdbe *p;
   p = sqliteMalloc( sizeof(Vdbe) );
   if( p==0 ) return 0;
-  p->pBt = db->pBe;
   p->db = db;
   if( db->pVdbe ){
     db->pVdbe->pPrev = p;
@@ -1212,6 +1210,7 @@ static void Cleanup(Vdbe *p){
 */
 void sqliteVdbeDelete(Vdbe *p){
   int i;
+  sqlite *db = p->db;
   if( p==0 ) return;
   Cleanup(p);
   if( p->pPrev ){
@@ -1233,6 +1232,13 @@ void sqliteVdbeDelete(Vdbe *p){
       sqliteFree(p->aOp[i].p3);
     }
   }
+  for(i=2; i<db->nDb; i++){
+    if( db->aDb[i].pBt && db->aDb[i].zName==0 ){
+      sqliteBtreeClose(db->aDb[i].pBt);
+      db->aDb[i].pBt = 0;
+      db->aDb[i].inTrans = 0;
+    }
+  }
   sqliteFree(p->aOp);
   sqliteFree(p->aLabel);
   sqliteFree(p->aStack);
@@ -1584,7 +1590,6 @@ int sqliteVdbeExec(
   int pc;                    /* The program counter */
   Op *pOp;                   /* Current operation */
   int rc = SQLITE_OK;        /* Value to return */
-  Btree *pBt = p->pBt;       /* The backend driver */
   sqlite *db = p->db;        /* The database */
   char **zStack = p->zStack; /* Text stack */
   Stack *aStack = p->aStack; /* Additional stack information */
@@ -1894,6 +1899,7 @@ case OP_Push: {
 ** to all column names is passed as the 4th parameter to the callback.
 */
 case OP_ColumnName: {
+  assert( pOp->p1>=0 && pOp->p1<p->nOp );
   p->azColName[pOp->p1] = pOp->p3;
   p->nCallback = 0;
   break;
@@ -3154,17 +3160,21 @@ case OP_IncrKey: {
   break;
 }
 
-/* Opcode: Checkpoint * * *
+/* Opcode: Checkpoint P1 * *
 **
 ** Begin a checkpoint.  A checkpoint is the beginning of a operation that
 ** is part of a larger transaction but which might need to be rolled back
 ** itself without effecting the containing transaction.  A checkpoint will
 ** be automatically committed or rollback when the VDBE halts.
+**
+** The checkpoint is begun on the database file with index P1.  The main
+** database file has an index of 0 and the file used for temporary tables
+** has an index of 1.
 */
 case OP_Checkpoint: {
-  rc = sqliteBtreeBeginCkpt(pBt);
-  if( rc==SQLITE_OK && db->pBeTemp ){
-     rc = sqliteBtreeBeginCkpt(db->pBeTemp);
+  int i = pOp->p1;
+  if( i>=0 && i<db->nDb && db->aDb[i].pBt ){
+    rc = sqliteBtreeBeginCkpt(db->aDb[i].pBt);
   }
   break;
 }
@@ -3175,10 +3185,9 @@ case OP_Checkpoint: {
 ** opcode is encountered.  Depending on the ON CONFLICT setting, the
 ** transaction might also be rolled back if an error is encountered.
 **
-** If P1 is true, then the transaction is started on the temporary
-** tables of the database only.  The main database file is not write
-** locked and other processes can continue to read the main database
-** file.
+** P1 is the index of the database file on which the transaction is
+** started.  Index 0 is the main database file and index 1 is the
+** file used for temporary tables.
 **
 ** A write lock is obtained on the database file when a transaction is
 ** started.  No other process can read or write the file while the
@@ -3188,15 +3197,9 @@ case OP_Checkpoint: {
 */
 case OP_Transaction: {
   int busy = 1;
-  if( db->pBeTemp && !p->inTempTrans ){
-    rc = sqliteBtreeBeginTrans(db->pBeTemp);
-    if( rc!=SQLITE_OK ){
-      goto abort_due_to_error;
-    }
-    p->inTempTrans = 1;
-  }
-  while( pOp->p1==0 && busy ){
-    rc = sqliteBtreeBeginTrans(pBt);
+  int i = pOp->p1;
+  while( i>=0 && i<db->nDb && db->aDb[i].pBt!=0 && busy ){
+    rc = sqliteBtreeBeginTrans(db->aDb[i].pBt);
     switch( rc ){
       case SQLITE_BUSY: {
         if( db->xBusyCallback==0 ){
@@ -3224,6 +3227,7 @@ case OP_Transaction: {
       }
     }
   }
+  db->aDb[i].inTrans = 1;
   p->undoTransOnError = 1;
   break;
 }
@@ -3237,53 +3241,48 @@ case OP_Transaction: {
 ** A read lock continues to be held if there are still cursors open.
 */
 case OP_Commit: {
-  if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
-    rc = p->inTempTrans ? SQLITE_OK : sqliteBtreeCommit(pBt);
+  int i;
+  assert( rc==SQLITE_OK );
+  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+    if( db->aDb[i].inTrans ){
+      rc = sqliteBtreeCommit(db->aDb[i].pBt);
+      db->aDb[i].inTrans = 0;
+    }
   }
   if( rc==SQLITE_OK ){
     sqliteCommitInternalChanges(db);
   }else{
-    if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
-    sqliteBtreeRollback(pBt);
-    sqliteRollbackInternalChanges(db);
+    sqliteRollbackAll(db);
   }
-  p->inTempTrans = 0;
   break;
 }
 
-/* Opcode: Rollback * * *
+/* Opcode: Rollback P1 * *
 **
 ** Cause all modifications to the database that have been made since the
 ** last Transaction to be undone. The database is restored to its state
 ** before the Transaction opcode was executed.  No additional modifications
 ** are allowed until another transaction is started.
 **
+** P1 is the index of the database file that is committed.  An index of 0
+** is used for the main database and an index of 1 is used for the file used
+** to hold temporary tables.
+**
 ** This instruction automatically closes all cursors and releases both
-** the read and write locks on the database.
+** the read and write locks on the indicated database.
 */
 case OP_Rollback: {
-  if( db->pBeTemp ){
-    sqliteBtreeRollback(db->pBeTemp);
-  }
-  rc = sqliteBtreeRollback(pBt);
-  sqliteRollbackInternalChanges(db);
+  sqliteRollbackAll(db);
   break;
 }
 
-/* Opcode: ReadCookie * P2 *
-**
-** When P2==0, 
-** read the schema cookie from the database file and push it onto the
-** stack.  The schema cookie is an integer that is used like a version
-** number for the database schema.  Everytime the schema changes, the
-** cookie changes to a new random value.  This opcode is used during
-** initialization to read the initial cookie value so that subsequent
-** database accesses can verify that the cookie has not changed.
+/* Opcode: ReadCookie P1 P2 *
 **
-** If P2>0, then read global database parameter number P2.  There is
-** a small fixed number of global database parameters.  P2==1 is the
-** database version number.  P2==2 is the recommended pager cache size.
-** Other parameters are currently unused.
+** Read cookie number P2 from database P1 and push it onto the stack.
+** P2==0 is the schema version.  P2==1 is the database format.
+** P2==2 is the recommended pager cache size, and so forth.  P1==0 is
+** the main database file and P1==1 is the database file used to store
+** temporary tables.
 **
 ** There must be a read-lock on the database (either a transaction
 ** must be started or there must be an open cursor) before
@@ -3293,36 +3292,35 @@ case OP_ReadCookie: {
   int i = ++p->tos;
   int aMeta[SQLITE_N_BTREE_META];
   assert( pOp->p2<SQLITE_N_BTREE_META );
-  rc = sqliteBtreeGetMeta(pBt, aMeta);
+  assert( pOp->p1>=0 && pOp->p1<db->nDb );
+  assert( db->aDb[pOp->p1].pBt!=0 );
+  rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
   aStack[i].i = aMeta[1+pOp->p2];
   aStack[i].flags = STK_Int;
   break;
 }
 
-/* Opcode: SetCookie * P2 *
+/* Opcode: SetCookie P1 P2 *
 **
-** When P2==0,
-** this operation changes the value of the schema cookie on the database.
-** The new value is top of the stack.
-** When P2>0, the value of global database parameter
-** number P2 is changed.  See ReadCookie for more information about
-** global database parametes.
-**
-** The schema cookie changes its value whenever the database schema changes.
-** That way, other processes can recognize when the schema has changed
-** and reread it.
+** Write the top of the stack into cookie number P2 of database P1.
+** P2==0 is the schema version.  P2==1 is the database format.
+** P2==2 is the recommended pager cache size, and so forth.  P1==0 is
+** the main database file and P1==1 is the database file used to store
+** temporary tables.
 **
 ** A transaction must be started before executing this opcode.
 */
 case OP_SetCookie: {
   int aMeta[SQLITE_N_BTREE_META];
   assert( pOp->p2<SQLITE_N_BTREE_META );
+  assert( pOp->p1>=0 && pOp->p1<db->nDb );
+  assert( db->aDb[pOp->p1].pBt!=0 );
   VERIFY( if( p->tos<0 ) goto not_enough_stack; )
   Integerify(p, p->tos)
-  rc = sqliteBtreeGetMeta(pBt, aMeta);
+  rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
   if( rc==SQLITE_OK ){
     aMeta[1+pOp->p2] = aStack[p->tos].i;
-    rc = sqliteBtreeUpdateMeta(pBt, aMeta);
+    rc = sqliteBtreeUpdateMeta(db->aDb[pOp->p1].pBt, aMeta);
   }
   POPSTACK;
   break;
@@ -3330,10 +3328,11 @@ case OP_SetCookie: {
 
 /* Opcode: VerifyCookie P1 P2 *
 **
-** Check the value of global database parameter number P2 and make
-** sure it is equal to P1.  P2==0 is the schema cookie.  P1==1 is
-** the database version.  If the values do not match, abort with
-** an SQLITE_SCHEMA error.
+** Check the value of global database parameter number 0 (the
+** schema version) and make sure it is equal to P2.  
+** P1 is the database number which is 0 for the main database file
+** and 1 for the file holding temporary tables and some higher number
+** for auxiliary databases.
 **
 ** The cookie changes its value whenever the database schema changes.
 ** This operation is used to detect when that the cookie has changed
@@ -3345,23 +3344,27 @@ case OP_SetCookie: {
 */
 case OP_VerifyCookie: {
   int aMeta[SQLITE_N_BTREE_META];
-  assert( pOp->p2<SQLITE_N_BTREE_META );
-  rc = sqliteBtreeGetMeta(pBt, aMeta);
-  if( rc==SQLITE_OK && aMeta[1+pOp->p2]!=pOp->p1 ){
+  assert( pOp->p1>=0 && pOp->p1<db->nDb );
+  assert( db->aDb[pOp->p1].zName!=0 );
+  rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
+  if( rc==SQLITE_OK && aMeta[1]!=pOp->p2 ){
     sqliteSetString(&p->zErrMsg, "database schema has changed", 0);
     rc = SQLITE_SCHEMA;
   }
   break;
 }
 
-/* Opcode: Open P1 P2 P3
+/* Opcode: OpenRead P1 P2 P3
 **
 ** Open a read-only cursor for the database table whose root page is
-** P2 in the main database file.  Give the new cursor an identifier
-** of P1.  The P1 values need not be contiguous but all P1 values
-** should be small integers.  It is an error for P1 to be negative.
+** P2 in a database file.  The database file is determined by an 
+** integer from the top of the stack.  0 means the main database and
+** 1 means the database used for temporary tables.  Give the new 
+** cursor an identifier of P1.  The P1 values need not be contiguous
+** but all P1 values should be small integers.  It is an error for
+** P1 to be negative.
 **
-** If P2==0 then take the root page number from the top of the stack.
+** If P2==0 then take the root page number from the next of the stack.
 **
 ** There will be a read lock on the database whenever there is an
 ** open cursor.  If the database was unlocked prior to this instruction
@@ -3377,52 +3380,39 @@ case OP_VerifyCookie: {
 ** 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.
+** See also OpenWrite.
 */
 /* Opcode: OpenWrite P1 P2 P3
 **
 ** Open a read/write cursor named P1 on the table or index whose root
 ** page is P2.  If P2==0 then take the root page number from the stack.
 **
-** This instruction works just like Open except that it opens the cursor
+** This instruction works just like OpenRead 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.
+** See also OpenRead.
 */
-/* 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: {
+case OP_OpenRead:
+case OP_OpenWrite: {
   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;
-  }
+  int iDb;
+  
+  VERIFY( if( tos<0 ) goto not_enough_stack; );
+  Integerify(p, tos);
+  iDb = p->aStack[tos].i;
+  tos--;
+  VERIFY( if( iDb<0 || iDb>=db->nDb ) goto bad_instruction; );
+  VERIFY( if( db->aDb[iDb].pBt==0 ) goto bad_instruction; );
+  pX = db->aDb[iDb].pBt;
+  wrFlag = pOp->opcode==OP_OpenWrite;
   if( p2<=0 ){
-    if( tos<0 ) goto not_enough_stack;
+    VERIFY( if( tos<0 ) goto not_enough_stack; );
     Integerify(p, tos);
     p2 = p->aStack[tos].i;
     POPSTACK;
@@ -3464,6 +3454,7 @@ case OP_Open: {
   if( p2<=0 ){
     POPSTACK;
   }
+  POPSTACK;
   break;
 }
 
@@ -4448,7 +4439,7 @@ case OP_IdxGE: {
 ** See also: Clear
 */
 case OP_Destroy: {
-  sqliteBtreeDropTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
+  sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
   break;
 }
 
@@ -4465,7 +4456,7 @@ case OP_Destroy: {
 ** See also: Destroy
 */
 case OP_Clear: {
-  sqliteBtreeClearTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
+  sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
   break;
 }
 
@@ -4499,10 +4490,12 @@ case OP_CreateTable: {
   int i = ++p->tos;
   int pgno;
   assert( pOp->p3!=0 && pOp->p3type==P3_POINTER );
+  assert( pOp->p2>=0 && pOp->p2<db->nDb );
+  assert( db->aDb[pOp->p2].pBt!=0 );
   if( pOp->opcode==OP_CreateTable ){
-    rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
+    rc = sqliteBtreeCreateTable(db->aDb[pOp->p2].pBt, &pgno);
   }else{
-    rc = sqliteBtreeCreateIndex(pOp->p2 ? db->pBeTemp : pBt, &pgno);
+    rc = sqliteBtreeCreateIndex(db->aDb[pOp->p2].pBt, &pgno);
   }
   if( rc==SQLITE_OK ){
     aStack[i].i = pgno;
@@ -4546,7 +4539,7 @@ case OP_IntegrityCk: {
     toInt((char*)sqliteHashKey(i), &aRoot[j]);
   }
   aRoot[j] = 0;
-  z = sqliteBtreeIntegrityCheck(pOp->p2 ? db->pBeTemp : pBt, aRoot, nRoot);
+  z = sqliteBtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
   if( z==0 || z[0]==0 ){
     if( z ) sqliteFree(z);
     zStack[tos] = "ok";
@@ -5671,8 +5664,7 @@ bad_instruction:
 */
 int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
   sqlite *db = p->db;
-  Btree *pBt = p->pBt;
-  int rc;
+  int i, rc;
 
   if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
     sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0);
@@ -5691,23 +5683,24 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
     switch( p->errorAction ){
       case OE_Abort: {
         if( !p->undoTransOnError ){
-          sqliteBtreeRollbackCkpt(pBt);
-          if( db->pBeTemp ) sqliteBtreeRollbackCkpt(db->pBeTemp);
+          for(i=0; i<db->nDb; i++){
+            if( db->aDb[i].pBt ){
+              sqliteBtreeRollbackCkpt(db->aDb[i].pBt);
+            }
+          }
           break;
         }
         /* Fall through to ROLLBACK */
       }
       case OE_Rollback: {
-        sqliteBtreeRollback(pBt);
-        if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
+        sqliteRollbackAll(db);
         db->flags &= ~SQLITE_InTrans;
         db->onError = OE_Default;
         break;
       }
       default: {
         if( p->undoTransOnError ){
-          sqliteBtreeCommit(pBt);
-          if( db->pBeTemp ) sqliteBtreeCommit(db->pBeTemp);
+          sqliteRollbackAll(db);
           db->flags &= ~SQLITE_InTrans;
           db->onError = OE_Default;
         }
@@ -5716,8 +5709,11 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
     }
     sqliteRollbackInternalChanges(db);
   }
-  sqliteBtreeCommitCkpt(pBt);
-  if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
+  for(i=0; i<db->nDb; i++){
+    if( db->aDb[i].pBt ){
+      sqliteBtreeCommitCkpt(db->aDb[i].pBt);
+    }
+  }
   assert( p->tos<p->pc || sqlite_malloc_failed==1 );
 #ifdef VDBE_PROFILE
   {
index 7fa6f4171628ab70a4560af34e599477ade022ae..3f7f306a06dcfad7fa4152d59528689d790e1a50 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.72 2003/01/31 17:21:50 drh Exp $
+** $Id: where.c,v 1.73 2003/03/19 03:14:03 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -636,21 +636,21 @@ WhereInfo *sqliteWhereBegin(
   /* Open all tables in the pTabList and all indices used by those tables.
   */
   for(i=0; i<pTabList->nSrc; i++){
-    int openOp;
     Table *pTab;
 
     pTab = pTabList->a[i].pTab;
     if( pTab->isTransient || pTab->pSelect ) continue;
-    openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
-    sqliteVdbeAddOp(v, openOp, base+i, pTab->tnum);
+    sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+    sqliteVdbeAddOp(v, OP_OpenRead, base+i, pTab->tnum);
     sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
     if( i==0 && !pParse->schemaVerified &&
           (pParse->db->flags & SQLITE_InTrans)==0 ){
-      sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
-      pParse->schemaVerified = 1;
+      sqliteCodeVerifySchema(pParse);
     }
     if( pWInfo->a[i].pIdx!=0 ){
-      sqliteVdbeAddOp(v, openOp, pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
+      sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
+      sqliteVdbeAddOp(v, OP_OpenRead,
+                      pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
       sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC);
     }
   }
index 1823f65f78cfeca4fd133e38ad15a63c41a3130b..628512e9fcef897bff305277af90ef8937348167 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this Tcl script to generate the sqlite.html file.
 #
-set rcsid {$Id: arch.tcl,v 1.8 2002/08/06 12:05:00 drh Exp $}
+set rcsid {$Id: arch.tcl,v 1.9 2003/03/19 03:14:03 drh Exp $}
 
 puts {<html>
 <head>
@@ -69,7 +69,7 @@ the tokenizer to call the parser.  YACC has it backwards.</p>
 <p>The parser is the piece that assigns meaning to tokens based on
 their context.  The parser for SQLite is generated using the
 <a href="http://www.hwaci.com/sw/lemon/">Lemon</a> LALR(1) parser
-generator.  Lemon does the same job as YACC/BISON, but is uses
+generator.  Lemon does the same job as YACC/BISON, but it uses
 a different input syntax which is less error-prone.
 Lemon also generates a parser which is reentrant and thread-safe.
 And lemon defines the concept of a non-terminal destructor so