The code is in place to replace GDBM with BTree. But I have not yet

attempted to compile it.  I am sure the code contains bugs. (CVS 238)

FossilOrigin-Name: 6ecc8b20d4f402f45f03d46d8d4fa40dea666e97
This commit is contained in:
drh 2001-09-13 13:46:56 +00:00
parent 5c4d9703d9
commit 5e00f6c7d5
20 changed files with 3910 additions and 2679 deletions

View File

@ -1,5 +1,5 @@
C Restore\sbtree\sto\sthe\smain\sline.\s(CVS\s237)
D 2001-08-20T00:33:58
C The\scode\sis\sin\splace\sto\sreplace\sGDBM\swith\sBTree.\s\sBut\sI\shave\snot\syet\nattempted\sto\scompile\sit.\s\sI\sam\ssure\sthe\scode\scontains\sbugs.\s(CVS\s238)
D 2001-09-13T13:46:56
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 9eea999e1d95531de4dd0a96a6ecf6ba0027b05b
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@ -13,14 +13,15 @@ F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e
F notes/notes2b.txt 1c17a5b7f6b44a75cd3eb98ed2c24db1eefb06c3
F notes/notes3.txt 71e47be517e3d2578b3b9343a45b772d43b7ba16
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
F src/btree.c 049c6a8d6c308b1945bd2f32746f3df187c7f18b
F src/btree.h 6617284287be90afe41bcd5047e44f109ecd1b48
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
F src/btree.c af587cc36f36ea9e7544accfcedf4ea55460f61a
F src/btree.h 1fe9710a1d2ed79bda8efbbb324cfb80ce6f53e7
F src/build.c 5a990a295413887bd873258f1ca7b78cb086d04d
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
F src/dbbe.h bbb53eafcd1e3186597f6ee4a17ef2501f1b0628
F src/dbbebtree.c 7a0292e1f1578973646f4f51cd9066ed5b4ee282
F src/dbbegdbm.c cbb6ebc79a7100324f07b67d4e867faca9f9efa9
F src/dbbemem.c 910ad3bb82fc065a95a762b34593b3386b4833d5
F src/delete.c 40ddb169ee98013d976b2dadd140d98f7876f54f
F src/delete.c bee9e20720436b74d7116735389ac81f7aa1d684
F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a
F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7
F src/ex/db.h 3f2933ee20c147fe494835786e4c6f3a562def4e
@ -30,30 +31,30 @@ F src/ex/pg.c 2bbf6a94f37226d06337868b6bf4d7affc60197f
F src/ex/pg.h 23a4ac807b0546ec2bb6239ec8bd3e06926572cd
F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
F src/expr.c f64760004afc10c1c1232ae7ece2947452aa70dd
F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
F src/main.c 0a13c7a2beb8ce36aee43daf8c95989b200727a7
F src/insert.c 51d21e65eba5b4bef017fec6af79266bc0065824
F src/main.c afdb7ecb5de4e0eb0d69d1e0d5db7ad070c8e0d6
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/pager.c fbb1f1d8d2fd71333dfb9014852fd60194320732
F src/pager.h ee84c00ca56ff6f0c53bbf216ede342cc99c701a
F src/pager.c 1928e68b5c00c24749b71f41eeabacd7217337a5
F src/pager.h 238aa88bafe33911bf9b0b365f35afd0a261cd46
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a
F src/select.c 52bb7d081ac00dfad3687d52c917d2d90165331d
F src/shell.c d9c64418765d90909e9e200b207ff9e355afb5c4
F src/select.c e5977916f59a79d67c40fae11e2c5736cddd1fa8
F src/shell.c 1fcdf8c4180098bcfdee12501e01b4c8eb21d726
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 3e5906f72608f0fd4394dfbb1d7e8d35b8353677
F src/sqliteInt.h 47845c60e2e196b5409d774936a56700b1611f00
F src/sqlite.h.in 8faa2fed0513d188ced16e5f9094e57694594e70
F src/sqliteInt.h 1a3a7ac6db97c15ec6e80ee8df8a8f8eadf70316
F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6
F src/tclsqlite.c d328970848c028e13e61e173bef79adcc379568a
F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4
F src/test2.c b3177e061fabd20d48e4b1b4bca610a0d2b28670
F src/test3.c 147b42ec368a10e9f267e7466d30c46e76d7f278
F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf
F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6
F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc
F src/vdbe.c b019394ebe0de12917a93ec06d787d8d909726cc
F src/vdbe.h 5331b9a3963d13af01a9cf749f57ac46727bdbe6
F src/where.c a49083e59358bac83c80cf0d19626d09bab629bd
F src/update.c ea8f2c0712cd4cd19314a26ef4766866013facda
F src/util.c c77668fef860cfd2e4e682ef4f3ed8f9e68c551b
F src/vdbe.c 16dce6e16b63840d8e74d7ffed0fb7bf9e43b999
F src/vdbe.h 533068ed67e3d8519be49b6ed50f6229c73b6b36
F src/where.c ddf119d879fbfa2abb0b0f5963be0560dfa30247
F test/all.test 21d55a97e39e7ec5776751dc9dd8b1b51ef4a048
F test/btree.test 5e1eeb03cda22161eec827dc5224ce6c500eaaf9
F test/btree2.test a66add2093843d0e5617fed6924002667832f279
@ -112,7 +113,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
P c15f6ffc4d41f30a06d750c8015226713ae0126b
R 7b718c617d1cbd654e712509bb5deb19
P 2e6aff980287825b59d2ebb7005bb08dd601ff1c
R 2654e388e3b472efb037b78486fd2a60
U drh
Z a087795b1966c95abd2653a136093358
Z bd85e26e61c9c38cc5377a9e930cda9b

View File

@ -1 +1 @@
2e6aff980287825b59d2ebb7005bb08dd601ff1c
6ecc8b20d4f402f45f03d46d8d4fa40dea666e97

View File

