From 001bbcbb8fa5a55e9950445c6287a1fc0496e83e Mon Sep 17 00:00:00 2001
From: drh
Date: Wed, 19 Mar 2003 03:14:00 +0000
Subject: [PATCH] Modifications to the VDBE to support more than one database
file. (CVS 878)
FossilOrigin-Name: 875da9eed981bfa27b98e95025f9fdbed74b4098
---
manifest | 44 ++++-----
manifest.uuid | 2 +-
src/btree.c | 101 ++++++++++++++++++++-
src/btree.h | 3 +-
src/build.c | 109 ++++++++++++-----------
src/delete.c | 19 ++--
src/insert.c | 19 ++--
src/main.c | 66 +++++++++-----
src/os.c | 24 +++++
src/os.h | 1 +
src/pager.c | 21 ++++-
src/pager.h | 3 +-
src/printf.c | 1 -
src/select.c | 13 ++-
src/sqliteInt.h | 30 +++++--
src/update.c | 13 +--
src/vdbe.c | 230 ++++++++++++++++++++++++------------------------
src/where.c | 14 +--
www/arch.tcl | 4 +-
19 files changed, 451 insertions(+), 266 deletions(-)
diff --git a/manifest b/manifest
index 6516711419..d9eb81fc87 100644
--- 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
diff --git a/manifest.uuid b/manifest.uuid
index 5431fa5643..35b85046ec 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-2aba40bea5fc1c4aef8cfd4c790d40808821ca14
\ No newline at end of file
+875da9eed981bfa27b98e95025f9fdbed74b4098
\ No newline at end of file
diff --git a/src/btree.c b/src/btree.c
index 9745f6d908..a8fd80e4d0 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -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.
*/
diff --git a/src/btree.h b/src/btree.h
index b92dce6e28..ef6f781277 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -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);
diff --git a/src/build.c b/src/build.c
index 45b82b0b5e..0c763d07a7 100644
--- a/src/build.c
+++ b/src/build.c
@@ -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
@@ -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; inDb; 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);
diff --git a/src/delete.c b/src/delete.c
index 65e5075b49..62bcf9ca1e 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
-** $Id: delete.c,v 1.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
diff --git a/src/insert.c b/src/insert.c
index f90e2ab0d1..5b96f48a1b 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
-** $Id: insert.c,v 1.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;
diff --git a/src/main.c b/src/main.c
index 8fa81d83c1..cf1481418d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.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; jnDb; 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; inDb; 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,
diff --git a/src/os.c b/src/os.c
index d0b50dc4f1..77bdf3ae00 100644
--- 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,
diff --git a/src/os.h b/src/os.h
index 8491d90dfe..f9784ef525 100644
--- a/src/os.h
+++ b/src/os.h
@@ -147,6 +147,7 @@
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*);
diff --git a/src/pager.c b/src/pager.c
index bd191d6e1d..58eb8cee41 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.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
diff --git a/src/pager.h b/src/pager.h
index 4735b82d6b..bba8220ace 100644
--- a/src/pager.h
+++ b/src/pager.h
@@ -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*);
diff --git a/src/printf.c b/src/printf.c
index 387ea1c2da..8587f80d28 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -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;
diff --git a/src/select.c b/src/select.c
index 4b462486d4..eb2892f243 100644
--- a/src/select.c
+++ b/src/select.c
@@ -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);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index e8f1682046..63610ae8ea 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -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*);
diff --git a/src/update.c b/src/update.c
index fccd86343d..c914e61abb 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.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 );
}
}
diff --git a/src/vdbe.c b/src/vdbe.c
index e7b8732f94..85baf68903 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -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
@@ -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; inDb; 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->p1nOp );
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 && inDb && 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 && inDb && 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 && inDb; 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 *
+/* Opcode: ReadCookie P1 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.
-**
-** 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->p2p1>=0 && pOp->p1nDb );
+ 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->p2p1>=0 && pOp->p1nDb );
+ 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->p2p2]!=pOp->p1 ){
+ assert( pOp->p1>=0 && pOp->p1nDb );
+ 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->p2nDb );
+ 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; inDb; 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; inDb; i++){
+ if( db->aDb[i].pBt ){
+ sqliteBtreeCommitCkpt(db->aDb[i].pBt);
+ }
+ }
assert( p->tospc || sqlite_malloc_failed==1 );
#ifdef VDBE_PROFILE
{
diff --git a/src/where.c b/src/where.c
index 7fa6f41716..3f7f306a06 100644
--- a/src/where.c
+++ b/src/where.c
@@ -13,7 +13,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
-** $Id: where.c,v 1.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; inSrc; 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);
}
}
diff --git a/www/arch.tcl b/www/arch.tcl
index 1823f65f78..628512e9fc 100644
--- a/www/arch.tcl
+++ b/www/arch.tcl
@@ -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 {
@@ -69,7 +69,7 @@ the tokenizer to call the parser. YACC has it backwards.
The parser is the piece that assigns meaning to tokens based on
their context. The parser for SQLite is generated using the
Lemon 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