-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
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
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
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
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
-2aba40bea5fc1c4aef8cfd4c790d40808821ca14
\ No newline at end of file
+875da9eed981bfa27b98e95025f9fdbed74b4098
\ No newline at end of file
** 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
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.
*/
** 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_
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);
** 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>
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);
}
** 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;
}
** 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);
}
/*
/* 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);
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);
** 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);
}
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);
}
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 ){
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);
}
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 ){
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 ){
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 ){
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 ){
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.
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);
}
}
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
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
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
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
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);
** 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"
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;
** 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);
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);
** 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
** 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"
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 */
** 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 ){
/* 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;
/* 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;
** 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"
/* 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);
/* 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.
*/
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
- sParse.pBe = db->pBe;
sParse.xCallback = sqliteInitCallback;
sParse.pArg = (void*)&initData;
sParse.initFlag = 1;
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 ){
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: {
sqliteStrRealloc(pzErrMsg);
return 0;
}
+ db->aDb[0].zName = "main";
/* Attempt to read the schema */
sqliteRegisterBuiltinFunctions(db);
&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 ){
*/
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){
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()
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;
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 ){
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,
}
+/*
+** 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,
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*);
** 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"
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
** 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 $
*/
/*
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*);
char *sqliteMPrintf(const char *zFormat, ...){
va_list ap;
struct sgMprintf sMprintf;
- char *zNew;
char zBuf[200];
sMprintf.nChar = 0;
** 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"
Index *pIdx;
int base;
Vdbe *v;
- int openOp;
int seekOp;
int cont;
ExprList eList;
** 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);
*************************************************************************
** 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"
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.
** 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 */
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 */
*/
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 */
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*);
** 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"
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 */
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);
** 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{
}
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 );
}
}
** 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>
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[] */
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;
*/
void sqliteVdbeDelete(Vdbe *p){
int i;
+ sqlite *db = p->db;
if( p==0 ) return;
Cleanup(p);
if( p->pPrev ){
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);
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 */
** 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;
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;
}
** 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
*/
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 ){
}
}
}
+ db->aDb[i].inTrans = 1;
p->undoTransOnError = 1;
break;
}
** 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
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;
/* 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
*/
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
** 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;
if( p2<=0 ){
POPSTACK;
}
+ POPSTACK;
break;
}
** See also: Clear
*/
case OP_Destroy: {
- sqliteBtreeDropTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
+ sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
** See also: Destroy
*/
case OP_Clear: {
- sqliteBtreeClearTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
+ sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
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;
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";
*/
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);
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;
}
}
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
{
** 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"
/* 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);
}
}
#
# 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>
<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