@ -21,7 +21,7 @@
** http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: btree.c,v 1.21 2001/08/20 00:33:58 drh Exp $
** $Id: btree.c,v 1.22 2001/09/13 13:46:56 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@ -43,8 +43,8 @@
** on Ptr(N+1) and its subpages have values greater than Key(N). And
** so forth.
**
** Finding a particular key requires reading O(log(M)) pages from the file
** where M is the number of entries in the tree.
** Finding a particular key requires reading O(log(M)) pages from the
** disk where M is the number of entries in the tree.
**
** In this implementation, a single file can hold one or more separate
** BTrees. Each BTree is identified by the index of its root page. The
@ -112,7 +112,7 @@ static const char zMagicHeader[] =
#define MAGIC_SIZE (sizeof(zMagicHeader))
/*
** This is a magic integer also used to the integrety of the database
** This is a magic integer also used to test the integrity of the database
** file. This integer is used in addition to the string above so that
** if the file is written on a little-endian architecture and read
** on a big-endian architectures (or vice versa) we can detect the
@ -726,20 +726,28 @@ int sqliteBtreeBeginTrans(Btree *pBt){
return rc;
}
}
rc = sqlitepager_write(pBt->page1);
if( rc!=SQLITE_OK ){
return rc;
if( !sqlitepager_isreadonly(pBt) ){
rc = sqlitepager_write(pBt->page1);
if( rc!=SQLITE_OK ){
return rc;
}
rc = newDatabase(pBt);
}
pBt->inTrans = 1;
rc = newDatabase(pBt);
return rc;
}
/*
** Remove the last reference to the database file. This will
** remove the read lock.
** If there are no outstanding cursors and we are not in the middle
** of a transaction but there is a read lock on the database, then
** this routine unrefs the first page of the database file which
** has the effect of releasing the read lock.
**
** If there are any outstanding cursors, this routine is a no-op.
**
** If there is a transaction in progress, this routine is a no-op.
*/
static void unlockBtree(Btree *pBt){
static void unlockBtreeIfUnused(Btree *pBt){
if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){
sqlitepager_unref(pBt->page1);
pBt->page1 = 0;
@ -749,19 +757,25 @@ static void unlockBtree(Btree *pBt){
/*
** Commit the transaction currently in progress.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
int sqliteBtreeCommit(Btree *pBt){
int rc;
if( pBt->inTrans==0 ) return SQLITE_ERROR;
rc = sqlitepager_commit(pBt->pPager);
pBt->inTrans = 0;
unlockBtree(pBt);
unlockBtreeIfUnused(pBt);
return rc;
}
/*
** Rollback the transaction in progress. All cursors must be
** closed before this routine is called.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
int sqliteBtreeRollback(Btree *pBt){
int rc;
@ -769,7 +783,7 @@ int sqliteBtreeRollback(Btree *pBt){
if( pBt->inTrans==0 ) return SQLITE_OK;
pBt->inTrans = 0;
rc = sqlitepager_rollback(pBt->pPager);
unlockBtree(pBt);
unlockBtreeIfUnused(pBt);
return rc;
}
@ -819,12 +833,12 @@ create_cursor_exception:
if( pCur->pPage ) sqlitepager_unref(pCur->pPage);
sqliteFree(pCur);
}
unlockBtree(pBt);
unlockBtreeIfUnused(pBt);
return rc;
}
/*
** Close a cursor. The lock on the database file is released
** Close a cursor. The read lock on the database file is released
** when the last cursor is closed.
*/
int sqliteBtreeCloseCursor(BtCursor *pCur){
@ -838,7 +852,7 @@ int sqliteBtreeCloseCursor(BtCursor *pCur){
pCur->pNext->pPrev = pCur->pPrev;
}
sqlitepager_unref(pCur->pPage);
unlockBtree(pBt);
unlockBtreeIfUnused(pBt);
sqliteFree(pCur);
return SQLITE_OK;
}
@ -942,29 +956,34 @@ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){
}
/*
** Read part of the key associated with cursor pCur. A total
** Read part of the key associated with cursor pCur. A maximum
** of "amt" bytes will be transfered into zBuf[]. The transfer
** begins at "offset". If the key does not contain enough data
** to satisfy the request, no data is fetched and this routine
** returns SQLITE_ERROR.
** begins at "offset". The number of bytes actually read is
** returned. The amount returned will be smaller than the
** amount requested if there are not enough bytes in the key
** to satisfy the request.
*/
int sqliteBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){
Cell *pCell;
MemPage *pPage;
if( amt<0 ) return SQLITE_ERROR;
if( offset<0 ) return SQLITE_ERROR;
if( amt==0 ) return SQLITE_OK;
if( amt<0 ) return 0;
if( offset<0 ) return 0;
if( amt==0 ) return 0;
pPage = pCur->pPage;
assert( pPage!=0 );
if( pCur->idx >= pPage->nCell ){
return SQLITE_ERROR;
return 0;
}
pCell = pPage->apCell[pCur->idx];
if( amt+offset > pCell->h.nKey ){
return SQLITE_ERROR;
amt = pCell->h.nKey - offset;
if( amt<=0 ){
return 0;
}
}
return getPayload(pCur, offset, amt, zBuf);
getPayload(pCur, offset, amt, zBuf);
return amt;
}
/*
@ -990,29 +1009,34 @@ int sqliteBtreeDataSize(BtCursor *pCur, int *pSize){
}
/*
** Read part of the data associated with cursor pCur. A total
** Read part of the data associated with cursor pCur. A maximum
** of "amt" bytes will be transfered into zBuf[]. The transfer
** begins at "offset". If the size of the data in the record
** is insufficent to satisfy this request then no data is read
** and this routine returns SQLITE_ERROR.
** begins at "offset". The number of bytes actually read is
** returned. The amount returned will be smaller than the
** amount requested if there are not enough bytes in the data
** to satisfy the request.
*/
int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){
Cell *pCell;
MemPage *pPage;
if( amt<0 ) return SQLITE_ERROR;
if( offset<0 ) return SQLITE_ERROR;
if( amt==0 ) return SQLITE_OK;
if( amt<0 ) return 0;
if( offset<0 ) return 0;
if( amt==0 ) return 0;
pPage = pCur->pPage;
assert( pPage!=0 );
if( pCur->idx >= pPage->nCell ){
return SQLITE_ERROR;
return 0;
}
pCell = pPage->apCell[pCur->idx];
if( amt+offset > pCell->h.nData ){
return SQLITE_ERROR;
amt = pCell->h.nData - offset;
if( amt<=0 ){
return 0;
}
}
return getPayload(pCur, offset + pCell->h.nKey, amt, zBuf);
getPayload(pCur, offset + pCell->h.nKey, amt, zBuf);
return amt;
}
/*
@ -1160,6 +1184,22 @@ static int moveToLeftmost(BtCursor *pCur){
return SQLITE_OK;
}
/* Move the cursor to the first entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty and there is no first element.
*/
int sqliteBtreeFirst(BtCursor *pCur, int *pRes){
int rc;
rc = moveToRoot(pCur);
if( rc ) return rc;
if( pCur->pPage->nCell==0 ){
*pRes = 1;
return SQLITE_OK;
}
*pRes = 0;
rc = moveToLeftmost(pCur);
return rc;
}
/* Move the cursor so that it points to an entry near pKey.
** Return a success code.
@ -1471,7 +1511,7 @@ static void reparentPage(Pager *pPager, Pgno pgno, MemPage *pNewParent){
/*
** Reparent all children of the given page to be the given page.
** In other words, for every child of pPage, invoke reparentPage()
** to make sure that child knows that pPage is its parent.
** to make sure that each child knows that pPage is its parent.
**
** This routine gets called after you memcpy() one page into
** another.
@ -1563,7 +1603,7 @@ static void relinkCellList(MemPage *pPage){
/*
** Make a copy of the contents of pFrom into pTo. The pFrom->apCell[]
** pointers that point intto pFrom->u.aDisk[] must be adjusted to point
** pointers that point into pFrom->u.aDisk[] must be adjusted to point
** into pTo->u.aDisk[] instead. But some pFrom->apCell[] entries might
** not point to pFrom->u.aDisk[]. Those are unchanged.
*/
@ -1624,8 +1664,9 @@ static void copyPage(MemPage *pTo, MemPage *pFrom){
** might become overfull or underfull. If that happens, then this routine
** is called recursively on the parent.
**
** If this routine fails for any reason, it means the database may have
** been left in a corrupted state and should be rolled back.
** If this routine fails for any reason, it might leave the database
** in a corrupted state. So if this routine fails, the database should
** be rolled back.
*/
static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
MemPage *pParent; /* The parent of pPage */
@ -2037,7 +2078,7 @@ int sqliteBtreeDelete(BtCursor *pCur){
clearCell(pCur->pBt, pCell);
if( pgnoChild ){
/*
** If the entry we are about to delete is not a leaf so if we do not
** The entry we are about to delete is not a leaf so if we do not
** do something we will leave a hole on an internal page.
** We have to fill the hole by moving in a cell from a leaf. The
** next Cell after the one to be deleted is guaranteed to exist and
@ -2603,7 +2644,7 @@ char *sqliteBtreeSanityCheck(Btree *pBt, int *aRoot, int nRoot){
/* Make sure this analysis did not leave any unref() pages
*/
unlockBtree(pBt);
unlockBtreeIfUnused(pBt);
if( nRef != *sqlitepager_stats(pBt->pPager) ){
char zBuf[100];
sprintf(zBuf,

View File

@ -24,7 +24,7 @@
** This header file defines the interface that the sqlite B-Tree file
** subsystem.
**
** @(#) $Id: btree.h,v 1.10 2001/08/20 00:33:58 drh Exp $
** @(#) $Id: btree.h,v 1.11 2001/09/13 13:46:56 drh Exp $
*/
typedef struct Btree Btree;
@ -46,6 +46,7 @@ int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes);
int sqliteBtreeDelete(BtCursor*);
int sqliteBtreeInsert(BtCursor*, const void *pKey, int nKey,
const void *pData, int nData);
int sqliteBtreeFirst(BtCursor*, int *pRes);
int sqliteBtreeNext(BtCursor*, int *pRes);
int sqliteBtreeKeySize(BtCursor*, int *pSize);
int sqliteBtreeKey(BtCursor*, int offset, int amt, char *zBuf);

View File

@ -33,7 +33,7 @@
** COPY
** VACUUM
**
** $Id: build.c,v 1.28 2001/04/15 00:37:09 drh Exp $
** $Id: build.c,v 1.29 2001/09/13 13:46:56 drh Exp $
*/
#include "sqliteInt.h"
@ -191,6 +191,24 @@ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
sqliteFree(pIndex);
}
/*
** Unlink the given index from its table, then remove
** the index from the index hash table, and free its memory
** structures.
*/
static void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){
if( pIndex->pTable->pIndex==pIndex ){
pIndex->pTable->pIndex = pIndex->pNext;
}else{
Index *p;
for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
if( p && p->pNext==pIndex ){
p->pNext = pIndex->pNext;
}
}
sqliteDeleteIndex(db, pIndex);
}
/*
** Remove the memory data structures associated with the given
** Table. No changes are made to disk by this routine.
@ -221,6 +239,84 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
sqliteFree(pTable);
}
/*
** Check all Tables and Indexes in the internal hash table and commit
** any additions or deletions to those hash tables.
**
** When executing CREATE TABLE and CREATE INDEX statements, the Table
** and Index structures are created and added to the hash tables, but
** the "isCommit" field is not set. This routine sets those fields.
** When executing DROP TABLE and DROP INDEX, the "isDelete" fields of
** Table and Index structures is set but the structures are not unlinked
** from the hash tables nor deallocated. This routine handles that
** deallocation.
**
** See also: sqliteRollbackInternalChanges()
*/
void sqliteCommitInternalChanges(sqlite *db){
int i;
if( (db->flags & SQLITE_InternChanges)==0 ) return;
for(i=0; i<N_HASH; i++){
Table *pTable, *pNext;
for(pTable = apTblHash[i]; pTable; pTable=pNext){
pNext = pTable->pHash;
if( pTable->isDelete ){
sqliteDeleteTable(db, pTable);
}else if( pTable->isCommit==0 ){
pTable->isCommit = 1;
}
}
}
for(i=0; i<N_HASH; i++){
Index *pIndex, *pNext;
for(pIndex = apIdxHash[i]; pIndex; pIndex=pNext){
pNext = pIndex->pHash;
if( pIndex->isDelete ){
sqliteUnlinkAndDeleteIndex(db, pIndex);
}else if( pIndex->isCommit==0 ){
pIndex->isCommit = 1;
}
}
}
db->flags &= ~SQLITE_InternChanges;
}
/*
** This routine runs when one or more CREATE TABLE, CREATE INDEX,
** DROP TABLE, or DROP INDEX statements get rolled back. The
** additions or deletions of Table and Index structures in the
** internal hash tables are undone.
**
** See also: sqliteCommitInternalChanges()
*/
void sqliteRollbackInternalChanges(sqlite *db){
int i;
if( (db->flags & SQLITE_InternChanges)==0 ) return;
for(i=0; i<N_HASH; i++){
Table *pTable, *pNext;
for(pTable = apTblHash[i]; pTable; pTable=pNext){
pNext = pTable->pHash;
if( !pTable->isCommit ){
sqliteDeleteTable(db, pTable);
}else if( pTable->isDelete ){
pTable->isDelete = 0;
}
}
}
for(i=0; i<N_HASH; i++){
Index *pIndex, *pNext;
for(pIndex = apIdxHash[i]; pIndex; pIndex=pNext){
pNext = pIndex->pHash;
if( !pIndex->isCommit ){
sqliteUnlinkAndDeleteIndex(db, pIndex);
}else if( pIndex->isDelete ){
pIndex->isDelete = 0;
}
}
}
db->flags &= ~SQLITE_InternChanges;
}
/*
** Construct the name of a user table or index from a token.
**
@ -275,6 +371,12 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
pTable->pIndex = 0;
if( pParse->pNewTable ) sqliteDeleteTable(pParse->db, pParse->pNewTable);
pParse->pNewTable = pTable;
if( !pParse->initFlag && (pParse->db->flags & SQLITE_InTrans)==0 ){
Vdbe *v = sqliteGetVdbe(pParse);
if( v ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
}
}
/*
@ -340,12 +442,10 @@ void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
void sqliteEndTable(Parse *pParse, Token *pEnd){
Table *p;
int h;
int addMeta; /* True to insert a meta records into the file */
if( pEnd==0 || pParse->nErr || sqlite_malloc_failed ) return;
p = pParse->pNewTable;
if( p==0 ) return;
addMeta = pParse->db->nTable==1;
/* Add the table to the in-memory representation of the database
*/
@ -355,27 +455,20 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
pParse->db->apTblHash[h] = p;
pParse->pNewTable = 0;
pParse->db->nTable++;
db->flags |= SQLITE_InternChanges;
}
/* If not initializing, then create the table on disk.
*/
if( !pParse->initFlag ){
static VdbeOp addTable[] = {
{ OP_OpenTbl, 0, 1, MASTER_NAME },
{ OP_New, 0, 0, 0},
{ OP_Open, 0, 2, 0},
{ OP_NewRecno, 0, 0, 0},
{ OP_String, 0, 0, "table" },
{ OP_String, 0, 0, 0}, /* 3 */
{ OP_String, 0, 0, 0}, /* 4 */
{ OP_CreateTable, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 5 */
{ OP_MakeRecord, 4, 0, 0},
{ OP_Put, 0, 0, 0},
};
static VdbeOp addVersion[] = {
{ OP_New, 0, 0, 0},
{ OP_String, 0, 0, "meta" },
{ OP_String, 0, 0, "" },
{ OP_String, 0, 0, "" },
{ OP_String, 0, 0, "file format 2" },
{ OP_String, 0, 0, 0}, /* 6 */
{ OP_MakeRecord, 4, 0, 0},
{ OP_Put, 0, 0, 0},
};
@ -387,12 +480,13 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
sqliteVdbeChangeP3(v, base+3, p->zName, 0);
sqliteVdbeChangeP3(v, base+4, p->zName, 0);
sqliteVdbeChangeP3(v, base+5, pParse->sFirstToken.z, n);
if( addMeta ){
sqliteVdbeAddOpList(v, ArraySize(addVersion), addVersion);
}
sqliteVdbeTableRootAddr(v, &p->tnum);
sqliteVdbeChangeP3(v, base+5, p->zName, 0);
sqliteVdbeChangeP3(v, base+6, pParse->sFirstToken.z, n);
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
}
}
@ -441,50 +535,41 @@ void sqliteDropTable(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse);
if( v ){
static VdbeOp dropTable[] = {
{ OP_OpenTbl, 0, 1, MASTER_NAME },
{ OP_ListOpen, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_Next, 0, ADDR(10), 0}, /* 3 */
{ OP_Open, 0, 2, 0},
{ OP_String, 0, 0, 0}, /* 1 */
{ OP_Next, 0, ADDR(9), 0}, /* 2 */
{ OP_Dup, 0, 0, 0},
{ OP_Field, 0, 2, 0},
{ OP_Ne, 0, ADDR(3), 0},
{ OP_Key, 0, 0, 0},
{ OP_ListWrite, 0, 0, 0},
{ OP_Goto, 0, ADDR(3), 0},
{ OP_ListRewind, 0, 0, 0}, /* 10 */
{ OP_ListRead, 0, ADDR(14), 0}, /* 11 */
{ OP_Column, 0, 3, 0},
{ OP_Ne, 0, ADDR(2), 0},
{ OP_Recno, 0, 0, 0},
{ OP_Delete, 0, 0, 0},
{ OP_Goto, 0, ADDR(11), 0},
{ OP_Destroy, 0, 0, 0}, /* 14 */
{ OP_Goto, 0, ADDR(2), 0},
{ OP_Destroy, 0, 0, 0}, /* 9 */
{ OP_Close, 0, 0, 0},
};
Index *pIdx;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
sqliteVdbeChangeP3(v, base+14, pTable->zName, 0);
sqliteVdbeChangeP1(v, base+9, pTable->tnum);
for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pIdx->zName, 0);
sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0);
}
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
}
/* Remove the in-memory table structure and free its memory.
/* Mark the in-memory Table structure as being deleted. The actually
** deletion occurs inside of sqliteCommitInternalChanges().
**
** Exception: if the SQL statement began with the EXPLAIN keyword,
** then no changes are made.
** then no changes should be made.
*/
if( !pParse->explain ){
h = sqliteHashNoCase(pTable->zName, 0) % N_HASH;
if( pParse->db->apTblHash[h]==pTable ){
pParse->db->apTblHash[h] = pTable->pHash;
}else{
Table *p;
for(p=pParse->db->apTblHash[h]; p && p->pHash!=pTable; p=p->pHash){}
if( p && p->pHash==pTable ){
p->pHash = pTable->pHash;
}
}
pParse->db->nTable--;
sqliteDeleteTable(pParse->db, pTable);
pTable->isDelete = 1;
db->flags |= SQLITE_InternChanges;
}
}
@ -603,6 +688,7 @@ void sqliteCreateIndex(
pParse->db->apIdxHash[h] = pIndex;
pIndex->pNext = pTab->pIndex;
pTab->pIndex = pIndex;
db->flags |= SQLITE_InternChanges;
}
/* If the initFlag is 0 then create the index on disk. This
@ -617,13 +703,14 @@ void sqliteCreateIndex(
*/
if( pParse->initFlag==0 ){
static VdbeOp addTable[] = {
{ OP_OpenTbl, 2, 1, MASTER_NAME},
{ OP_New, 2, 0, 0},
{ OP_Open, 2, 2, 0},
{ OP_NewRecno, 2, 0, 0},
{ OP_String, 0, 0, "index"},
{ OP_String, 0, 0, 0}, /* 3 */
{ OP_String, 0, 0, 0}, /* 4 */
{ OP_CreateIndex, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 5 */
{ OP_MakeRecord, 4, 0, 0},
{ OP_String, 0, 0, 0}, /* 6 */
{ OP_MakeRecord, 5, 0, 0},
{ OP_Put, 2, 0, 0},
{ OP_Close, 2, 0, 0},
};
@ -634,29 +721,36 @@ void sqliteCreateIndex(
v = sqliteGetVdbe(pParse);
if( v==0 ) goto exit_create_index;
sqliteVdbeAddOp(v, OP_OpenTbl, 0, 0, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, 1, 1, pIndex->zName, 0);
if( pTable!=0 && (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_Open, 1, pIndex->tnum, pIndex->zName, 0);
if( pStart && pEnd ){
int base;
n = (int)pEnd->z - (int)pStart->z + 1;
base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
sqliteVdbeChangeP3(v, base+3, pIndex->zName, 0);
sqliteVdbeChangeP3(v, base+4, pTab->zName, 0);
sqliteVdbeChangeP3(v, base+5, pStart->z, n);
sqliteVdbeIndexRootAddr(v, &pIndex->tnum);
sqliteVdbeChangeP3(v, base+5, pTab->zName, 0);
sqliteVdbeChangeP3(v, base+6, pStart->z, n);
}
lbl1 = sqliteVdbeMakeLabel(v);
lbl2 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1);
sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_GetRecno, 0, 0, 0, 0);
for(i=0; i<pIndex->nColumn; i++){
sqliteVdbeAddOp(v, OP_Field, 0, pIndex->aiColumn[i], 0, 0);
sqliteVdbeAddOp(v, OP_Column, 0, pIndex->aiColumn[i], 0, 0);
}
sqliteVdbeAddOp(v, OP_MakeKey, pIndex->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_PutIdx, 1, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
if( pTable!=0 && (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
}
/* Reclaim memory on an EXPLAIN call.
@ -696,39 +790,35 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse);
if( v ){
static VdbeOp dropIndex[] = {
{ OP_OpenTbl, 0, 1, MASTER_NAME},
{ OP_ListOpen, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_Next, 0, ADDR(9), 0}, /* 3 */
{ OP_Open, 0, 2, 0},
{ OP_String, 0, 0, 0}, /* 1 */
{ OP_Next, 0, ADDR(8), 0}, /* 2 */
{ OP_Dup, 0, 0, 0},
{ OP_Field, 0, 1, 0},
{ OP_Ne, 0, ADDR(3), 0},
{ OP_Column, 0, 1, 0},
{ OP_Ne, 0, ADDR(2), 0},
{ OP_Key, 0, 0, 0},
{ OP_Delete, 0, 0, 0},
{ OP_Destroy, 0, 0, 0}, /* 9 */
{ OP_Destroy, 0, 0, 0}, /* 8 */
{ OP_Close, 0, 0, 0},
};
int base;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
sqliteVdbeChangeP3(v, base+9, pIndex->zName, 0);
sqliteVdbeChangeP1(v, base+8, pIndex->tnum);
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
}
/* Remove the index structure and free its memory. Except if the
** EXPLAIN keyword is present, no changes are made.
/* Mark the internal Index structure for deletion by the
** sqliteCommitInternalChanges routine.
*/
if( !pParse->explain ){
if( pIndex->pTable->pIndex==pIndex ){
pIndex->pTable->pIndex = pIndex->pNext;
}else{
Index *p;
for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
if( p && p->pNext==pIndex ){
p->pNext = pIndex->pNext;
}
}
sqliteDeleteIndex(pParse->db, pIndex);
pIndex->isDelete = 1;
db->flags |= SQLITE_InternChanges;
}
}
@ -881,12 +971,15 @@ void sqliteCopy(
}
v = sqliteGetVdbe(pParse);
if( v ){
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
sqliteVdbeDequoteP3(v, addr);
sqliteVdbeAddOp(v, OP_OpenTbl, 0, 1, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
sqliteVdbeAddOp(v, OP_OpenIdx, i, 1, pIdx->zName, 0);
sqliteVdbeAddOp(v, OP_Open, i, pIdx->tnum, pIdx->zName, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
@ -896,12 +989,12 @@ void sqliteCopy(
}else{
sqliteVdbeChangeP3(v, addr, "\t", 1);
}
sqliteVdbeAddOp(v, OP_New, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
if( pTab->pIndex ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
}
for(i=0; i<pTab->nCol; i++){
sqliteVdbeAddOp(v, OP_FileField, i, 0, 0, 0);
sqliteVdbeAddOp(v, OP_FileColumn, i, 0, 0, 0);
}
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
@ -910,13 +1003,16 @@ void sqliteCopy(
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
}
for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_FileField, pIdx->aiColumn[j], 0, 0, 0);
sqliteVdbeAddOp(v, OP_FileColumn, pIdx->aiColumn[j], 0, 0, 0);
}
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_PutIdx, i, 0, 0, 0);
}
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, end);
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
}
copy_cleanup:
@ -946,6 +1042,9 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
}
v = sqliteGetVdbe(pParse);
if( v==0 ) goto vacuum_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
if( zName ){
sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, zName, 0);
}else{
@ -961,6 +1060,9 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
}
}
}
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
vacuum_cleanup:
sqliteFree(zName);
@ -972,20 +1074,17 @@ vacuum_cleanup:
*/
void sqliteBeginTransaction(Parse *pParse){
int rc;
DbbeMethods *pM;
sqlite *db;
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
if( pParse->nErr || sqlite_malloc_failed ) return;
if( db->flags & SQLITE_InTrans ) return;
pM = pParse->db->pBe->x;
if( pM && pM->BeginTransaction ){
rc = (*pM->BeginTransaction)(pParse->db->pBe);
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
db->flags |= SQLITE_InTrans;
v = sqliteGetVdbe(pParse);
if( v ){
sqliteVdbeAddOp(v, OP_Transaction, 1, 0, 0, 0);
}
db->flags |= SQLITE_InTrans;
}
/*
@ -993,20 +1092,17 @@ void sqliteBeginTransaction(Parse *pParse){
*/
void sqliteCommitTransaction(Parse *pParse){
int rc;
DbbeMethods *pM;
sqlite *db;
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
if( pParse->nErr || sqlite_malloc_failed ) return;
if( (db->flags & SQLITE_InTrans)==0 ) return;
pM = pParse->db->pBe->x;
if( pM && pM->Commit ){
rc = (*pM->Commit)(pParse->db->pBe);
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
db->flags &= ~SQLITE_InTrans;
v = sqliteGetVdbe(pParse);
if( v ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
db->flags &= ~SQLITE_InTrans;
}
/*
@ -1014,18 +1110,15 @@ void sqliteCommitTransaction(Parse *pParse){
*/
void sqliteRollbackTransaction(Parse *pParse){
int rc;
DbbeMethods *pM;
sqlite *db;
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
if( pParse->nErr || sqlite_malloc_failed ) return;
if( (db->flags & SQLITE_InTrans)==0 ) return;
pM = pParse->db->pBe->x;
if( pM && pM->Rollback ){
rc = (*pM->Rollback)(pParse->db->pBe);
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
db->flags &= ~SQLITE_InTrans;
v = sqliteGetVdbe(pParse);
if( v ){
sqliteVdbeAddOp(v, OP_Rollback, 0, 0, 0, 0);
}
db->flags &= ~SQLITE_InTrans;
}

676
src/dbbebtree.c Normal file
View File

@ -0,0 +1,676 @@
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA 02111-1307, USA.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code to implement the database backend (DBBE)
** for sqlite. The database backend is the interface between
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses a custom B-Tree implementation as the database backend.
**
** $Id: dbbebtree.c,v 1.1 2001/09/13 13:46:56 drh Exp $
*/
#include "sqliteInt.h"
#include "btree.h"
/*
** The following structure contains all information used by B-Tree
** database driver. This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
Dbbe dbbe; /* The base class */
int write; /* True for write permission */
int inTrans; /* Currently in a transaction */
char *zFile; /* File containing the database */
Btree *pBt; /* Pointer to the open database */
BtCursor *pCur; /* Cursor for the main database table */
DbbeCursor *pDCur; /* List of all Dbbe cursors */
};
/*
** An cursor into a database table is an instance of the following
** structure.
*/
struct DbbeCursor {
DbbeCursor *pNext; /* Next on list of all cursors */
DbbeCursor *pPrev; /* Previous on list of all cursors */
Dbbex *pBe; /* The database of which this record is a part */
BtCursor *pCur; /* The cursor */
char *zTempFile; /* Name of file if referring to a temporary table */
Btree *pTempBt; /* Database handle, if this is a temporary table */
char *zKey; /* Most recent key. Memory obtained from sqliteMalloc() */
int nKey; /* Size of the key */
char *zKeyBuf; /* Space used during NextIndex() processing */
char *zData; /* Most recent data. Memory from sqliteMalloc() */
int needRewind; /* Next call to Next() returns first entry in table */
int skipNext; /* Do not advance cursor for next NextIndex() call */
};
/*
** Forward declaration
*/
static void sqliteBtbeCloseCursor(DbbeCursor *pCursr);
/*
** Completely shutdown the given database. Close all files. Free all memory.
*/
static void sqliteBtbeClose(Dbbe *pDbbe){
Dbbex *pBe = (Dbbex*)pDbbe;
assert( pBe->pDCur==0 );
if( pBe->pCur ){
sqliteBtreeCloseCursor(pBe->pCur);
}
sqliteBtreeClose(pBe->pBt);
sqliteFree(pBe->zFile);
sqliteFree(pBe);
}
/*
** Translate a database table name into the table number for the database.
** The pBe->pCur cursor points to table number 2 of the database and that
** table maps all other database names into database number. Return the
** database number of the table, or return 0 if not found.
*/
static int mapTableNameToNumber(Dbbex *pBe, char *zName){
int nName = strlen(zName);
int rc;
int res;
if( pBe->pCur==0 ){
rc = sqliteBtreeCursor(pBe, 2, &pBe->pCur);
if( rc!=SQLITE_OK ) return 0;
}
rc = sqliteBtreeMoveto(pBe->pCur, zName, nName, &res);
if( rc!=SQLITE_OK || res!=0 ) return 0;
rc = sqliteBtreeData(pBe->pCur, 0, sizeof(res), &res);
if( rc!=SQLITE_OK ) return 0;
return res;
}
/*
** Locate a directory where we can potentially create a temporary
** file.
*/
static const char *findTempDir(void){
static const char *azDirs[] = {
"/var/tmp",
"/usr/tmp",
"/tmp",
"/temp",
".",
"./temp",
};
int i;
struct stat buf;
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
if( stat(azDirs[i], &buf)==0 && S_ISDIR(buf.st_mode)
&& S_IWUSR(buf.st_mode) ){
return azDirs[i];
}
}
return 0;
}
/*
** Open a new table cursor. Write a pointer to the corresponding
** DbbeCursor structure into *ppCursr. Return an integer success
** code:
**
** SQLITE_OK It worked!
**
** SQLITE_NOMEM sqliteMalloc() failed
**
** SQLITE_PERM Attempt to access a file for which file
** access permission is denied
**
** SQLITE_BUSY Another thread or process is already using
** the corresponding file and has that file locked.
**
** SQLITE_READONLY The current thread already has this file open
** readonly but you are trying to open for writing.
** (This can happen if a SELECT callback tries to
** do an UPDATE or DELETE.)
**
** If the table does not previously exist and writeable is TRUE then
** a new table is created. If zTable is 0 or "", then a temporary
** database table is created and a cursor to that temporary file is
** opened. The temporary file will be deleted when it is closed.
*/
static int sqliteBtbeOpenCursor(
Dbbe *pDbbe, /* The database the table belongs to */
const char *zTable, /* The SQL name of the file to be opened */
int writeable, /* True to open for writing */
int intKeyOnly, /* True if only integer keys are used */
DbbeCursor **ppCursr /* Write the resulting table pointer here */
){
char *zFile; /* Name of the table file */
DbbeCursor *pCursr; /* The new table cursor */
int rc = SQLITE_OK; /* Return value */
int rw_mask; /* Permissions mask for opening a table */
int mode; /* Mode for opening a table */
Dbbex *pBe = (Dbbex*)pDbbe;
*ppCursr = 0;
if( pBe->pCur==0 ){
rc = sqliteBtreeCursor(pBe->pBt, 2, &pBe->pCur);
if( rc!=SQLITE_OK ) return rc;
}
pCursr = sqliteMalloc( sizeof(*pCursr) );
if( pCursr==0 ) return SQLITE_NOMEM;
if( zTable ){
char *zTab;
int tabId, i;
if( writeable && pBe->inTrans==0 ){
rc = sqliteBeginTrans(pBe->pBt);
if( rc!=SQLITE_OK ){
sqliteFree(pCursr);
return rc;
}
pBe->inTrans = 1;
}
zTab = sqliteStrDup(zTable);
for(i=0; zTab[i]; i++){
if( isupper(zTab[i]) ) zTab[i] = tolower(zTab[i]);
}
tabId = mapTableNameToNumber(pBe, zTab);
if( tabId==0 ){
if( writeable==0 ){
pCursr->pCur = 0;
}else{
rc = sqliteBtreeCreateTable(pBe->pBt, &tabId);
if( rc!=SQLITE_OK ){
sqliteFree(pCursr);
sqliteFree(zTab);
return rc;
}
sqliteBtreeInsert(pBe->pCur, zTab, strlen(zTab), tabId, sizeof(tabId));
}
}
sqliteFree(zTab);
rc = sqliteBtreeCursor(pBe->pBt, tabId, &pCursr->pCur);
if( rc!=SQLITE_OK ){
sqliteFree(pCursr);
return rc;
}
pCursr->zTempFile = 0;
pCursr->pTempBt = 0;
}else{
int nTry = 5;
char zFileName[200];
while( nTry>0 ){
nTry--;
sprintf(zFileName,"%s/_sqlite_temp_file_%d",
findTempDir(), sqliteRandomInteger());
rc = sqliteBtreeOpen(zFileName, 0, 100, &pCursr->pTempBt);
if( rc!=SQLITE_OK ) continue;
rc = sqliteBtreeCursor(pCursr->pTempBt, 2, &pCursr->pCur*****
pFile = 0;
zFile = 0;
}
pCursr->pNext = pBe->pDCur;
if( pBe->pDCur ){
pBe->pDCur->pPrev = pCursr;
}
pCursr->pPrev = 0;
pCursr->pBe = pBe;
pCursr->skipNext = 0;
pCursr->needRewind = 1;
return SQLITE_OK;
}
/*
** Drop a table from the database.
*/
static void sqliteBtbeDropTable(Dbbe *pDbbe, const char *zTable){
int iTable;
Dbbex *pBe = (Dbbex*)pDbbe;
iTable = mapTableNameToNumber(zTable);
if( iTable>0 ){
sqliteBtreeDelete(pBe->pCur);
sqliteBtreeDropTable(pBe->pBt, iTable);
}
}
/*
** Clear the remembered key and data from the cursor.
*/
static void clearCursorCache(DbbeCursor *pCursr){
if( pCursr->zKey ){
sqliteFree(pCursr->zKey);
pCursr->zKey = 0;
pCursr->nKey = 0;
pCursr->zKeyBuf = 0;
}
if( pCursr->zData ){
sqliteFree(pCursr->zData);
pCursr->zData = 0;
}
}
/*
** Close a cursor previously opened by sqliteBtbeOpenCursor().
*/
static void sqliteBtbeCloseCursor(DbbeCursor *pCursr){
Dbbex *pBe;
if( pCursr==0 ) return;
if( pCursr->pCur ){
sqliteBtreeCloseCursor(pCursr->pCur);
}
if( pCursr->pTemp ){
sqliteBtreeClose(pCursr->pTemp);
}
if( pCursr->zTempFile ){
unlink(pCursr->zTempFile);
sqliteFree(pCursr->zTempFile);
}
clearCursorCache(pCursr);
pBe = pCursr->pBe;
if( pCursr->pPrev ){
pCursr->pPrev->pNext = pCursr->pNext;
}else{
pBe->pDCur = pCur->pNext;
}
if( pCursr->pNext ){
pCursr->pNext->pPrev = pCursr->pPrev;
}
if( pBe->pDCur==0 && pBe->inTrans==0 && pBe->pCur!=0 ){
sqliteBtreeCloseCursor(pBe->pCur);
pBe->pCur = 0;
}
memset(pCursr, 0, sizeof(*pCursr));
sqliteFree(pCursr);
}
/*
** Reorganize a table to reduce search times and disk usage.
*/
static int sqliteBtbeReorganizeTable(Dbbe *pBe, const char *zTable){
return SQLITE_OK;
}
/*
** Move the cursor so that it points to the entry with a key that
** matches the argument. Return 1 on success and 0 if no keys match
** the argument.
*/
static int sqliteBtbeFetch(DbbeCursor *pCursr, int nKey, char *pKey){
int rc, res;
clearCursorCache(pCursr);
if( pCursr->pCur==0 ) return 0;
rc = sqliteBtreeMoveto(pCursr->pCur, pKey, nKey, &res);
return rc==SQLITE_OK && res==0;
}
/*
** Copy bytes from the current key or data into a buffer supplied by
** the calling function. Return the number of bytes copied.
*/
static
int sqliteBtbeCopyKey(DbbeCursor *pCursr, int offset, int size, char *zBuf){
if( pCursr->pCur==0 ) return 0;
int rc = sqliteBtreeKey(pCursr->pCur, offset, amt, zBuf);
if( rc!=SQLITE_OK ) amt = 0;
return amt;
}
static
int sqliteBtbeCopyData(DbbeCursor *pCursr, int offset, int size, char *zBuf){
if( pCursr->pCur==0 ) return 0;
int rc = sqliteBtreeData(pCursr->pCur, offset, amt, zBuf);
if( rc!=SQLITE_OK ) amt = 0;
return amt;
}
/*
** Return a pointer to bytes from the key or data. The data returned
** is ephemeral.
*/
static char *sqliteBtbeReadKey(DbbeCursor *pCursr, int offset){
if( pCursr->zKey==0 && pCursr->pCur!=0 ){
sqliteBtreeKeySize(pCursr->pCur, &pCursr->nKey);
pCursr->zKey = sqliteMalloc( pCursr->nKey + 1 );
if( pCursr->zKey==0 ) return 0;
sqliteBtreeKey(pCursr->pCur, 0, pCursr->nKey, pCursr->zKey);
pCursr->zKey[pCursor->nKey] = 0;
}
return pCursr->zKey;
}
static char *sqliteBtbeReadData(DbbeCursor *pCursr, int offset){
if( pCursr->zData==0 && pCursr->pCur!=0 ){
int nData;
sqliteBtreeDataSize(pCursr->pCur, &nData);
pCursr->zData = sqliteMalloc( nData + 1 );
if( pCursr->zData==0 ) return 0;
sqliteBtreeData(pCursr->pCur, 0, nData, pCursr->zData);
pCursr->zData[nData] = 0;
}
return pCursr->zData;
}
/*
** Return the total number of bytes in either data or key.
*/
static int sqliteBtbeKeyLength(DbbeCursor *pCursr){
int n;
if( pCursr->pCur==0 ) return 0;
sqliteBtreeKeySize(pCursr->pCur, &n);
return n;
}
static int sqliteBtbeDataLength(DbbeCursor *pCursr){
int n;
if( pCursr->pCur==0 ) return 0;
sqliteBtreeDataSize(pCursr->pCur, &n);
return n;
}
/*
** Make is so that the next call to sqliteNextKey() finds the first
** key of the table.
*/
static int sqliteBtbeRewind(DbbeCursor *pCursr){
pCursr->needRewind = 1;
return SQLITE_OK;
}
/*
** Move the cursor so that it points to the next key in the table.
** Return 1 on success. Return 0 if there are no more keys in this
** table.
**
** If the pCursr->needRewind flag is set, then move the cursor so
** that it points to the first key of the table.
*/
static int sqliteBtbeNextKey(DbbeCursor *pCursr){
int rc, res;
static char zNullKey[1] = { '\000' };
assert( pCursr!=0 );
clearCursorCache(pCursr);
if( pCursr->pCur==0 ) return 0;
if( pCursr->needRewind ){
rc = sqliteBtreeFirst(pCursr->pCur, &res);
return rc==SQLITE_OK && res==0;
}
rc = sqliteBtreeNext(pCursr->pCur);
return rc==SQLITE_OK && res==0;
}
/*
** Get a new integer key.
*/
static int sqliteBtbeNew(DbbeCursor *pCursr){
int rc;
int res = 0;
assert( pCursr->pCur!=0 );
while( res==0 ){
iKey = sqliteRandomInteger() & 0x7fffffff;
if( iKey==0 ) continue;
rc = sqliteBtreeMoveto(pCursr->pCur, &iKey, sizeof(iKey), &res);
assert( rc==SQLITE_OK );
}
clearCursorCache(pCursr);
return iKey;
}
/*
** Write an entry into the table. Overwrite any prior entry with the
** same key.
*/
static int sqliteBtbePut(
DbbeCursor *pCursr, /* Write to the database associated with this cursor */
int nKey, /* Number of bytes in the key */
char *pKey, /* The data for the key */
int nData, /* Number of bytes of data */
char *pData /* The data */
){
clearCursorCache(pCursr);
assert( pCursr->pCur!=0 );
return sqliteBtreeInsert(pCursr->pCur, pKey, nKey, pData, nData);
}
/*
** Remove an entry from a table, if the entry exists.
*/
static int sqliteBtbeDelete(DbbeCursor *pCursr, int nKey, char *pKey){
int rc;
int res;
clearCursorCache(pCursr);
assert( pCursr->pCur!=0 );
rc = sqliteBtreeMoveto(pCursr->pCur, pKey, nKey, &res);
if( rc==SQLITE_OK && res==0 ){
rc = sqliteBtreeDelete(pCursr->pCur);
}
return rc;
}
/*
** Begin a transaction.
*/
static int sqliteBtbeBeginTrans(Dbbe *pDbbe){
Dbbex *pBe = (Dbbex*)pDbbe;
if( pBe->inTrans ) return SQLITE_OK;
sqliteBtreeBeginTrans(pBe->pBt);
pBe->inTrans = 1;
return SQLITE_OK;
}
/*
** Commit a transaction.
*/
static int sqliteBtbeCommit(Dbbe *pDbbe){
Dbbex *pBe = (Dbbex*)pDbbe;
if( !pBe->inTrans ) return SQLITE_OK;
pBe->inTrans = 0;
return sqliteBtreeCommit(pBe->pBt);
}
/*
** Rollback a transaction.
*/
static int sqliteBtbeRollback(Dbbe *pDbbe){
Dbbex *pBe = (Dbbex*)pDbbe;
if( !pBe->inTrans ) return SQLITE_OK;
if( pBt->pDCur!=0 ) return SQLITE_INTERNAL;
pBe->inTrans = 0;
if( pBe->pCur ){
sqliteBtreeCloseCursor(pBe->pCur);
pBe->pCur = 0;
}
return sqliteBtreeRollback(pBe->pBt);
}
/*
** Begin scanning an index for the given key. Return 1 on success and
** 0 on failure. (Vdbe ignores the return value.)
*/
static int sqliteBtbeBeginIndex(DbbeCursor *pCursr, int nKey, char *pKey){
int rc;
int res;
clearCursorCache(pCursr);
if( pCursr->pCur==0 ) return 0;
pCursr->nKey = nKey;
pCursr->zKey = sqliteMalloc( 2*(nKey + 1) );
if( pCursr->zKey==0 ) return 0;
pCursr->zKeyBuf = &pCursr->zKey[nKey+1];
memcpy(pCursr->zKey, zKey, nKey);
pCursr->zKey[nKey] = 0;
rc = sqliteBtreeMoveTo(pCursr->pCur, pKey, nKey, res);
pCursr->skipNext = res<0;
return rc==SQLITE_OK;
}
/*
** Return an integer key which is the next record number in the index search
** that was started by a prior call to BeginIndex. Return 0 if all records
** have already been searched.
*/
static int sqliteBtbeNextIndex(DbbeCursor *pCursr){
int rc, res;
int iRecno;
BtCursor *pCur = pCursr->pCur;
if( pCur==0 ) return 0;
if( pCursr->zKey==0 || pCursr->zKeyBuf==0 ) return 0;
if( !pCursr->skipNext ){
rc = sqliteBtreeNext(pCur, &res);
pCursr->skipNext = 0;
if( res ) return 0;
}
if( sqliteBtreeKeySize(pCur)!=pCursr->nKey+4 ){
return 0;
}
rc = sqliteBtreeKey(pCur, 0, pCursr->nKey, pCursr->zKeyBuf);
if( rc!=SQLITE_OK || memcmp(pCursr->zKey, pCursr->zKeyBuf, pCursr->nKey)!=0 ){
return 0;
}
sqliteBtreeKey(pCur, pCursr->nKey, 4, &iRecno);
return iRecno;
}
/*
** Write a new record number and key into an index table. Return a status
** code.
*/
static int sqliteBtbePutIndex(DbbeCursor *pCursr, int nKey, char *pKey, int N){
char *zBuf;
int rc;
char zStaticSpace[200];
assert( pCursr->pCur!=0 );
if( nKey+4>sizeof(zStaticSpace){
zBuf = sqliteMalloc( nKey + 4 );
if( zBuf==0 ) return SQLITE_NOMEM;
}else{
zBuf = zStaticSpace;
}
memcpy(zBuf, pKey, nKey);
memcpy(&zBuf[nKey], N, 4);
rc = sqliteBtreeInsert(pCursr->pCur, zBuf, nKey+4, "", 0);
if( zBuf!=zStaticSpace ){
sqliteFree(zBuf);
}
}
/*
** Delete an index entry. Return a status code.
*/
static
int sqliteBtbeDeleteIndex(DbbeCursor *pCursr, int nKey, char *pKey, int N){
char *zBuf;
int rc;
char zStaticSpace[200];
assert( pCursr->pCur!=0 );
if( nKey+4>sizeof(zStaticSpace){
zBuf = sqliteMalloc( nKey + 4 );
if( zBuf==0 ) return SQLITE_NOMEM;
}else{
zBuf = zStaticSpace;
}
memcpy(zBuf, pKey, nKey);
memcpy(&zBuf[nKey], N, 4);
rc = sqliteBtreeMoveto(pCursr->pCur, zBuf, nKey+4, &res);
if( rc==SQLITE_OK && res==0 ){
sqliteBtreeDelete(pCursr->pCur);
}
if( zBuf!=zStaticSpace ){
sqliteFree(zBuf);
}
return SQLITE_OK;
}
/*
** This variable contains pointers to all of the access methods
** used to implement the GDBM backend.
*/
static struct DbbeMethods btbeMethods = {
/* Close */ sqliteBtbeClose,
/* OpenCursor */ sqliteBtbeOpenCursor,
/* DropTable */ sqliteBtbeDropTable,
/* ReorganizeTable */ sqliteBtbeReorganizeTable,
/* CloseCursor */ sqliteBtbeCloseCursor,
/* Fetch */ sqliteBtbeFetch,
/* Test */ sqliteBtbeFetch,
/* CopyKey */ sqliteBtbeCopyKey,
/* CopyData */ sqliteBtbeCopyData,
/* ReadKey */ sqliteBtbeReadKey,
/* ReadData */ sqliteBtbeReadData,
/* KeyLength */ sqliteBtbeKeyLength,
/* DataLength */ sqliteBtbeDataLength,
/* NextKey */ sqliteBtbeNextKey,
/* Rewind */ sqliteBtbeRewind,
/* New */ sqliteBtbeNew,
/* Put */ sqliteBtbePut,
/* Delete */ sqliteBtbeDelete,
/* BeginTrans */ sqliteBtbeBeginTrans,
/* Commit */ sqliteBtbeCommit,
/* Rollback */ sqliteBtbeRollback,
/* BeginIndex */ sqliteBtbeBeginIndex,
/* NextIndex */ sqliteBtbeNextIndex,
/* PutIndex */ sqliteBtbePutIndex,
/* DeleteIndex */ sqliteBtbeDeleteIndex,
};
/*
** This routine opens a new database. For the BTree driver
** implemented here, the database name is the name of a single
** file that contains all tables of the database.
**
** If successful, a pointer to the Dbbe structure is returned.
** If there are errors, an appropriate error message is left
** in *pzErrMsg and NULL is returned.
*/
Dbbe *sqliteBtbeOpen(
const char *zName, /* The name of the database */
int writeFlag, /* True if we will be writing to the database */
int createFlag, /* True to create database if it doesn't exist */
char **pzErrMsg /* Write error messages (if any) here */
){
Dbbex *pNew;
char *zTemp;
Btree *pBt;
int rc;
rc = sqliteBtreeOpen(zName, 0, 100, &pBt);
if( rc!=SQLITE_OK ){
sqliteSetString(pzErrMsg, "unable to open database file \"", zName, "\"",0);
return 0;
}
pNew = sqliteMalloc(sizeof(Dbbex) + strlen(zName) + 1);
if( pNew==0 ){
sqliteBtreeCloseCursor(pCur);
sqliteBtreeClose(pBt);
sqliteSetString(pzErrMsg, "out of memory", 0);
return 0;
}
pNew->dbbe.x = &btbeMethods;
pNew->write = writeFlag;
pNew->inTrans = 0;
pNew->zFile = (char*)&pNew[1];
strcpy(pNew->zFile, zName);
pNew->pBt = pBt;
pNew->pCur = 0;
return &pNew->dbbe;
}
#endif /* DISABLE_GDBM */

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.9 2001/04/11 14:28:42 drh Exp $
** $Id: delete.c,v 1.10 2001/09/13 13:46:56 drh Exp $
*/
#include "sqliteInt.h"
@ -90,14 +90,18 @@ void sqliteDeleteFrom(
*/
v = sqliteGetVdbe(pParse);
if( v==0 ) goto delete_from_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
/* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to deleted the database files directly.
*/
if( pWhere==0 ){
sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_Destroy, pTab->tnum, 0, 0, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pIdx->zName, 0);
sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0);
}
}
@ -125,9 +129,9 @@ void sqliteDeleteFrom(
*/
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_OpenIdx, base+i, 1, pIdx->zName, 0);
sqliteVdbeAddOp(v, OP_Open, base+i, pIdx->tnum, 0, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
@ -140,7 +144,7 @@ void sqliteDeleteFrom(
for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
}
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0);
}
}
@ -148,6 +152,10 @@ void sqliteDeleteFrom(
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
}
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
delete_from_cleanup:
sqliteIdListDelete(pTabList);

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements.
**
** $Id: insert.c,v 1.13 2001/04/11 14:28:42 drh Exp $
** $Id: insert.c,v 1.14 2001/09/13 13:46:56 drh Exp $
*/
#include "sqliteInt.h"
@ -85,6 +85,9 @@ void sqliteInsert(
*/
v = sqliteGetVdbe(pParse);
if( v==0 ) goto insert_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
/* Figure out how many columns of data are supplied. If the data
** is comming from a SELECT statement, then this step has to generate
@ -235,7 +238,7 @@ void sqliteInsert(
sqliteExprCode(pParse, pList->a[j].pExpr);
}
}
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_PutIdx, idx+base, 0, 0, 0);
}
@ -245,6 +248,10 @@ void sqliteInsert(
sqliteVdbeAddOp(v, OP_Goto, 0, iCont, 0, 0);
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, iBreak);
}
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
insert_cleanup:
if( pList ) sqliteExprListDelete(pList);

View File

@ -26,7 +26,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.29 2001/04/28 16:52:42 drh Exp $
** $Id: main.c,v 1.30 2001/09/13 13:46:56 drh Exp $
*/
#include "sqliteInt.h"
#if defined(HAVE_USLEEP) && HAVE_USLEEP
@ -87,6 +87,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
"CREATE TABLE " MASTER_NAME " (\n"
" type text,\n"
" name text,\n"
" tnum integer,\n"
" tbl_name text,\n"
" sql text\n"
")"
@ -100,6 +101,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
** CREATE TABLE sqlite_master (
** type text, -- Either "table" or "index" or "meta"
** name text, -- Name of table or index
** tnum integer, -- The integer page number of root page
** tbl_name text, -- Associated table
** sql text -- The CREATE statement for this object
** );
@ -126,32 +128,33 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
** database scheme.
*/
static VdbeOp initProg[] = {
{ OP_OpenTbl, 0, 0, MASTER_NAME},
{ OP_Open, 0, 2, 0},
{ OP_Next, 0, 9, 0}, /* 1 */
{ OP_Field, 0, 0, 0},
{ OP_Column, 0, 0, 0},
{ OP_String, 0, 0, "meta"},
{ OP_Ne, 0, 1, 0},
{ OP_Field, 0, 0, 0},
{ OP_Field, 0, 3, 0},
{ OP_Column, 0, 0, 0},
{ OP_Column, 0, 4, 0},
{ OP_Callback, 2, 0, 0},
{ OP_Goto, 0, 1, 0},
{ OP_Rewind, 0, 0, 0}, /* 9 */
{ OP_Next, 0, 17, 0}, /* 10 */
{ OP_Field, 0, 0, 0},
{ OP_Column, 0, 0, 0},
{ OP_String, 0, 0, "table"},
{ OP_Ne, 0, 10, 0},
{ OP_Field, 0, 3, 0},
{ OP_Column, 0, 4, 0},
{ OP_Callback, 1, 0, 0},
{ OP_Goto, 0, 10, 0},
{ OP_Rewind, 0, 0, 0}, /* 17 */
{ OP_Next, 0, 25, 0}, /* 18 */
{ OP_Field, 0, 0, 0},
{ OP_Column, 0, 0, 0},
{ OP_String, 0, 0, "index"},
{ OP_Ne, 0, 18, 0},
{ OP_Field, 0, 3, 0},
{ OP_Column, 0, 4, 0},
{ OP_Callback, 1, 0, 0},
{ OP_Goto, 0, 18, 0},
{ OP_Halt, 0, 0, 0}, /* 25 */
{ OP_Close, 2, 0, 0}, /* 25 */
{ OP_Halt, 0, 0, 0},
};
/* Create a virtual machine to run the initialization program. Run
@ -181,6 +184,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
pTab->readOnly = 1;
}
db->flags |= SQLITE_Initialized;
sqliteCommitInternalChanges(db);
}
return rc;
}
@ -219,11 +223,17 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
if( db==0 ) goto no_mem_on_open;
/* Open the backend database driver */
db->pBe = sqliteDbbeOpen(zFilename, (mode&0222)!=0, mode!=0, pzErrMsg);
if( db->pBe==0 ){
rc = sqliteBtreeOpen(zFilename, mode, 100, &db->pBe);
if( rc!=SQLITE_OK ){
switch( rc ){
default: {
if( pzErrMsg ){
sqliteSetString(pzErrMsg, "unable to open database: ", zFilename, 0);
}
}
}
sqliteFree(db);
sqliteStrRealloc(pzErrMsg);
return 0;
return rc;
}
/* Assume file format 1 unless the database says otherwise */
@ -253,7 +263,7 @@ no_mem_on_open:
*/
void sqlite_close(sqlite *db){
int i;
db->pBe->x->Close(db->pBe);
sqliteBtreeClose(db->pBe);
for(i=0; i<N_HASH; i++){
Table *pNext, *pList = db->apTblHash[i];
db->apTblHash[i] = 0;
@ -346,6 +356,7 @@ int sqlite_exec(
}
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sParse.pBe = db->pBe;
sParse.xCallback = xCallback;
sParse.pArg = pArg;
sqliteRunParser(&sParse, zSql, pzErrMsg);

View File

@ -25,9 +25,9 @@
**
** The page cache is used to access a database file. The pager journals
** all writes in order to support rollback. Locking is used to limit
** access to one or more reader or one writer.
** access to one or more reader or to one writer.
**
** @(#) $Id: pager.c,v 1.13 2001/07/02 17:51:46 drh Exp $
** @(#) $Id: pager.c,v 1.14 2001/09/13 13:46:57 drh Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
@ -122,6 +122,8 @@ struct Pager {
int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
unsigned char state; /* SQLITE_UNLOCK, _READLOCK or _WRITELOCK */
unsigned char errMask; /* One of several kinds of errors */
unsigned char tempFile; /* zFilename is a temporary file */
unsigned char readOnly; /* True for a read-only database */
unsigned char *aInJournal; /* One bit for each page in the database file */
PgHdr *pFirst, *pLast; /* List of free pages */
PgHdr *pAll; /* List of all pages */
@ -147,8 +149,8 @@ struct PageRecord {
};
/*
** Journal files begin with the following magic string. This data
** is completely random. It is used only as a sanity check.
** Journal files begin with the following magic string. The data
** was obtained from /dev/random. It is used only as a sanity check.
*/
static const unsigned char aJournalMagic[] = {
0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd4,
@ -163,7 +165,7 @@ static const unsigned char aJournalMagic[] = {
** Enable reference count tracking here:
*/
#if SQLITE_TEST
int pager_refinfo_enable = 0;
int pager_refinfo_enable = 0;
static void pager_refinfo(PgHdr *p){
static int cnt = 0;
if( !pager_refinfo_enable ) return;
@ -457,9 +459,33 @@ static int pager_playback(Pager *pPager){
return rc;
}
/*
** Locate a directory where we can potentially create a temporary
** file.
*/
static const char *findTempDir(void){
static const char *azDirs[] = {
".",
"/var/tmp",
"/usr/tmp",
"/tmp",
"/temp",
"./temp",
};
int i;
struct stat buf;
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
if( stat(azDirs[i], &buf)==0 && S_ISDIR(buf.st_mode)
&& S_IWUSR(buf.st_mode) ){
return azDirs[i];
}
}
return 0;
}
/*
** Create a new page cache and put a pointer to the page cache in *ppPager.
** The file to be cached need not exist. The file is not opened until
** The file to be cached need not exist. The file is not locked until
** the first call to sqlitepager_get() and is only held open until the
** last page is released using sqlitepager_unref().
*/
@ -472,12 +498,33 @@ int sqlitepager_open(
Pager *pPager;
int nameLen;
int fd;
int tempFile;
int readOnly = 0;
char zTemp[300];
*ppPager = 0;
if( sqlite_malloc_failed ){
return SQLITE_NOMEM;
}
fd = open(zFilename, O_RDWR|O_CREAT, 0644);
if( zFilename ){
fd = open(zFilename, O_RDWR|O_CREAT, 0644);
if( fd<0 ){
fd = open(zFilename, O_RDONLY, 0);
readOnly = 1;
}
tempFile = 0;
}else{
int cnt = 8;
char *zDir = findTempDir();
if( zDir==0 ) return SQLITE_CANTOPEN;
do{
cnt--;
sprintf(zTemp,"%s/_sqlite_%u",(unsigned)sqliteRandomInteger());
fd = open(zTemp, O_RDWR|O_CREAT|O_EXCL, 0600);
}while( cnt>0 && fd<0 );
zFilename = zTemp;
tempFile = 1;
}
if( fd<0 ){
return SQLITE_CANTOPEN;
}
@ -500,6 +547,8 @@ int sqlitepager_open(
pPager->mxPage = mxPage>5 ? mxPage : 10;
pPager->state = SQLITE_UNLOCK;
pPager->errMask = 0;
pPager->tempFile = tempFile;
pPager->readOnly = readOnly;
pPager->pFirst = 0;
pPager->pLast = 0;
pPager->nExtra = nExtra;
@ -510,7 +559,8 @@ int sqlitepager_open(
/*
** Set the destructor for this pager. If not NULL, the destructor is called
** when the reference count on the page reaches zero.
** when the reference count on each page reaches zero. The destructor can
** be used to clean up information in the extra segment appended to each page.
**
** The destructor is not called as a result sqlitepager_close().
** Destructors are only called by sqlitepager_unref().
@ -520,7 +570,8 @@ void sqlitepager_set_destructor(Pager *pPager, void (*xDesc)(void*)){
}
/*
** Return the total number of pages in the file opened by pPager.
** Return the total number of pages in the disk file associated with
** pPager.
*/
int sqlitepager_pagecount(Pager *pPager){
int n;
@ -572,12 +623,15 @@ int sqlitepager_close(Pager *pPager){
}
if( pPager->fd>=0 ) close(pPager->fd);
assert( pPager->jfd<0 );
if( pPager->tempFile ){
unlink(pPager->zFilename);
}
sqliteFree(pPager);
return SQLITE_OK;
}
/*
** Return the page number for the given page data
** Return the page number for the given page data.
*/
Pgno sqlitepager_pagenumber(void *pData){
PgHdr *p = DATA_TO_PGHDR(pData);
@ -621,8 +675,8 @@ int sqlitepager_ref(void *pData){
/*
** Acquire a page.
**
** A read lock is obtained for the first page acquired. The lock
** is dropped when the last page is released.
** A read lock on the disk file is obtained when the first page acquired.
** This read lock is dropped when the last page is released.
**
** A _get works for any page number greater than 0. If the database
** file is smaller than the requested page, then no actual disk
@ -635,7 +689,7 @@ int sqlitepager_ref(void *pData){
**
** See also sqlitepager_lookup(). Both this routine and _lookup() attempt
** to find a page in the in-memory cache first. If the page is not already
** in cache, this routine goes to disk to read it in whereas _lookup()
** in memory, this routine goes to disk to read it in whereas _lookup()
** just returns 0. This routine acquires a read-lock the first time it
** has to go to disk, and could also playback an old journal if necessary.
** Since _lookup() never goes to disk, it never has to deal with locks
@ -829,8 +883,8 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
** See also sqlitepager_get(). The difference between this routine
** and sqlitepager_get() is that _get() will go to the disk and read
** in the page if the page is not already in cache. This routine
** returns NULL if the page is not in cache of if a disk I/O has ever
** happened.
** returns NULL if the page is not in cache or if a disk I/O error
** has ever happened.
*/
void *sqlitepager_lookup(Pager *pPager, Pgno pgno){
PgHdr *pPg;
@ -925,6 +979,9 @@ int sqlitepager_write(void *pData){
if( pPager->errMask ){
return pager_errcode(pPager);
}
if( pPager->readOnly ){
return SQLITE_PERM;
}
pPg->dirty = 1;
if( pPg->inJournal ){ return SQLITE_OK; }
assert( pPager->state!=SQLITE_UNLOCK );
@ -1076,6 +1133,14 @@ int sqlitepager_rollback(Pager *pPager){
return rc;
};
/*
** Return TRUE if the database file is opened read-only. Return FALSE
** if the database is (in theory) writable.
*/
int sqlitepager_isreadonly(Pager *pPager){
return pPager->readonly;
}
/*
** This routine is used for testing and analysis only.
*/

View File

@ -25,7 +25,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.7 2001/07/02 17:51:46 drh Exp $
** @(#) $Id: pager.h,v 1.8 2001/09/13 13:46:57 drh Exp $
*/
/*
@ -57,6 +57,7 @@ int sqlitepager_iswriteable(void*);
int sqlitepager_pagecount(Pager*);
int sqlitepager_commit(Pager*);
int sqlitepager_rollback(Pager*);
int sqlitepager_isreadonly(Pager*);
int *sqlitepager_stats(Pager*);
#ifdef SQLITE_TEST

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
** $Id: select.c,v 1.31 2001/04/11 14:28:42 drh Exp $
** $Id: select.c,v 1.32 2001/09/13 13:46:57 drh Exp $
*/
#include "sqliteInt.h"
@ -515,10 +515,10 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
return 1;
}
if( p->op!=TK_ALL ){
sqliteVdbeAddOp(v, OP_OpenIdx, unionTab, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0, 0, 0);
sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1, 0, 0);
}else{
sqliteVdbeAddOp(v, OP_OpenTbl, unionTab, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0, 0, 0);
}
}
@ -576,7 +576,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
return 1;
}
sqliteVdbeAddOp(v, OP_OpenIdx, tab1, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTemp, tab1, 0, 0, 0);
sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1, 0, 0);
/* Code the SELECTs to our left into temporary table "tab1".
@ -586,7 +586,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
/* Code the current SELECT into temporary table "tab2"
*/
sqliteVdbeAddOp(v, OP_OpenIdx, tab2, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTemp, tab2, 0, 0, 0);
sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1, 0, 0);
p->pPrior = 0;
rc = sqliteSelect(pParse, p, SRT_Union, tab2);
@ -877,7 +877,7 @@ int sqliteSelect(
/* Begin the database scan
*/
if( isDistinct ){
sqliteVdbeAddOp(v, OP_OpenIdx, distinct, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTemp, distinct, 0, 0, 0);
}
pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
if( pWInfo==0 ) return 1;

View File

@ -24,7 +24,7 @@
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.31 2001/04/11 14:28:42 drh Exp $
** $Id: shell.c,v 1.32 2001/09/13 13:46:57 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
@ -40,7 +40,7 @@
# include <readline/readline.h>
# include <readline/history.h>
#else
# define readline getline
# define readline(p) getline(p,stdin)
# define add_history(X)
#endif

View File

@ -24,7 +24,7 @@
** This header file defines the interface that the sqlite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.13 2001/04/07 15:24:33 drh Exp $
** @(#) $Id: sqlite.h.in,v 1.14 2001/09/13 13:46:57 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
@ -159,6 +159,7 @@ int sqlite_exec(
#define SQLITE_FULL 12 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 13 /* Unable to open the database file */
#define SQLITE_PROTOCOL 14 /* Database lock protocol error */
#define SQLITE_EMPTY 15 /* Database table is empty */
/* This function causes any pending database operation to abort and
** return at its earliest opportunity. This routine is typically

View File

@ -23,10 +23,9 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.42 2001/04/28 16:52:42 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.43 2001/09/13 13:46:57 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#ifndef DISABLE_GDBM
@ -136,23 +135,24 @@ typedef struct AggExpr AggExpr;
** Each database is an instance of the following structure
*/
struct sqlite {
Dbbe *pBe; /* The backend driver */
int flags; /* Miscellanous flags. See below */
int file_format; /* What file format version is this database? */
int nTable; /* Number of tables in the database */
void *pBusyArg; /* 1st Argument to the busy callback */
Btree *pBe; /* The B*Tree backend */
int flags; /* Miscellanous flags. See below */
int file_format; /* What file format version is this database? */
int nTable; /* Number of tables in the database */
void *pBusyArg; /* 1st Argument to the busy callback */
int (*xBusyCallback)(void *,const char*,int); /* The busy callback */
Table *apTblHash[N_HASH]; /* All tables of the database */
Index *apIdxHash[N_HASH]; /* All indices of the database */
Table *apTblHash[N_HASH]; /* All tables of the database */
Index *apIdxHash[N_HASH]; /* All indices of the database */
};
/*
** Possible values for the sqlite.flags.
*/
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
#define SQLITE_Initialized 0x00000002 /* True after initialization */
#define SQLITE_Interrupt 0x00000004 /* Cancel current operation */
#define SQLITE_InTrans 0x00000008 /* True if in a transaction */
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
#define SQLITE_Initialized 0x00000002 /* True after initialization */
#define SQLITE_Interrupt 0x00000004 /* Cancel current operation */
#define SQLITE_InTrans 0x00000008 /* True if in a transaction */
#define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */
/*
** Current file format version
@ -178,8 +178,11 @@ struct Table {
Table *pHash; /* Next table with same hash on zName */
int nCol; /* Number of columns in this table */
Column *aCol; /* Information about each column */
int readOnly; /* True if this table should not be written by the user */
Index *pIndex; /* List of SQL indexes on this table. */
int tnum; /* Page containing root for this table */
int readOnly; /* True if this table should not be written by the user */
int isCommit; /* True if creation of this table has been committed */
int isDelete; /* True if deletion of this table has not been comitted */
};
/*
@ -208,6 +211,8 @@ struct Index {
int *aiColumn; /* Which columns are used by this index. 1st is 0 */
Table *pTable; /* The SQL table being indexed */
int isUnique; /* True if keys must all be unique */
int isCommit; /* True if creation of this index has been committed */
int isDelete; /* True if deletion of this index has not been comitted */
Index *pNext; /* The next index associated with the same table */
};
@ -342,6 +347,7 @@ 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 */
@ -398,6 +404,8 @@ Expr *sqliteExprFunction(ExprList*, Token*);
void sqliteExprDelete(Expr*);
ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*);
void sqliteExprListDelete(ExprList*);
void sqliteCommitInternalChanges(sqlite*);
void sqliteRollbackInternalChanges(sqlite*);
void sqliteStartTable(Parse*,Token*,Token*);
void sqliteAddColumn(Parse*,Token*);
void sqliteAddDefaultValue(Parse*,Token*,int);
@ -442,3 +450,4 @@ void sqliteBeginTransaction(Parse*);
void sqliteCommitTransaction(Parse*);
void sqliteRollbackTransaction(Parse*);
char *sqlite_mprintf(const char *, ...);
const char *sqliteErrStr(int);

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.11 2001/04/11 14:28:43 drh Exp $
** $Id: update.c,v 1.12 2001/09/13 13:46:57 drh Exp $
*/
#include "sqliteInt.h"
@ -144,6 +144,9 @@ void sqliteUpdate(
*/
v = sqliteGetVdbe(pParse);
if( v==0 ) goto update_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
/* Begin the database scan
*/
@ -164,9 +167,9 @@ void sqliteUpdate(
*/
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0);
for(i=0; i<nIdx; i++){
sqliteVdbeAddOp(v, OP_OpenIdx, base+i+1, 1, apIdx[i]->zName, 0);
sqliteVdbeAddOp(v, OP_Open, base+i+1, apIdx[i]->tnum, 0, 0);
}
/* Loop over every record that needs updating. We have to load
@ -177,7 +180,7 @@ void sqliteUpdate(
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MoveTo, base, 0, 0, 0);
/* Delete the old indices for the current record.
*/
@ -185,9 +188,9 @@ void sqliteUpdate(
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
pIdx = apIdx[i];
for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j], 0, 0);
}
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
}
@ -196,7 +199,7 @@ void sqliteUpdate(
for(i=0; i<pTab->nCol; i++){
j = aXRef[i];
if( j<0 ){
sqliteVdbeAddOp(v, OP_Field, base, i, 0, 0);
sqliteVdbeAddOp(v, OP_Column, base, i, 0, 0);
}else{
sqliteExprCode(pParse, pChanges->a[j].pExpr);
}
@ -210,7 +213,7 @@ void sqliteUpdate(
for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiColumn[j], 0, 0, 0);
}
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
}
@ -224,6 +227,9 @@ void sqliteUpdate(
*/
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
update_cleanup:
sqliteFree(apIdx);

View File

@ -26,7 +26,7 @@
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.21 2001/04/11 14:28:43 drh Exp $
** $Id: util.c,v 1.22 2001/09/13 13:46:57 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@ -972,3 +972,31 @@ sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){
}
return *zString==0;
}
/*
** Return a static string that describes the kind of error specified in the
** argument.
*/
const char *sqliteErrStr(int rc){
char *z = 0;
switch( rc ){
case SQLITE_OK: z = "not an error"; break;
case SQLITE_ERROR: z = "SQL logic error or missing database"; break;
case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break;
case SQLITE_PERM: z = "access permission denied"; break;
case SQLITE_ABORT: z = "callback requested query abort"; break;
case SQLITE_BUSY: z = "database in use by another process"; break;
case SQLITE_NOMEM: z = "out of memory"; break;
case SQLITE_READONLY: z = "attempt to write a readonly database"; break;
case SQLITE_INTERRUPT: z = "interrupted"; break;
case SQLITE_IOERR: z = "disk I/O error"; break;
case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
case SQLITE_NOTFOUND: z = "table or record not found"; break;
case SQLITE_FULL: z = "database is full"; break;
case SQLITE_CANTOPEN: z = "unable to open database file"; break;
case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
case SQLITE_EMPTY: z = "table contains no data";
default:
}
return z;
}

4930
src/vdbe.c

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.18 2001/08/19 18:19:46 drh Exp $
** $Id: vdbe.h,v 1.19 2001/09/13 13:46:57 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -71,122 +71,133 @@ typedef struct VdbeOp VdbeOp;
** The source tree contains an AWK script named renumberOps.awk that
** can be used to renumber these opcodes when new opcodes are inserted.
*/
#define OP_OpenIdx 1
#define OP_OpenTbl 2
#define OP_Close 3
#define OP_Fetch 4
#define OP_Fcnt 5
#define OP_New 6
#define OP_Put 7
#define OP_Distinct 8
#define OP_Found 9
#define OP_NotFound 10
#define OP_Delete 11
#define OP_Field 12
#define OP_KeyAsData 13
#define OP_Key 14
#define OP_FullKey 15
#define OP_Rewind 16
#define OP_Next 17
#define OP_Transaction 1
#define OP_Commit 2
#define OP_Rollback 3
#define OP_Destroy 18
#define OP_Reorganize 19
#define OP_Open 4
#define OP_OpenTemp 5
#define OP_Close 6
#define OP_MoveTo 7
#define OP_Fcnt 8
#define OP_NewRecno 9
#define OP_Put 10
#define OP_Distinct 11
#define OP_Found 12
#define OP_NotFound 13
#define OP_Delete 14
#define OP_Column 15
#define OP_KeyAsData 16
#define OP_Recno 17
#define OP_FullKey 18
#define OP_Rewind 19
#define OP_Next 20
#define OP_BeginIdx 20
#define OP_NextIdx 21
#define OP_PutIdx 22
#define OP_DeleteIdx 23
#define OP_Destroy 21
#define OP_CreateIndex 22
#define OP_CreateTable 23
#define OP_Reorganize 24
#define OP_MemLoad 24
#define OP_MemStore 25
#define OP_BeginIdx 25
#define OP_NextIdx 26
#define OP_PutIdx 27
#define OP_DeleteIdx 28
#define OP_ListOpen 26
#define OP_ListWrite 27
#define OP_ListRewind 28
#define OP_ListRead 29
#define OP_ListClose 30
#define OP_MemLoad 29
#define OP_MemStore 30
#define OP_SortOpen 31
#define OP_SortPut 32
#define OP_SortMakeRec 33
#define OP_SortMakeKey 34
#define OP_Sort 35
#define OP_SortNext 36
#define OP_SortKey 37
#define OP_SortCallback 38
#define OP_SortClose 39
#define OP_ListOpen 31
#define OP_ListWrite 32
#define OP_ListRewind 33
#define OP_ListRead 34
#define OP_ListClose 35
#define OP_FileOpen 40
#define OP_FileRead 41
#define OP_FileField 42
#define OP_FileClose 43
#define OP_SortOpen 36
#define OP_SortPut 37
#define OP_SortMakeRec 38
#define OP_SortMakeKey 39
#define OP_Sort 40
#define OP_SortNext 41
#define OP_SortKey 42
#define OP_SortCallback 43
#define OP_SortClose 44
#define OP_AggReset 44
#define OP_AggFocus 45
#define OP_AggIncr 46
#define OP_AggNext 47
#define OP_AggSet 48
#define OP_AggGet 49
#define OP_FileOpen 45
#define OP_FileRead 46
#define OP_FileField 47
#define OP_FileClose 48
#define OP_SetInsert 50
#define OP_SetFound 51
#define OP_SetNotFound 52
#define OP_SetClear 53
#define OP_AggReset 49
#define OP_AggFocus 50
#define OP_AggIncr 51
#define OP_AggNext 52
#define OP_AggSet 53
#define OP_AggGet 54
#define OP_MakeRecord 54
#define OP_MakeKey 55
#define OP_SetInsert 55
#define OP_SetFound 56
#define OP_SetNotFound 57
#define OP_SetClear 58
#define OP_Goto 56
#define OP_If 57
#define OP_Halt 58
#define OP_MakeRecord 59
#define OP_MakeKey 60
#define OP_MakeIdxKey 61
#define OP_ColumnCount 59
#define OP_ColumnName 60
#define OP_Callback 61
#define OP_Goto 62
#define OP_If 63
#define OP_Halt 64
#define OP_Integer 62
#define OP_String 63
#define OP_Null 64
#define OP_Pop 65
#define OP_Dup 66
#define OP_Pull 67
#define OP_ColumnCount 65
#define OP_ColumnName 66
#define OP_Callback 67
#define OP_Add 68
#define OP_AddImm 69
#define OP_Subtract 70
#define OP_Multiply 71
#define OP_Divide 72
#define OP_Min 73
#define OP_Max 74
#define OP_Like 75
#define OP_Glob 76
#define OP_Eq 77
#define OP_Ne 78
#define OP_Lt 79
#define OP_Le 80
#define OP_Gt 81
#define OP_Ge 82
#define OP_IsNull 83
#define OP_NotNull 84
#define OP_Negative 85
#define OP_And 86
#define OP_Or 87
#define OP_Not 88
#define OP_Concat 89
#define OP_Noop 90
#define OP_Integer 68
#define OP_String 69
#define OP_Null 70
#define OP_Pop 71
#define OP_Dup 72
#define OP_Pull 73
#define OP_Strlen 91
#define OP_Substr 92
#define OP_Add 74
#define OP_AddImm 75
#define OP_Subtract 76
#define OP_Multiply 77
#define OP_Divide 78
#define OP_Min 79
#define OP_Max 80
#define OP_Like 81
#define OP_Glob 82
#define OP_Eq 83
#define OP_Ne 84
#define OP_Lt 85
#define OP_Le 86
#define OP_Gt 87
#define OP_Ge 88
#define OP_IsNull 89
#define OP_NotNull 90
#define OP_Negative 91
#define OP_And 92
#define OP_Or 93
#define OP_Not 94
#define OP_Concat 95
#define OP_Noop 96
#define OP_MAX 93
#define OP_Strlen 97
#define OP_Substr 98
#define OP_MAX 98
/*
** Prototypes for the VDBE interface. See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(sqlite*);
void sqliteVdbeCreateCallback(Vdbe*, int*);
void sqliteVdbeTableRootAddr(Vdbe*, int*);
void sqliteVdbeIndexRootAddr(Vdbe*, int*);
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);
int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
void sqliteVdbeChangeP1(Vdbe*, int addr, int P1);
void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
void sqliteVdbeDequoteP3(Vdbe*, int addr);
int sqliteVdbeMakeLabel(Vdbe*);

View File

@ -25,7 +25,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.15 2001/08/19 18:19:46 drh Exp $
** $Id: where.c,v 1.16 2001/09/13 13:46:57 drh Exp $
*/
#include "sqliteInt.h"
@ -297,9 +297,11 @@ WhereInfo *sqliteWhereBegin(
/* Open all tables in the pTabList and all indices in aIdx[].
*/
for(i=0; i<pTabList->nId; i++){
sqliteVdbeAddOp(v, OP_OpenTbl, base+i, 0, pTabList->a[i].pTab->zName, 0);
sqliteVdbeAddOp(v, OP_Open, base+i, pTabList->a[i].pTab->tnum,
pTabList->a[i].pTab->zName, 0);
if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
sqliteVdbeAddOp(v, OP_OpenIdx, base+pTabList->nId+i, 0, aIdx[i]->zName,0);
sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, aIdx[i]->tnum
aIdx[i]->zName, 0);
}
}
memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx));