diff --git a/Makefile.in b/Makefile.in index 20ffb5e313..b0213a2908 100644 --- a/Makefile.in +++ b/Makefile.in @@ -47,7 +47,7 @@ LIBREADLINE = @TARGET_READLINE_LIBS@ # Object files for the SQLite library. # -LIBOBJ = btree.o build.o dbbe.o dbbegdbm.o dbbemem.o delete.o expr.o insert.o \ +LIBOBJ = btree.o build.o delete.o expr.o insert.o \ main.o pager.o parse.o printf.o random.o select.o table.o \ tokenize.o update.o util.o vdbe.o where.o tclsqlite.o @@ -55,16 +55,14 @@ LIBOBJ = btree.o build.o dbbe.o dbbegdbm.o dbbemem.o delete.o expr.o insert.o \ # SRC = \ $(TOP)/src/btree.c \ + $(TOP)/src/btree.h \ $(TOP)/src/build.c \ - $(TOP)/src/dbbe.c \ - $(TOP)/src/dbbe.h \ - $(TOP)/src/dbbegdbm.c \ - $(TOP)/src/dbbemem.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ $(TOP)/src/insert.c \ $(TOP)/src/main.c \ $(TOP)/src/pager.c \ + $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ @@ -121,30 +119,21 @@ lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c # HDR = \ sqlite.h \ + $(TOP)/src/btree.h \ $(TOP)/src/sqliteInt.h \ - $(TOP)/src/dbbe.h \ $(TOP)/src/vdbe.h \ parse.h -btree.o: $(TOP)/src/btree.c $(HDR) +btree.o: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/btree.c build.o: $(TOP)/src/build.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/build.c -dbbe.o: $(TOP)/src/dbbe.c $(HDR) - $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbe.c - -dbbegdbm.o: $(TOP)/src/dbbegdbm.c $(HDR) - $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbegdbm.c - -dbbemem.o: $(TOP)/src/dbbemem.c $(HDR) - $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbemem.c - main.o: $(TOP)/src/main.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/main.c -pager.o: $(TOP)/src/pager.c $(HDR) +pager.o: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/pager.c parse.o: parse.c $(HDR) diff --git a/manifest b/manifest index 50f453860c..986a8fb9b6 100644 --- a/manifest +++ b/manifest @@ -1,7 +1,7 @@ -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 +C The\sBTree\schanges\sare\snow\sintegrated\sand\sthe\swhole\sthing\scompiles\sand\nlinks.\sI\shave\snot\syet\stried\sto\srun\sit,\sthough.\s(CVS\s239) +D 2001-09-13T14:46:10 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 -F Makefile.in 9eea999e1d95531de4dd0a96a6ecf6ba0027b05b +F Makefile.in 7ecb2370b5cb34d390af1fcb3118ea6d84a253ca F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F VERSION 00453ed53ff28fe8e701e1609e81f1b9df12adab F configure d2051345f49f7e48604423da26e086a745c86a47 x @@ -13,15 +13,10 @@ F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e F notes/notes2b.txt 1c17a5b7f6b44a75cd3eb98ed2c24db1eefb06c3 F notes/notes3.txt 71e47be517e3d2578b3b9343a45b772d43b7ba16 F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4 -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 bee9e20720436b74d7116735389ac81f7aa1d684 +F src/btree.c 9f22b51681bcc0026ea300134e4e2f1f40fc0800 +F src/btree.h 2427961c702dd0755ec70f529cf3db32707d689b +F src/build.c 58020177a1b96455284899774442833a81c5ae9c +F src/delete.c 769a28cf35ab75df4b2416982d8369520b28f3c5 F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7 F src/ex/db.h 3f2933ee20c147fe494835786e4c6f3a562def4e @@ -30,20 +25,20 @@ F src/ex/dbbemird.c b00aef85656fa0a101dac2c32e12922ad106715a 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 51d21e65eba5b4bef017fec6af79266bc0065824 -F src/main.c afdb7ecb5de4e0eb0d69d1e0d5db7ad070c8e0d6 +F src/expr.c 83b6a7ed4cf502249f192b698517e9a9b8f05303 +F src/insert.c 1072c0dd7782c17af735df37f447630d4d577ba1 +F src/main.c b7a2da8375ca61d4464610368608e7fd0566b950 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c -F src/pager.c 1928e68b5c00c24749b71f41eeabacd7217337a5 +F src/pager.c 05a2177c99a835c3efec1e4187556e2e29311d4a F src/pager.h 238aa88bafe33911bf9b0b365f35afd0a261cd46 F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9 F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a -F src/select.c e5977916f59a79d67c40fae11e2c5736cddd1fa8 +F src/select.c 391921bcc612e15efecc451e42a93697fb826e46 F src/shell.c 1fcdf8c4180098bcfdee12501e01b4c8eb21d726 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in 8faa2fed0513d188ced16e5f9094e57694594e70 -F src/sqliteInt.h 1a3a7ac6db97c15ec6e80ee8df8a8f8eadf70316 +F src/sqliteInt.h f8b8417dde95419d2e4ab683ce4ac418f96913bd F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6 F src/tclsqlite.c d328970848c028e13e61e173bef79adcc379568a F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4 @@ -52,12 +47,12 @@ F src/test3.c 147b42ec368a10e9f267e7466d30c46e76d7f278 F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf 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 src/vdbe.c f502b592d1cc94f68e9e4b3fa130361cb3038b0c +F src/vdbe.h 6ee941ecd78b7b224607517fd060d6547910dc10 +F src/where.c b9f6d2c029983e9db9521474c876f9a039e7fb6c F test/all.test 21d55a97e39e7ec5776751dc9dd8b1b51ef4a048 F test/btree.test 5e1eeb03cda22161eec827dc5224ce6c500eaaf9 -F test/btree2.test a66add2093843d0e5617fed6924002667832f279 +F test/btree2.test a3c9ff1e4490357dd15c9a41f8aefd02f6e32fdc F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf @@ -113,7 +108,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad -P 2e6aff980287825b59d2ebb7005bb08dd601ff1c -R 2654e388e3b472efb037b78486fd2a60 +P 6ecc8b20d4f402f45f03d46d8d4fa40dea666e97 +R 9f3dc1f51d7a55174d7eb7f5f17c9756 U drh -Z bd85e26e61c9c38cc5377a9e930cda9b +Z 89f03479b34b99fd737e2528660926bd diff --git a/manifest.uuid b/manifest.uuid index a3d6fe45fc..dce1623836 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6ecc8b20d4f402f45f03d46d8d4fa40dea666e97 \ No newline at end of file +a0a1e701abc52a164d9b09a5426eb12af1fe6a4c \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index b34f59ccd5..a67af7d4aa 100644 --- a/src/btree.c +++ b/src/btree.c @@ -21,7 +21,7 @@ ** http://www.hwaci.com/drh/ ** ************************************************************************* -** $Id: btree.c,v 1.22 2001/09/13 13:46:56 drh Exp $ +** $Id: btree.c,v 1.23 2001/09/13 14:46:10 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -726,7 +726,7 @@ int sqliteBtreeBeginTrans(Btree *pBt){ return rc; } } - if( !sqlitepager_isreadonly(pBt) ){ + if( !sqlitepager_isreadonly(pBt->pPager) ){ rc = sqlitepager_write(pBt->page1); if( rc!=SQLITE_OK ){ return rc; @@ -2012,7 +2012,7 @@ balance_cleanup: */ int sqliteBtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ - const void *pKey, int nKey, /* The key of the new record */ + const void *pKey, int nKey, /* The key of the new record */ const void *pData, int nData /* The data of the new record */ ){ Cell newCell; diff --git a/src/btree.h b/src/btree.h index 6d9230d5cd..993b3d2d0b 100644 --- a/src/btree.h +++ b/src/btree.h @@ -24,8 +24,10 @@ ** This header file defines the interface that the sqlite B-Tree file ** subsystem. ** -** @(#) $Id: btree.h,v 1.11 2001/09/13 13:46:56 drh Exp $ +** @(#) $Id: btree.h,v 1.12 2001/09/13 14:46:10 drh Exp $ */ +#ifndef _BTREE_H_ +#define _BTREE_H_ typedef struct Btree Btree; typedef struct BtCursor BtCursor; @@ -62,6 +64,8 @@ int sqliteBtreeUpdateMeta(Btree*, int*); #ifdef SQLITE_TEST int sqliteBtreePageDump(Btree*, int, int); int sqliteBtreeCursorDump(BtCursor*, int*); -Pager *sqliteBtreePager(Btree*); +struct Pager *sqliteBtreePager(Btree*); char *sqliteBtreeSanityCheck(Btree*, int*, int); #endif + +#endif /* _BTREE_H_ */ diff --git a/src/build.c b/src/build.c index a11c7a243a..2d452d8ceb 100644 --- a/src/build.c +++ b/src/build.c @@ -33,7 +33,7 @@ ** COPY ** VACUUM ** -** $Id: build.c,v 1.29 2001/09/13 13:46:56 drh Exp $ +** $Id: build.c,v 1.30 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" @@ -49,17 +49,18 @@ */ void sqliteExec(Parse *pParse){ int rc = SQLITE_OK; + sqlite *db = pParse->db; if( sqlite_malloc_failed ) return; if( pParse->pVdbe ){ if( pParse->explain ){ rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, &pParse->zErrMsg); }else{ - FILE *trace = (pParse->db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0; + FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0; sqliteVdbeTrace(pParse->pVdbe, trace); rc = sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg, - &pParse->zErrMsg, pParse->db->pBusyArg, - pParse->db->xBusyCallback); + &pParse->zErrMsg, db->pBusyArg, + db->xBusyCallback); } sqliteVdbeDelete(pParse->pVdbe); pParse->pVdbe = 0; @@ -258,7 +259,7 @@ void sqliteCommitInternalChanges(sqlite *db){ if( (db->flags & SQLITE_InternChanges)==0 ) return; for(i=0; iapTblHash[i]; pTable; pTable=pNext){ pNext = pTable->pHash; if( pTable->isDelete ){ sqliteDeleteTable(db, pTable); @@ -269,7 +270,7 @@ void sqliteCommitInternalChanges(sqlite *db){ } for(i=0; iapIdxHash[i]; pIndex; pIndex=pNext){ pNext = pIndex->pHash; if( pIndex->isDelete ){ sqliteUnlinkAndDeleteIndex(db, pIndex); @@ -294,7 +295,7 @@ void sqliteRollbackInternalChanges(sqlite *db){ if( (db->flags & SQLITE_InternChanges)==0 ) return; for(i=0; iapTblHash[i]; pTable; pTable=pNext){ pNext = pTable->pHash; if( !pTable->isCommit ){ sqliteDeleteTable(db, pTable); @@ -305,7 +306,7 @@ void sqliteRollbackInternalChanges(sqlite *db){ } for(i=0; iapIdxHash[i]; pIndex; pIndex=pNext){ pNext = pIndex->pHash; if( !pIndex->isCommit ){ sqliteUnlinkAndDeleteIndex(db, pIndex); @@ -343,11 +344,12 @@ char *sqliteTableNameFromToken(Token *pName){ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ Table *pTable; char *zName; + sqlite *db = pParse->db; pParse->sFirstToken = *pStart; zName = sqliteTableNameFromToken(pName); if( zName==0 ) return; - pTable = sqliteFindTable(pParse->db, zName); + pTable = sqliteFindTable(db, zName); if( pTable!=0 ){ sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, " already exists", 0, 0); @@ -355,7 +357,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ pParse->nErr++; return; } - if( sqliteFindIndex(pParse->db, zName) ){ + if( sqliteFindIndex(db, zName) ){ sqliteSetString(&pParse->zErrMsg, "there is already an index named ", zName, 0); sqliteFree(zName); @@ -369,9 +371,9 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ pTable->nCol = 0; pTable->aCol = 0; pTable->pIndex = 0; - if( pParse->pNewTable ) sqliteDeleteTable(pParse->db, pParse->pNewTable); + if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; - if( !pParse->initFlag && (pParse->db->flags & SQLITE_InTrans)==0 ){ + if( !pParse->initFlag && (db->flags & SQLITE_InTrans)==0 ){ Vdbe *v = sqliteGetVdbe(pParse); if( v ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); @@ -442,6 +444,7 @@ void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){ void sqliteEndTable(Parse *pParse, Token *pEnd){ Table *p; int h; + sqlite *db = pParse->db; if( pEnd==0 || pParse->nErr || sqlite_malloc_failed ) return; p = pParse->pNewTable; @@ -451,10 +454,10 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){ */ if( pParse->explain==0 ){ h = sqliteHashNoCase(p->zName, 0) % N_HASH; - p->pHash = pParse->db->apTblHash[h]; - pParse->db->apTblHash[h] = p; + p->pHash = db->apTblHash[h]; + db->apTblHash[h] = p; pParse->pNewTable = 0; - pParse->db->nTable++; + db->nTable++; db->flags |= SQLITE_InternChanges; } @@ -484,7 +487,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){ 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 ){ + if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } @@ -515,7 +518,6 @@ Table *sqliteTableFromToken(Parse *pParse, Token *pTok){ */ void sqliteDropTable(Parse *pParse, Token *pName){ Table *pTable; - int h; Vdbe *v; int base; @@ -569,7 +571,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){ */ if( !pParse->explain ){ pTable->isDelete = 1; - db->flags |= SQLITE_InternChanges; + pParse->db->flags |= SQLITE_InternChanges; } } @@ -595,6 +597,7 @@ void sqliteCreateIndex( char *zName = 0; int i, j, h; Token nullId; /* Fake token for an empty ID list */ + sqlite *db = pParse->db; if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; @@ -625,13 +628,13 @@ void sqliteCreateIndex( sqliteSetString(&zName, pTab->zName, "__primary_key", 0); } if( zName==0 ) goto exit_create_index; - if( sqliteFindIndex(pParse->db, zName) ){ + if( sqliteFindIndex(db, zName) ){ sqliteSetString(&pParse->zErrMsg, "index ", zName, " already exists", 0); pParse->nErr++; goto exit_create_index; } - if( sqliteFindTable(pParse->db, zName) ){ + if( sqliteFindTable(db, zName) ){ sqliteSetString(&pParse->zErrMsg, "there is already a table named ", zName, 0); pParse->nErr++; @@ -684,8 +687,8 @@ void sqliteCreateIndex( */ if( pParse->explain==0 ){ h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH; - pIndex->pHash = pParse->db->apIdxHash[h]; - pParse->db->apIdxHash[h] = pIndex; + pIndex->pHash = db->apIdxHash[h]; + db->apIdxHash[h] = pIndex; pIndex->pNext = pTab->pIndex; pTab->pIndex = pIndex; db->flags |= SQLITE_InternChanges; @@ -721,7 +724,7 @@ void sqliteCreateIndex( v = sqliteGetVdbe(pParse); if( v==0 ) goto exit_create_index; - if( pTable!=0 && (pParse->db->flags & SQLITE_InTrans)==0 ){ + if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0); @@ -738,7 +741,7 @@ void sqliteCreateIndex( lbl1 = sqliteVdbeMakeLabel(v); lbl2 = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1); - sqliteVdbeAddOp(v, OP_GetRecno, 0, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Recno, 0, 0, 0, 0); for(i=0; inColumn; i++){ sqliteVdbeAddOp(v, OP_Column, 0, pIndex->aiColumn[i], 0, 0); } @@ -748,7 +751,7 @@ void sqliteCreateIndex( 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 ){ + if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } @@ -773,11 +776,12 @@ void sqliteDropIndex(Parse *pParse, Token *pName){ Index *pIndex; char *zName; Vdbe *v; + sqlite *db = pParse->db; if( pParse->nErr || sqlite_malloc_failed ) return; zName = sqliteTableNameFromToken(pName); if( zName==0 ) return; - pIndex = sqliteFindIndex(pParse->db, zName); + pIndex = sqliteFindIndex(db, zName); sqliteFree(zName); if( pIndex==0 ){ sqliteSetNString(&pParse->zErrMsg, "no such index: ", 0, @@ -796,19 +800,19 @@ void sqliteDropIndex(Parse *pParse, Token *pName){ { OP_Dup, 0, 0, 0}, { OP_Column, 0, 1, 0}, { OP_Ne, 0, ADDR(2), 0}, - { OP_Key, 0, 0, 0}, + { OP_Recno, 0, 0, 0}, { OP_Delete, 0, 0, 0}, { OP_Destroy, 0, 0, 0}, /* 8 */ { OP_Close, 0, 0, 0}, }; int base; - if( (pParse->db->flags & SQLITE_InTrans)==0 ){ + if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); sqliteVdbeChangeP1(v, base+8, pIndex->tnum); - if( (pParse->db->flags & SQLITE_InTrans)==0 ){ + if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } @@ -952,10 +956,11 @@ void sqliteCopy( Vdbe *v; int addr, end; Index *pIdx; + sqlite *db = pParse->db; zTab = sqliteTableNameFromToken(pTableName); if( sqlite_malloc_failed || zTab==0 ) goto copy_cleanup; - pTab = sqliteFindTable(pParse->db, zTab); + pTab = sqliteFindTable(db, zTab); sqliteFree(zTab); if( pTab==0 ){ sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, @@ -971,7 +976,7 @@ void sqliteCopy( } v = sqliteGetVdbe(pParse); if( v ){ - if( (pParse->db->flags & SQLITE_InTrans)==0 ){ + if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0); @@ -1010,7 +1015,7 @@ void sqliteCopy( } sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, end); - if( (pParse->db->flags & SQLITE_InTrans)==0 ){ + if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } @@ -1027,6 +1032,7 @@ copy_cleanup: void sqliteVacuum(Parse *pParse, Token *pTableName){ char *zName; Vdbe *v; + sqlite *db = pParse->db; if( pParse->nErr || sqlite_malloc_failed ) return; if( pTableName ){ @@ -1034,15 +1040,15 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ }else{ zName = 0; } - if( zName && sqliteFindIndex(pParse->db, zName)==0 - && sqliteFindTable(pParse->db, zName)==0 ){ + if( zName && sqliteFindIndex(db, zName)==0 + && sqliteFindTable(db, zName)==0 ){ sqliteSetString(&pParse->zErrMsg, "no such table or index: ", zName, 0); pParse->nErr++; goto vacuum_cleanup; } v = sqliteGetVdbe(pParse); if( v==0 ) goto vacuum_cleanup; - if( (pParse->db->flags & SQLITE_InTrans)==0 ){ + if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } if( zName ){ @@ -1052,7 +1058,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ Table *pTab; Index *pIdx; for(h=0; hdb->apTblHash[h]; pTab; pTab=pTab->pHash){ + for(pTab=db->apTblHash[h]; pTab; pTab=pTab->pHash){ sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, pTab->zName, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, pIdx->zName, 0); @@ -1060,7 +1066,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ } } } - if( (pParse->db->flags & SQLITE_InTrans)==0 ){ + if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } @@ -1073,7 +1079,6 @@ vacuum_cleanup: ** Begin a transaction */ void sqliteBeginTransaction(Parse *pParse){ - int rc; sqlite *db; Vdbe *v; @@ -1091,7 +1096,6 @@ void sqliteBeginTransaction(Parse *pParse){ ** Commit a transaction */ void sqliteCommitTransaction(Parse *pParse){ - int rc; sqlite *db; Vdbe *v; @@ -1109,7 +1113,6 @@ void sqliteCommitTransaction(Parse *pParse){ ** Rollback a transaction */ void sqliteRollbackTransaction(Parse *pParse){ - int rc; sqlite *db; Vdbe *v; diff --git a/src/dbbe.c b/src/dbbe.c deleted file mode 100644 index 469efc82a6..0000000000 --- a/src/dbbe.c +++ /dev/null @@ -1,124 +0,0 @@ -/* -** Copyright (c) 1999, 2000 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 GDBM as the database backend. It should be -** relatively simple to convert to a different database such -** as NDBM, SDBM, or BerkeleyDB. -** -** $Id: dbbe.c,v 1.28 2001/04/28 16:52:41 drh Exp $ -*/ -#include "sqliteInt.h" -#include - -/* -** This routine opens a new database. It looks at the first -** few characters of the database name to try to determine what -** kind of database to open. If the first characters are "gdbm:", -** then it uses the GDBM driver. If the first few characters are -** "memory:" then it uses the in-memory driver. If there is no -** match, the default to the GDBM driver. -** -** 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 *sqliteDbbeOpen( - 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 */ -){ - extern Dbbe *sqliteMemOpen(const char*,int,int,char**); -#ifndef DISABLE_GDBM - extern Dbbe *sqliteGdbmOpen(const char*,int,int,char**); - if( strncmp(zName, "gdbm:", 5)==0 ){ - return sqliteGdbmOpen(&zName[5], writeFlag, createFlag, pzErrMsg); - } -#endif - if( strncmp(zName, "memory:", 7)==0 ){ - return sqliteMemOpen(&zName[7], writeFlag, createFlag, pzErrMsg); - } -#ifndef DISABLE_GDBM - return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg); -#else - return sqliteMemOpen(zName, writeFlag, createFlag, pzErrMsg); -#endif -} - -#if 0 /* NOT USED */ -/* -** Translate the name of an SQL table (or index) into the name -** of a file that holds the key/data pairs for that table or -** index. Space to hold the filename is obtained from -** sqliteMalloc() and must be freed by the calling function. -** -** zDir is the name of the directory in which the file should -** be located. zSuffix is the filename extension to use for -** the file. -*/ -char *sqliteDbbeNameToFile( - const char *zDir, /* Directory containing the file */ - const char *zTable, /* Name of the SQL table that the file contains */ - const char *zSuffix /* Suffix for the file. Includes the "." */ -){ - char *zFile = 0; - int i, k, c; - int nChar = 0; - - for(i=0; (c = zTable[i])!=0; i++){ - if( !isalnum(c) && c!='_' ){ - nChar += 3; - }else{ - nChar ++; - } - } - nChar += strlen(zDir) + strlen(zSuffix) + 2; - zFile = sqliteMalloc( nChar ); - if( zFile==0 ) return 0; - for(i=0; (c = zDir[i])!=0; i++){ - zFile[i] = c; - } - zFile[i++] = '/'; - for(k=0; (c = zTable[k])!=0; k++){ - if( isupper(c) ){ - zFile[i++] = tolower(c); - }else if( isalnum(c) || c=='_' ){ - zFile[i++] = c; - }else{ - zFile[i++] = '~'; - zFile[i++] = "0123456789abcdef"[c & 0xf]; - zFile[i++] = "0123456789abcdef"[(c>>8)&0xf]; - } - } - for(k=0; (c = zSuffix[k])!=0; k++){ - zFile[i++] = c; - } - zFile[i] = 0; - return zFile; -} -#endif /* NOT USED */ diff --git a/src/dbbe.h b/src/dbbe.h deleted file mode 100644 index 1ab99a86bb..0000000000 --- a/src/dbbe.h +++ /dev/null @@ -1,197 +0,0 @@ -/* -** Copyright (c) 1999, 2000 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 defines the interface to the database backend (Dbbe). -** -** The database backend is designed to be as general as possible -** so that it can easily be replaced by a different backend. -** This library was originally designed to support the following -** backends: GDBM, NDBM, SDBM, Berkeley DB. -** -** $Id: dbbe.h,v 1.14 2001/08/19 18:19:46 drh Exp $ -*/ -#ifndef _SQLITE_DBBE_H_ -#define _SQLITE_DBBE_H_ -#include - -/* -** The database backend supports two opaque structures. A Dbbe is -** a context for the entire set of tables forming a complete -** database. A DbbeCursor is a pointer into a single single table. -** -** Note that at this level, the term "table" can mean either an -** SQL table or an SQL index. In this module, a table stores a -** single arbitrary-length key and corresponding arbitrary-length -** data. The differences between tables and indices, and the -** segregation of data into various fields or columns is handled -** by software at higher layers. -** -** The DbbeCursor structure holds some state information, such as -** the key and data from the last retrieval. For this reason, -** the backend must allow the creation of multiple independent -** DbbeCursor structures for each table in the database. -*/ -typedef struct Dbbe Dbbe; -typedef struct DbbeCursor DbbeCursor; -typedef struct DbbeMethods DbbeMethods; - -/* -** Open a complete database. -** -** If the database name begins with "gdbm:" the GDBM driver is used. -** If the name begins with "memory:" the in-memory driver is used. -** The default driver is GDBM. -*/ -Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr); - -/* -** Each of the various SQLite backends defines a set of methods for -** accessing the database. Pointers to the methods are contained in -** an instance of the following structure. A pointer to a static instance -** of this structure is assigned to the Dbbe structure that sqlileDbbeOpen -** returns. -*/ -struct DbbeMethods { - /* Close the whole database. */ - void (*Close)(Dbbe*); - - /* Open a cursor into a particular table of a previously opened database. - ** Create the table if it doesn't already exist and writeable!=0. zName - ** is the base name of the table to be opened. If the database is - ** implement as one file per table, then this routine will add an - ** appropriate path and extension to the table name to locate the - ** actual file. - ** - ** The intKeyOnly parameter is TRUE if this table will only be accessed - ** using integer keys. This parameter allows the database backend to - ** use a faster algorithm for the special case of integer keys, if it - ** wants to. - ** - ** If zName is 0 or "", then a temporary table is created that - ** will be deleted when closed. - */ - int (*OpenCursor)(Dbbe*, const char *zName, int writeable, - int intKeyOnly, DbbeCursor**); - - /* Delete a table from the database */ - void (*DropTable)(Dbbe*, const char *zTableName); - - /* Reorganize a table to speed access or reduce its disk usage */ - int (*ReorganizeTable)(Dbbe*, const char *zTableName); - - /* Close a cursor */ - void (*CloseCursor)(DbbeCursor*); - - /* Fetch an entry from a table with the given key. Return 1 if - ** successful and 0 if no such entry exists. - */ - int (*Fetch)(DbbeCursor*, int nKey, char *pKey); - - /* Return 1 if the given key is already in the table. Return 0 - ** if it is not. - */ - int (*Test)(DbbeCursor*, int nKey, char *pKey); - - /* Retrieve the key or data used for the last fetch. Only size - ** bytes are read beginning with the offset-th byte. The return - ** value is the actual number of bytes read. - */ - int (*CopyKey)(DbbeCursor*, int offset, int size, char *zBuf); - int (*CopyData)(DbbeCursor*, int offset, int size, char *zBuf); - - /* Retrieve the key or data. The result is ephemeral. In other words, - ** the result is stored in a buffer that might be overwritten on the next - ** call to any DBBE routine. If the results are needed for longer than - ** that, you must make a copy. - */ - char *(*ReadKey)(DbbeCursor*, int offset); - char *(*ReadData)(DbbeCursor*, int offset); - - /* Return the length of the most recently fetched key or data. */ - int (*KeyLength)(DbbeCursor*); - int (*DataLength)(DbbeCursor*); - - /* Retrieve the next entry in the table. The first key is retrieved - ** the first time this routine is called, or after a call to - ** Dbbe.Rewind(). The return value is 1 if there is another - ** entry, or 0 if there are no more entries. */ - int (*NextKey)(DbbeCursor*); - - /* Make it so that the next call to Dbbe.NextKey() returns - ** the first entry of the table. */ - int (*Rewind)(DbbeCursor*); - - /* Get a new integer key for this table. */ - int (*New)(DbbeCursor*); - - /* Write an entry into a table. If another entry already exists with - ** the same key, the old entry is discarded first. - */ - int (*Put)(DbbeCursor*, int nKey, char *pKey, int nData, char *pData); - - /* Remove an entry from the table */ - int (*Delete)(DbbeCursor*, int nKey, char *pKey); - - /* Begin a transaction. */ - int (*BeginTransaction)(Dbbe*); - - /* Commit a transaction. */ - int (*Commit)(Dbbe*); - - /* Rollback a transaction. */ - int (*Rollback)(Dbbe*); - - /* Begin searching an index where the key is given. */ - int (*BeginIndex)(DbbeCursor*, int nKey, char *pKey); - - /* Return the integer key for the next index entry, or return 0 if - ** there are no more index entries. */ - int (*NextIndex)(DbbeCursor*); - - /* Add a new index entry to the file. The key and record number are - ** given. */ - int (*PutIndex)(DbbeCursor*, int nKey, char *pKey, int recno); - - /* Delete an index entry from the file. The key and record number are - ** given. */ - int (*DeleteIndex)(DbbeCursor*, int nKey, char *pKey, int recno); -}; - -/* -** This is the structure returned by sqliteDbbeOpen(). It contains -** information common to all the different backend drivers. -** -** The information in this structure (with the exception the method -** pointers in the Dbbe.x field) is intended to be visible to -** the backend drivers only. Users should not access or modify -** this structure in any way other than the read the method pointers -** in Dbbe.x. -*/ -struct Dbbe { - struct DbbeMethods *x; /* Backend-specific methods for database access */ - /* There used to be other information here, but it has since - ** been removed. We'll keep the same design, though, in case we - ** ever want to add some new fields in the future. */ -}; - -#endif /* defined(_SQLITE_DBBE_H_) */ diff --git a/src/dbbebtree.c b/src/dbbebtree.c deleted file mode 100644 index 123b62ee48..0000000000 --- a/src/dbbebtree.c +++ /dev/null @@ -1,676 +0,0 @@ -/* -** 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; ipCur==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 */ diff --git a/src/dbbegdbm.c b/src/dbbegdbm.c deleted file mode 100644 index b1ee44cc99..0000000000 --- a/src/dbbegdbm.c +++ /dev/null @@ -1,792 +0,0 @@ -/* -** Copyright (c) 2000 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 GDBM as the database backend. It should be -** relatively simple to convert to a different database such -** as NDBM, SDBM, or BerkeleyDB. -** -** $Id: dbbegdbm.c,v 1.9 2001/08/19 18:19:46 drh Exp $ -*/ -#ifndef DISABLE_GDBM -#include "sqliteInt.h" -#include -#include -#include -#include -#include - -/* -** Information about each open disk file is an instance of this -** structure. There will only be one such structure for each -** disk file. If the VDBE opens the same file twice (as will happen -** for a self-join, for example) then two DbbeCursor structures are -** created but there is only a single BeFile structure with an -** nRef of 2. -** -** This backend uses a separate disk file for each database table -** and index. -*/ -typedef struct BeFile BeFile; -struct BeFile { - char *zName; /* Name of the file */ - GDBM_FILE dbf; /* The file itself */ - int nRef; /* Number of references */ - int delOnClose; /* Delete when closing */ - int writeable; /* Opened for writing */ - BeFile *pNext, *pPrev; /* Next and previous on list of open files */ -}; - -/* -** The following structure contains all information used by GDBM -** 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 */ - BeFile *pOpen; /* List of open files */ - char *zDir; /* Directory hold the database */ -}; - -/* -** An cursor into a database file is an instance of the following structure. -** There can only be a single BeFile structure for each disk file, but -** there can be multiple DbbeCursor structures. Each DbbeCursor represents -** a cursor pointing to a particular part of the open BeFile. The -** BeFile.nRef field hold a count of the number of DbbeCursor structures -** associated with the same disk file. -*/ -struct DbbeCursor { - Dbbex *pBe; /* The database of which this record is a part */ - BeFile *pFile; /* The database file for this table */ - datum key; /* Most recently used key */ - datum data; /* Most recent data */ - int nextIndex; /* Next index entry to search */ - int needRewind; /* Next key should be the first */ - int readPending; /* The fetch hasn't actually been done yet */ -}; - -/* -** The "mkdir()" function only takes one argument under Windows. -*/ -#if OS_WIN -# define mkdir(A,B) mkdir(A) -#endif - -/* -** Forward declaration -*/ -static void sqliteGdbmCloseCursor(DbbeCursor *pCursr); - -/* -** Completely shutdown the given database. Close all files. Free all memory. -*/ -static void sqliteGdbmClose(Dbbe *pDbbe){ - Dbbex *pBe = (Dbbex*)pDbbe; - BeFile *pFile, *pNext; - for(pFile=pBe->pOpen; pFile; pFile=pNext){ - pNext = pFile->pNext; - gdbm_close(pFile->dbf); - memset(pFile, 0, sizeof(*pFile)); - sqliteFree(pFile); - } - memset(pBe, 0, sizeof(*pBe)); - sqliteFree(pBe); -} - -/* -** Translate the name of an SQL table (or index) into the name -** of a file that holds the key/data pairs for that table or -** index. Space to hold the filename is obtained from -** sqliteMalloc() and must be freed by the calling function. -*/ -static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){ - char *zFile = 0; - int i; - sqliteSetString(&zFile, pBe->zDir, "/", zTable, ".tbl", 0); - if( zFile==0 ) return 0; - for(i=strlen(pBe->zDir)+1; zFile[i]; i++){ - int c = zFile[i]; - if( isupper(c) ){ - zFile[i] = tolower(c); - }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){ - zFile[i] = '+'; - } - } - return zFile; -} - -/* -** 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 zTable is 0 or "", then a temporary database file is created and -** a cursor to that temporary file is opened. The temporary file -** will be deleted from the disk when it is closed. -*/ -static int sqliteGdbmOpenCursor( - 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 */ - BeFile *pFile; /* The underlying data file for this table */ - 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; - - if( pBe->inTrans ) writeable = 1; - *ppCursr = 0; - pCursr = sqliteMalloc( sizeof(*pCursr) ); - if( pCursr==0 ) return SQLITE_NOMEM; - if( zTable ){ - zFile = sqliteFileOfTable(pBe, zTable); - if( zFile==0 ) return SQLITE_NOMEM; - for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){ - if( strcmp(pFile->zName,zFile)==0 ) break; - } - }else{ - pFile = 0; - zFile = 0; - } - if( pFile==0 ){ - if( writeable ){ - rw_mask = GDBM_WRCREAT | GDBM_FAST; - mode = 0640; - }else{ - rw_mask = GDBM_READER; - mode = 0640; - } - pFile = sqliteMalloc( sizeof(*pFile) ); - if( pFile==0 ){ - sqliteFree(zFile); - return SQLITE_NOMEM; - } - if( zFile ){ - if( !writeable || pBe->write ){ - pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0); - }else{ - pFile->dbf = 0; - } - }else{ - int limit; - char zRandom[50]; - zFile = 0; - limit = 5; - do { - sqliteRandomName(zRandom, "_temp_table_"); - sqliteFree(zFile); - zFile = sqliteFileOfTable(pBe, zRandom); - pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0); - }while( pFile->dbf==0 && limit-- >= 0); - pFile->delOnClose = 1; - } - pFile->writeable = writeable; - pFile->zName = zFile; - pFile->nRef = 1 + pBe->inTrans; - pFile->pPrev = 0; - if( pBe->pOpen ){ - pBe->pOpen->pPrev = pFile; - } - pFile->pNext = pBe->pOpen; - pBe->pOpen = pFile; - if( pFile->dbf==0 ){ - if( !writeable && access(zFile,0) ){ - /* Trying to read a non-existant file. This is OK. All the - ** reads will return empty, which is what we want. */ - rc = SQLITE_OK; - }else if( pBe->write==0 ){ - rc = SQLITE_READONLY; - }else if( access(zFile,W_OK|R_OK) ){ - rc = SQLITE_PERM; - }else{ - rc = SQLITE_BUSY; - } - } - }else{ - sqliteFree(zFile); - pFile->nRef++; - if( writeable && !pFile->writeable ){ - rc = SQLITE_READONLY; - } - } - pCursr->pBe = pBe; - pCursr->pFile = pFile; - pCursr->readPending = 0; - pCursr->needRewind = 1; - if( rc!=SQLITE_OK ){ - sqliteGdbmCloseCursor(pCursr); - *ppCursr = 0; - }else{ - *ppCursr = pCursr; - } - return rc; -} - -/* -** Drop a table from the database. The file on the disk that corresponds -** to this table is deleted. -*/ -static void sqliteGdbmDropTable(Dbbe *pBe, const char *zTable){ - char *zFile; /* Name of the table file */ - - zFile = sqliteFileOfTable((Dbbex*)pBe, zTable); - unlink(zFile); - sqliteFree(zFile); -} - -/* -** Unlink a file pointer -*/ -static void sqliteUnlinkFile(Dbbex *pBe, BeFile *pFile){ - if( pFile->dbf!=NULL ){ - gdbm_close(pFile->dbf); - } - if( pFile->pPrev ){ - pFile->pPrev->pNext = pFile->pNext; - }else{ - pBe->pOpen = pFile->pNext; - } - if( pFile->pNext ){ - pFile->pNext->pPrev = pFile->pPrev; - } - if( pFile->delOnClose ){ - unlink(pFile->zName); - } - sqliteFree(pFile->zName); - memset(pFile, 0, sizeof(*pFile)); - sqliteFree(pFile); -} - -/* -** Close a cursor previously opened by sqliteGdbmOpenCursor(). -** -** There can be multiple cursors pointing to the same open file. -** The underlying file is not closed until all cursors have been -** closed. This routine decrements the BeFile.nref field of the -** underlying file and closes the file when nref reaches 0. -*/ -static void sqliteGdbmCloseCursor(DbbeCursor *pCursr){ - BeFile *pFile; - Dbbex *pBe; - if( pCursr==0 ) return; - pFile = pCursr->pFile; - pBe = pCursr->pBe; - pFile->nRef--; - if( pFile->dbf!=NULL ){ - gdbm_sync(pFile->dbf); - } - if( pFile->nRef<=0 ){ - sqliteUnlinkFile(pBe, pFile); - } - if( pCursr->key.dptr ) free(pCursr->key.dptr); - if( pCursr->data.dptr ) free(pCursr->data.dptr); - memset(pCursr, 0, sizeof(*pCursr)); - sqliteFree(pCursr); -} - -/* -** Reorganize a table to reduce search times and disk usage. -*/ -static int sqliteGdbmReorganizeTable(Dbbe *pBe, const char *zTable){ - DbbeCursor *pCursr; - int rc; - - rc = sqliteGdbmOpenCursor(pBe, zTable, 1, 0, &pCursr); - if( rc!=SQLITE_OK ){ - return rc; - } - if( pCursr && pCursr->pFile && pCursr->pFile->dbf ){ - gdbm_reorganize(pCursr->pFile->dbf); - } - if( pCursr ){ - sqliteGdbmCloseCursor(pCursr); - } - return SQLITE_OK; -} - -/* -** Clear the given datum -*/ -static void datumClear(datum *p){ - if( p->dptr ) free(p->dptr); - p->dptr = 0; - p->dsize = 0; -} - -/* -** Fetch a single record from an open cursor. Return 1 on success -** and 0 on failure. -*/ -static int sqliteGdbmFetch(DbbeCursor *pCursr, int nKey, char *pKey){ - datum key; - key.dsize = nKey; - key.dptr = pKey; - datumClear(&pCursr->key); - datumClear(&pCursr->data); - if( pCursr->pFile && pCursr->pFile->dbf ){ - pCursr->data = gdbm_fetch(pCursr->pFile->dbf, key); - } - return pCursr->data.dptr!=0; -} - -/* -** Return 1 if the given key is already in the table. Return 0 -** if it is not. -*/ -static int sqliteGdbmTest(DbbeCursor *pCursr, int nKey, char *pKey){ - datum key; - int result = 0; - key.dsize = nKey; - key.dptr = pKey; - if( pCursr->pFile && pCursr->pFile->dbf ){ - result = gdbm_exists(pCursr->pFile->dbf, key); - } - return result; -} - -/* -** Copy bytes from the current key or data into a buffer supplied by -** the calling function. Return the number of bytes copied. -*/ -static -int sqliteGdbmCopyKey(DbbeCursor *pCursr, int offset, int size, char *zBuf){ - int n; - if( offset>=pCursr->key.dsize ) return 0; - if( offset+size>pCursr->key.dsize ){ - n = pCursr->key.dsize - offset; - }else{ - n = size; - } - memcpy(zBuf, &pCursr->key.dptr[offset], n); - return n; -} -static -int sqliteGdbmCopyData(DbbeCursor *pCursr, int offset, int size, char *zBuf){ - int n; - if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){ - pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key); - pCursr->readPending = 0; - } - if( offset>=pCursr->data.dsize ) return 0; - if( offset+size>pCursr->data.dsize ){ - n = pCursr->data.dsize - offset; - }else{ - n = size; - } - memcpy(zBuf, &pCursr->data.dptr[offset], n); - return n; -} - -/* -** Return a pointer to bytes from the key or data. The data returned -** is ephemeral. -*/ -static char *sqliteGdbmReadKey(DbbeCursor *pCursr, int offset){ - if( offset<0 || offset>=pCursr->key.dsize ) return ""; - return &pCursr->key.dptr[offset]; -} -static char *sqliteGdbmReadData(DbbeCursor *pCursr, int offset){ - if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){ - pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key); - pCursr->readPending = 0; - } - if( offset<0 || offset>=pCursr->data.dsize ) return ""; - return &pCursr->data.dptr[offset]; -} - -/* -** Return the total number of bytes in either data or key. -*/ -static int sqliteGdbmKeyLength(DbbeCursor *pCursr){ - return pCursr->key.dsize; -} -static int sqliteGdbmDataLength(DbbeCursor *pCursr){ - if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){ - pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key); - pCursr->readPending = 0; - } - return pCursr->data.dsize; -} - -/* -** Make is so that the next call to sqliteNextKey() finds the first -** key of the table. -*/ -static int sqliteGdbmRewind(DbbeCursor *pCursr){ - pCursr->needRewind = 1; - return SQLITE_OK; -} - -/* -** Read the next key from the table. Return 1 on success. Return -** 0 if there are no more keys. -*/ -static int sqliteGdbmNextKey(DbbeCursor *pCursr){ - datum nextkey; - int rc; - if( pCursr==0 || pCursr->pFile==0 || pCursr->pFile->dbf==0 ){ - pCursr->readPending = 0; - return 0; - } - if( pCursr->needRewind ){ - nextkey = gdbm_firstkey(pCursr->pFile->dbf); - pCursr->needRewind = 0; - }else{ - nextkey = gdbm_nextkey(pCursr->pFile->dbf, pCursr->key); - } - datumClear(&pCursr->key); - datumClear(&pCursr->data); - pCursr->key = nextkey; - if( pCursr->key.dptr ){ - pCursr->readPending = 1; - rc = 1; - }else{ - pCursr->needRewind = 1; - pCursr->readPending = 0; - rc = 0; - } - return rc; -} - -/* -** Get a new integer key. -*/ -static int sqliteGdbmNew(DbbeCursor *pCursr){ - int iKey; - datum key; - int go = 1; - - if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1; - while( go ){ - iKey = sqliteRandomInteger() & 0x7fffffff; - if( iKey==0 ) continue; - key.dptr = (char*)&iKey; - key.dsize = 4; - go = gdbm_exists(pCursr->pFile->dbf, key); - } - return iKey; -} - -/* -** Write an entry into the table. Overwrite any prior entry with the -** same key. -*/ -static int sqliteGdbmPut( - 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 */ -){ - datum data, key; - int rc; - if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR; - data.dsize = nData; - data.dptr = pData; - key.dsize = nKey; - key.dptr = pKey; - rc = gdbm_store(pCursr->pFile->dbf, key, data, GDBM_REPLACE); - if( rc ) rc = SQLITE_ERROR; - datumClear(&pCursr->key); - datumClear(&pCursr->data); - return rc; -} - -/* -** Remove an entry from a table, if the entry exists. -*/ -static int sqliteGdbmDelete(DbbeCursor *pCursr, int nKey, char *pKey){ - datum key; - int rc; - datumClear(&pCursr->key); - datumClear(&pCursr->data); - if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR; - key.dsize = nKey; - key.dptr = pKey; - rc = gdbm_delete(pCursr->pFile->dbf, key); - if( rc ) rc = SQLITE_ERROR; - return rc; -} - -/* -** Begin a transaction. -*/ -static int sqliteGdbmBeginTrans(Dbbe *pDbbe){ - Dbbex *pBe = (Dbbex*)pDbbe; - BeFile *pFile; - if( pBe->inTrans ) return SQLITE_OK; - for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){ - pFile->nRef++; - } - pBe->inTrans = 1; - return SQLITE_OK; -} - -/* -** End a transaction. -*/ -static int sqliteGdbmEndTrans(Dbbe *pDbbe){ - Dbbex *pBe = (Dbbex*)pDbbe; - BeFile *pFile, *pNext; - if( !pBe->inTrans ) return SQLITE_OK; - for(pFile=pBe->pOpen; pFile; pFile=pNext){ - pNext = pFile->pNext; - pFile->nRef--; - if( pFile->nRef<=0 ){ - sqliteUnlinkFile(pBe, pFile); - } - } - pBe->inTrans = 0; - return SQLITE_OK; -} - -/* -** Begin scanning an index for the given key. Return 1 on success and -** 0 on failure. -*/ -static int sqliteGdbmBeginIndex(DbbeCursor *pCursr, int nKey, char *pKey){ - if( !sqliteGdbmFetch(pCursr, nKey, pKey) ) return 0; - pCursr->nextIndex = 0; - return 1; -} - -/* -** 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 sqliteGdbmNextIndex(DbbeCursor *pCursr){ - int *aIdx; - int nIdx; - int k; - nIdx = pCursr->data.dsize/sizeof(int); - aIdx = (int*)pCursr->data.dptr; - if( nIdx>1 ){ - k = *(aIdx++); - if( k>nIdx-1 ) k = nIdx-1; - }else{ - k = nIdx; - } - while( pCursr->nextIndex < k ){ - int recno = aIdx[pCursr->nextIndex++]; - if( recno!=0 ) return recno; - } - pCursr->nextIndex = 0; - return 0; -} - -/* -** Write a new record number and key into an index table. Return a status -** code. -*/ -static int sqliteGdbmPutIndex(DbbeCursor *pCursr, int nKey, char *pKey, int N){ - int r = sqliteGdbmFetch(pCursr, nKey, pKey); - if( r==0 ){ - /* Create a new record for this index */ - sqliteGdbmPut(pCursr, nKey, pKey, sizeof(int), (char*)&N); - }else{ - /* Extend the existing record */ - int nIdx; - int *aIdx; - int k; - - nIdx = pCursr->data.dsize/sizeof(int); - if( nIdx==1 ){ - aIdx = sqliteMalloc( sizeof(int)*4 ); - if( aIdx==0 ) return SQLITE_NOMEM; - aIdx[0] = 2; - sqliteGdbmCopyData(pCursr, 0, sizeof(int), (char*)&aIdx[1]); - aIdx[2] = N; - sqliteGdbmPut(pCursr, nKey, pKey, sizeof(int)*4, (char*)aIdx); - sqliteFree(aIdx); - }else{ - aIdx = (int*)sqliteGdbmReadData(pCursr, 0); - k = aIdx[0]; - if( kdata.dsize/sizeof(int); - aIdx = (int*)sqliteGdbmReadData(pCursr, 0); - if( (nIdx==1 && aIdx[0]==N) || (aIdx[0]==1 && aIdx[1]==N) ){ - sqliteGdbmDelete(pCursr, nKey, pKey); - }else{ - k = aIdx[0]; - for(j=1; j<=k && aIdx[j]!=N; j++){} - if( j>k ) return SQLITE_OK; - aIdx[j] = aIdx[k]; - aIdx[k] = 0; - aIdx[0]--; - if( aIdx[0]*3 + 1 < nIdx ){ - nIdx /= 2; - } - sqliteGdbmPut(pCursr, nKey, pKey, sizeof(int)*nIdx, (char*)aIdx); - } - return SQLITE_OK; -} - -/* -** This variable contains pointers to all of the access methods -** used to implement the GDBM backend. -*/ -static struct DbbeMethods gdbmMethods = { - /* Close */ sqliteGdbmClose, - /* OpenCursor */ sqliteGdbmOpenCursor, - /* DropTable */ sqliteGdbmDropTable, - /* ReorganizeTable */ sqliteGdbmReorganizeTable, - /* CloseCursor */ sqliteGdbmCloseCursor, - /* Fetch */ sqliteGdbmFetch, - /* Test */ sqliteGdbmTest, - /* CopyKey */ sqliteGdbmCopyKey, - /* CopyData */ sqliteGdbmCopyData, - /* ReadKey */ sqliteGdbmReadKey, - /* ReadData */ sqliteGdbmReadData, - /* KeyLength */ sqliteGdbmKeyLength, - /* DataLength */ sqliteGdbmDataLength, - /* NextKey */ sqliteGdbmNextKey, - /* Rewind */ sqliteGdbmRewind, - /* New */ sqliteGdbmNew, - /* Put */ sqliteGdbmPut, - /* Delete */ sqliteGdbmDelete, - /* BeginTrans */ sqliteGdbmBeginTrans, - /* Commit */ sqliteGdbmEndTrans, - /* Rollback */ sqliteGdbmEndTrans, - /* BeginIndex */ sqliteGdbmBeginIndex, - /* NextIndex */ sqliteGdbmNextIndex, - /* PutIndex */ sqliteGdbmPutIndex, - /* DeleteIndex */ sqliteGdbmDeleteIndex, -}; - - -/* -** This routine opens a new database. For the GDBM driver -** implemented here, the database name is the name of the directory -** containing all the files 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 *sqliteGdbmOpen( - 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; - struct stat statbuf; - char *zMaster; - - if( !writeFlag ) createFlag = 0; - if( stat(zName, &statbuf)!=0 ){ - if( createFlag ) mkdir(zName, 0750); - if( stat(zName, &statbuf)!=0 ){ - sqliteSetString(pzErrMsg, createFlag ? - "can't find or create directory \"" : "can't find directory \"", - zName, "\"", 0); - return 0; - } - } - if( !S_ISDIR(statbuf.st_mode) ){ - sqliteSetString(pzErrMsg, "not a directory: \"", zName, "\"", 0); - return 0; - } - if( access(zName, writeFlag ? (X_OK|W_OK|R_OK) : (X_OK|R_OK)) ){ - sqliteSetString(pzErrMsg, "access permission denied", 0); - return 0; - } - zMaster = 0; - sqliteSetString(&zMaster, zName, "/" MASTER_NAME ".tbl", 0); - if( stat(zMaster, &statbuf)==0 - && access(zMaster, writeFlag ? (W_OK|R_OK) : R_OK)!=0 ){ - sqliteSetString(pzErrMsg, "access permission denied for ", zMaster, 0); - sqliteFree(zMaster); - return 0; - } - sqliteFree(zMaster); - pNew = sqliteMalloc(sizeof(Dbbex) + strlen(zName) + 1); - if( pNew==0 ){ - sqliteSetString(pzErrMsg, "out of memory", 0); - return 0; - } - pNew->dbbe.x = &gdbmMethods; - pNew->zDir = (char*)&pNew[1]; - strcpy(pNew->zDir, zName); - pNew->write = writeFlag; - pNew->pOpen = 0; - return &pNew->dbbe; -} -#endif /* DISABLE_GDBM */ diff --git a/src/dbbemem.c b/src/dbbemem.c deleted file mode 100644 index 95d7319605..0000000000 --- a/src/dbbemem.c +++ /dev/null @@ -1,894 +0,0 @@ -/* -** Copyright (c) 2000 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 an in-memory hash table as the database backend. -** Nothing is ever written to disk using this backend. All information -** is forgotten when the program exits. -** -** $Id: dbbemem.c,v 1.17 2001/08/20 00:33:58 drh Exp $ -*/ -#include "sqliteInt.h" -#include - - -typedef struct Array Array; -typedef struct ArrayElem ArrayElem; -typedef struct Datum Datum; - -/* A complete associative array is an instance of the following structure. -** The internals of this structure are intended to be opaque -- client -** code should not attempt to access or modify the fields of this structure -** directly. Change this structure only by using the routines below. -** However, many of the "procedures" and "functions" for modifying and -** accessing this structure are really macros, so we can't really make -** this structure opaque. -*/ -struct Array { - int count; /* Number of entries in the array */ - ArrayElem *first; /* The first element of the array */ - int htsize; /* Number of buckets in the hash table */ - struct _Array_ht { /* the hash table */ - int count; /* Number of entries with this hash */ - ArrayElem *chain; /* Pointer to first entry with this hash */ - } *ht; -}; - -/* -** An instance of the following structure stores a single key or -** data element. -*/ -struct Datum { - int n; - void *p; -}; - -/* Each element in the associative array is an instance of the following -** structure. All elements are stored on a single doubly-linked list. -** -** Again, this structure is intended to be opaque, but it can't really -** be opaque because it is used by macros. -*/ -struct ArrayElem { - ArrayElem *next, *prev; /* Next and previous elements in the array */ - Datum key, data; /* Key and data for this element */ -}; - -/* Some routines are so simple that they can be implemented as macros -** These are given first. */ - -/* Return the number of entries in the array */ -#define ArrayCount(X) ((X)->count) - -/* Return a pointer to the first element of the array */ -#define ArrayFirst(X) ((X)->first) - -/* Return a pointer to the next (or previous) element of the array */ -#define ArrayNext(X) ((X)->next) -#define ArrayPrev(X) ((X)->prev) - -/* Return TRUE if the element given is the last element in the array */ -#define ArrayIsLast(X) ((X)->next==0) -#define ArrayIsFirst(X) ((X)->prev==0) - -/* Return the data or key for an element of the array */ -#define ArrayData(X) ((X)->data.p) -#define ArrayDataSize(X) ((X)->data.n) -#define ArrayKey(X) ((X)->key.p) -#define ArrayKeySize(X) ((X)->key.n) - -/* Turn bulk memory into an associative array object by initializing the -** fields of the Array structure. -*/ -static void ArrayInit(Array *new){ - new->first = 0; - new->count = 0; - new->htsize = 0; - new->ht = 0; -} - -/* Remove all entries from an associative array. Reclaim all memory. -** This is the opposite of ArrayInit(). -*/ -static void ArrayClear(Array *array){ - ArrayElem *elem; /* For looping over all elements of the array */ - - elem = array->first; - array->first = 0; - array->count = 0; - if( array->ht ) sqliteFree(array->ht); - array->ht = 0; - array->htsize = 0; - while( elem ){ - ArrayElem *next_elem = elem->next; - sqliteFree(elem); - elem = next_elem; - } -} - -/* -** Generate a hash from an N-byte key -*/ -static int ArrayHash(Datum d){ - int h = 0; - while( d.n-- > 0 ){ - /* The funky case "*(char**)&d.p" is to work around a bug the - ** c89 compiler of HPUX. */ - h = (h<<9) ^ (h<<3) ^ h ^ *((*(char**)&d.p)++); - } - if( h<0 ) h = -h; - return h; -} - -/* Resize the hash table for a Array array -*/ -static void ArrayRehash(Array *array, int new_size){ - struct _Array_ht *new_ht; /* The new hash table */ - ArrayElem *elem, *next_elem; /* For looping over existing elements */ - int i; /* Loop counter */ - ArrayElem *x; /* Element being copied to new hash table */ - - new_ht = sqliteMalloc( new_size*sizeof(struct _Array_ht) ); - if( new_ht==0 ){ ArrayClear(array); return; } - if( array->ht ) sqliteFree(array->ht); - array->ht = new_ht; - array->htsize = new_size; - for(i=new_size-1; i>=0; i--){ - new_ht[i].count = 0; - new_ht[i].chain = 0; - } - for(elem=array->first, array->first=0; elem; elem = next_elem){ - int h = ArrayHash(elem->key) & (new_size-1); - next_elem = elem->next; - x = new_ht[h].chain; - if( x ){ - elem->next = x; - elem->prev = x->prev; - if( x->prev ) x->prev->next = elem; - else array->first = elem; - x->prev = elem; - }else{ - elem->next = array->first; - if( array->first ) array->first->prev = elem; - elem->prev = 0; - array->first = elem; - } - new_ht[h].chain = elem; - new_ht[h].count++; - } -} - -/* This function (for internal use only) locates an element in an -** array that matches the given key. The hash for this key has -** already been computed and is passed as the 3rd parameter. -*/ -static ArrayElem *ArrayFindElementGivenHash( - const Array *array, /* The array to be searched */ - const Datum key, /* The key we are searching for */ - int h /* The hash for this key. */ -){ - ArrayElem *elem; /* Used to loop thru the element list */ - int count; /* Number of elements left to test */ - - if( array->count ){ - elem = array->ht[h].chain; - count = array->ht[h].count; - while( count-- && elem ){ - if( elem->key.n==key.n && memcmp(elem->key.p,key.p,key.n)==0 ){ - return elem; - } - elem = elem->next; - } - } - return 0; -} - - -/* Attempt to locate an element of the associative array with a key -** that matches "key". Return the ArrayElement if found and NULL if -** if no match. -*/ -static ArrayElem *ArrayFindElement(const Array *array, Datum key){ - int h; /* A hash on key */ - if( array->count==0 ) return 0; - h = ArrayHash(key); - return ArrayFindElementGivenHash(array, key, h & (array->htsize-1)); -} - -/* Remove a single entry from the array given a pointer to that -** element and a hash on the element's key. -*/ -static void ArrayRemoveElementGivenHash( - Array *array, /* The array containing "elem" */ - ArrayElem* elem, /* The element to be removed from the array */ - int h /* Hash value for the element */ -){ - if( elem->prev ){ - elem->prev->next = elem->next; - }else{ - array->first = elem->next; - } - if( elem->next ){ - elem->next->prev = elem->prev; - } - if( array->ht[h].chain==elem ){ - array->ht[h].chain = elem->next; - } - array->ht[h].count--; - if( array->ht[h].count<=0 ){ - array->ht[h].chain = 0; - } - sqliteFree( elem ); - array->count--; -} - -/* Attempt to locate an element of the associative array with a key -** that matches "key". Return the data for this element if it is -** found, or NULL if no match is found. -*/ -static Datum ArrayFind(const Array *array, Datum key){ - int h; /* A hash on key */ - ArrayElem *elem; /* The element that matches key */ - static Datum nil = {0, 0}; - - if( array->count==0 ) return nil; - h = ArrayHash(key); - elem = ArrayFindElementGivenHash(array, key, h & (array->htsize-1)); - return elem ? elem->data : nil; -} - -/* Insert an element into the array. The key will be "key" and -** the data will be "data". -** -** If no array element exists with a matching key, then a new -** array element is created. The key is copied into the new element. -** But only a pointer to the data is stored. NULL is returned. -** -** If another element already exists with the same key, then the -** new data replaces the old data and the old data is returned. -** The key is not copied in this instance. -** -** If the "data" parameter to this function is NULL, then the -** element corresponding to "key" is removed from the array. -*/ -static Datum ArrayInsert(Array *array, Datum key, Datum data){ - int hraw; /* Raw hash value of the key */ - int h; /* the hash of the key modulo hash table size */ - ArrayElem *elem; /* Used to loop thru the element list */ - ArrayElem *new_elem; /* New element added to the array */ - Datum rv; /* Return value */ - static Datum nil = {0, 0}; - - hraw = ArrayHash(key); - h = hraw & (array->htsize-1); - elem = ArrayFindElementGivenHash(array,key,h); - if( elem ){ - Datum old_data = elem->data; - if( data.p==0 ){ - ArrayRemoveElementGivenHash(array,elem,h); - }else{ - elem->data = data; - } - return old_data; - } - if( data.p==0 ) return nil; - new_elem = (ArrayElem*)sqliteMalloc( sizeof(ArrayElem) + key.n ); - if( new_elem==0 ) return nil; - new_elem->key.n = key.n; - new_elem->key.p = (void*)&new_elem[1]; - memcpy(new_elem->key.p, key.p, key.n); - array->count++; - if( array->htsize==0 ) ArrayRehash(array,4); - if( array->htsize==0 ) return nil; - if( array->count > array->htsize ){ - ArrayRehash(array,array->htsize*2); - if( array->htsize==0 ){ - sqliteFree(new_elem); - return nil; - } - } - h = hraw & (array->htsize-1); - elem = array->ht[h].chain; - if( elem ){ - new_elem->next = elem; - new_elem->prev = elem->prev; - if( elem->prev ){ elem->prev->next = new_elem; } - else { array->first = new_elem; } - elem->prev = new_elem; - }else{ - new_elem->next = array->first; - new_elem->prev = 0; - if( array->first ){ array->first->prev = new_elem; } - array->first = new_elem; - } - array->ht[h].count++; - array->ht[h].chain = new_elem; - new_elem->data = data; - rv.p = 0; - rv.n = 0; - return rv; -} - -/* -** Information about each open database table is an instance of this -** structure. There will only be one such structure for each -** table. If the VDBE opens the same table twice (as will happen -** for a self-join, for example) then two DbbeCursor structures are -** created but there is only a single MTable structure. -*/ -typedef struct MTable MTable; -struct MTable { - char *zName; /* Name of the table */ - int delOnClose; /* Delete when closing */ - int intKeyOnly; /* Use only integer keys on this table */ - Array data; /* The data in this stable */ -}; - -/* -** The following structure contains all information used by GDBM -** database driver. This is a subclass of the Dbbe structure. -*/ -typedef struct Dbbex Dbbex; -struct Dbbex { - Dbbe dbbe; /* The base class */ - Array tables; /* All tables of the database */ -}; - -/* -** An cursor into a database file is an instance of the following structure. -** There can only be a single MTable structure for each disk file, but -** there can be multiple DbbeCursor structures. Each DbbeCursor represents -** a cursor pointing to a particular part of the open MTable. The -** MTable.nRef field hold a count of the number of DbbeCursor structures -** associated with the same disk file. -*/ -struct DbbeCursor { - Dbbex *pBe; /* The database of which this record is a part */ - MTable *pTble; /* The database file for this table */ - ArrayElem *elem; /* Most recently accessed record */ - int needRewind; /* Next key should be the first */ - int nextIndex; /* Next recno in an index entry */ -}; - -/* -** Forward declaration -*/ -static void sqliteMemCloseCursor(DbbeCursor *pCursr); - -/* -** Erase all the memory of an MTable -*/ -static void deleteMTable(MTable *p){ - ArrayElem *i; - for(i=ArrayFirst(&p->data); i; i=ArrayNext(i)){ - void *data = ArrayData(i); - sqliteFree(data); - } - ArrayClear(&p->data); - sqliteFree(p->zName); - sqliteFree(p); -} - -/* -** Completely shutdown the given database. Close all files. Free all memory. -*/ -static void sqliteMemClose(Dbbe *pDbbe){ - Dbbex *pBe = (Dbbex*)pDbbe; - MTable *pTble; - ArrayElem *j; - for(j=ArrayFirst(&pBe->tables); j; j=ArrayNext(j)){ - pTble = ArrayData(j); - deleteMTable(pTble); - } - ArrayClear(&pBe->tables); - memset(pBe, 0, sizeof(*pBe)); - sqliteFree(pBe); -} - -/* -** Translate the name of an SQL table (or index) into its -** canonical name. -** -** Space to hold the canonical name is obtained from -** sqliteMalloc() and must be freed by the calling function. -*/ -static char *sqliteNameOfTable(const char *zTable){ - char *zNew = 0; - int i, c; - sqliteSetString(&zNew, zTable, 0); - if( zNew==0 ) return 0; - for(i=0; (c = zNew[i])!=0; i++){ - if( isupper(c) ){ - zNew[i] = tolower(c); - } - } - return zNew; -} - -/* -** 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 zTable is 0 or "", then a temporary database file is created and -** a cursor to that temporary file is opened. The temporary file -** will be deleted from the disk when it is closed. -*/ -static int sqliteMemOpenCursor( - 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 */ -){ - DbbeCursor *pCursr; /* The new table cursor */ - char *zName; /* Canonical table name */ - MTable *pTble; /* The underlying data file for this table */ - int rc = SQLITE_OK; /* Return value */ - Dbbex *pBe = (Dbbex*)pDbbe; - - *ppCursr = 0; - pCursr = sqliteMalloc( sizeof(*pCursr) ); - if( pCursr==0 ) return SQLITE_NOMEM; - if( zTable ){ - Datum key; - zName = sqliteNameOfTable(zTable); - if( zName==0 ) return SQLITE_NOMEM; - key.p = zName; - key.n = strlen(zName); - pTble = ArrayFind(&pBe->tables, key).p; - }else{ - zName = 0; - pTble = 0; - } - if( pTble==0 ){ - pTble = sqliteMalloc( sizeof(*pTble) ); - if( pTble==0 ){ - sqliteFree(zName); - return SQLITE_NOMEM; - } - if( zName ){ - Datum ins_key, ins_data; - pTble->zName = zName; - pTble->delOnClose = 0; - ins_data.p = pTble; - ins_data.n = sizeof( *pTble ); - ins_key.p = zName; - ins_key.n = strlen(zName); - ArrayInsert(&pBe->tables, ins_key, ins_data); - }else{ - pTble->zName = 0; - pTble->delOnClose = 1; - } - pTble->intKeyOnly = intKeyOnly; - ArrayInit(&pTble->data); - }else{ - assert( pTble->intKeyOnly==intKeyOnly ); - sqliteFree(zName); - } - pCursr->pBe = pBe; - pCursr->pTble = pTble; - pCursr->needRewind = 1; - *ppCursr = pCursr; - return rc; -} - -/* -** Drop a table from the database. The file on the disk that corresponds -** to this table is deleted. -*/ -static void sqliteMemDropTable(Dbbe *pDbbe, const char *zTable){ - char *zName; /* Name of the table file */ - Datum key, data; - MTable *pTble; - Dbbex *pBe = (Dbbex*)pDbbe; - - zName = sqliteNameOfTable(zTable); - key.p = zName; - key.n = strlen(zName); - pTble = ArrayFind(&pBe->tables, key).p; - if( pTble ){ - data.p = 0; - data.n = 0; - ArrayInsert(&pBe->tables, key, data); - deleteMTable(pTble); - } - sqliteFree(zName); -} - -/* -** Close a cursor previously opened by sqliteMemOpenCursor(). -** -** There can be multiple cursors pointing to the same open file. -** The underlying file is not closed until all cursors have been -** closed. This routine decrements the MTable.nref field of the -** underlying file and closes the file when nref reaches 0. -*/ -static void sqliteMemCloseCursor(DbbeCursor *pCursr){ - MTable *pTble; - Dbbex *pBe; - if( pCursr==0 ) return; - pTble = pCursr->pTble; - pBe = pCursr->pBe; - if( pTble->delOnClose ){ - deleteMTable(pTble); - } - sqliteFree(pCursr); -} - -/* -** Reorganize a table to reduce search times and disk usage. -*/ -static int sqliteMemReorganizeTable(Dbbe *pBe, const char *zTable){ - /* Do nothing */ - return SQLITE_OK; -} - -/* -** Fetch a single record from an open cursor. Return 1 on success -** and 0 on failure. -*/ -static int sqliteMemFetch(DbbeCursor *pCursr, int nKey, char *pKey){ - Datum key; - key.n = nKey; - key.p = pKey; - assert( nKey==4 || pCursr->pTble->intKeyOnly==0 ); - pCursr->elem = ArrayFindElement(&pCursr->pTble->data, key); - return pCursr->elem!=0; -} - -/* -** Return 1 if the given key is already in the table. Return 0 -** if it is not. -*/ -static int sqliteMemTest(DbbeCursor *pCursr, int nKey, char *pKey){ - return sqliteMemFetch(pCursr, nKey, pKey); -} - -/* -** Copy bytes from the current key or data into a buffer supplied by -** the calling function. Return the number of bytes copied. -*/ -static -int sqliteMemCopyKey(DbbeCursor *pCursr, int offset, int size, char *zBuf){ - int n; - if( pCursr->elem==0 ) return 0; - if( offset>=ArrayKeySize(pCursr->elem) ) return 0; - if( offset+size>ArrayKeySize(pCursr->elem) ){ - n = ArrayKeySize(pCursr->elem) - offset; - }else{ - n = size; - } - memcpy(zBuf, &((char*)ArrayKey(pCursr->elem))[offset], n); - return n; -} -static -int sqliteMemCopyData(DbbeCursor *pCursr, int offset, int size, char *zBuf){ - int n; - if( pCursr->elem==0 ) return 0; - if( offset>=ArrayDataSize(pCursr->elem) ) return 0; - if( offset+size>ArrayDataSize(pCursr->elem) ){ - n = ArrayDataSize(pCursr->elem) - offset; - }else{ - n = size; - } - memcpy(zBuf, &((char*)ArrayData(pCursr->elem))[offset], n); - return n; -} - -/* -** Return a pointer to bytes from the key or data. The data returned -** is ephemeral. -*/ -static char *sqliteMemReadKey(DbbeCursor *pCursr, int offset){ - if( pCursr->elem==0 || offset<0 || offset>=ArrayKeySize(pCursr->elem) ){ - return ""; - } - return &((char*)ArrayKey(pCursr->elem))[offset]; -} -static char *sqliteMemReadData(DbbeCursor *pCursr, int offset){ - if( pCursr->elem==0 || offset<0 || offset>=ArrayDataSize(pCursr->elem) ){ - return ""; - } - return &((char*)ArrayData(pCursr->elem))[offset]; -} - -/* -** Return the total number of bytes in either data or key. -*/ -static int sqliteMemKeyLength(DbbeCursor *pCursr){ - return pCursr->elem ? ArrayKeySize(pCursr->elem) : 0; -} -static int sqliteMemDataLength(DbbeCursor *pCursr){ - return pCursr->elem ? ArrayDataSize(pCursr->elem) : 0; -} - -/* -** Make is so that the next call to sqliteNextKey() finds the first -** key of the table. -*/ -static int sqliteMemRewind(DbbeCursor *pCursr){ - pCursr->needRewind = 1; - return SQLITE_OK; -} - -/* -** Read the next key from the table. Return 1 on success. Return -** 0 if there are no more keys. -*/ -static int sqliteMemNextKey(DbbeCursor *pCursr){ - if( pCursr->needRewind || pCursr->elem==0 ){ - pCursr->elem = ArrayFirst(&pCursr->pTble->data); - pCursr->needRewind = 0; - }else{ - pCursr->elem = ArrayNext(pCursr->elem); - } - return pCursr->elem!=0; -} - -/* -** Get a new integer key. -*/ -static int sqliteMemNew(DbbeCursor *pCursr){ - int iKey; - Datum key; - int go = 1; - - while( go ){ - iKey = sqliteRandomInteger() & 0x7fffffff; - if( iKey==0 ) continue; - key.p = (char*)&iKey; - key.n = 4; - go = ArrayFindElement(&pCursr->pTble->data, key)!=0; - } - return iKey; -} - -/* -** Write an entry into the table. Overwrite any prior entry with the -** same key. -*/ -static int sqliteMemPut( - DbbeCursor *pCursr, /* Write new entry into this database table */ - int nKey, char *pKey, /* The key of the new entry */ - int nData, char *pData /* The data of the new entry */ -){ - Datum data, key; - data.n = nData; - data.p = sqliteMalloc( data.n ); - if( data.p==0 ) return SQLITE_NOMEM; - memcpy(data.p, pData, data.n); - key.n = nKey; - key.p = pKey; - assert( nKey==4 || pCursr->pTble->intKeyOnly==0 ); - data = ArrayInsert(&pCursr->pTble->data, key, data); - if( data.p ){ - sqliteFree(data.p); - } - return SQLITE_OK; -} - -/* -** Remove an entry from a table, if the entry exists. -*/ -static int sqliteMemDelete(DbbeCursor *pCursr, int nKey, char *pKey){ - Datum key, data; - key.n = nKey; - key.p = pKey; - data.p = 0; - data.n = 0; - data = ArrayInsert(&pCursr->pTble->data, key, data); - if( data.p ){ - sqliteFree(data.p); - } - return SQLITE_OK; -} - -/* -** Begin scanning an index for the given key. Return 1 on success and -** 0 on failure. -*/ -static int sqliteMemBeginIndex(DbbeCursor *pCursr, int nKey, char *pKey){ - if( !sqliteMemFetch(pCursr, nKey, pKey) ) return 0; - pCursr->nextIndex = 0; - return 1; -} - -/* -** 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 sqliteMemNextIndex(DbbeCursor *pCursr){ - int *aIdx; - int nIdx; - int k; - nIdx = sqliteMemDataLength(pCursr)/sizeof(int); - aIdx = (int*)sqliteMemReadData(pCursr, 0); - if( nIdx>1 ){ - k = *(aIdx++); - if( k>nIdx-1 ) k = nIdx-1; - }else{ - k = nIdx; - } - while( pCursr->nextIndex < k ){ - int recno = aIdx[pCursr->nextIndex++]; - if( recno!=0 ) return recno; - } - pCursr->nextIndex = 0; - return 0; -} - -/* -** Write a new record number and key into an index table. Return a status -** code. -*/ -static int sqliteMemPutIndex(DbbeCursor *pCursr, int nKey, char *pKey, int N){ - int r = sqliteMemFetch(pCursr, nKey, pKey); - if( r==0 ){ - /* Create a new record for this index */ - sqliteMemPut(pCursr, nKey, pKey, sizeof(int), (char*)&N); - }else{ - /* Extend the existing record */ - int nIdx; - int *aIdx; - int k; - - nIdx = sqliteMemDataLength(pCursr)/sizeof(int); - if( nIdx==1 ){ - aIdx = sqliteMalloc( sizeof(int)*4 ); - if( aIdx==0 ) return SQLITE_NOMEM; - aIdx[0] = 2; - sqliteMemCopyData(pCursr, 0, sizeof(int), (char*)&aIdx[1]); - aIdx[2] = N; - sqliteMemPut(pCursr, nKey, pKey, sizeof(int)*4, (char*)aIdx); - sqliteFree(aIdx); - }else{ - aIdx = (int*)sqliteMemReadData(pCursr, 0); - k = aIdx[0]; - if( kk ) return SQLITE_OK; - aIdx[j] = aIdx[k]; - aIdx[k] = 0; - aIdx[0]--; - if( aIdx[0]*3 + 1 < nIdx ){ - nIdx /= 2; - } - sqliteMemPut(pCursr, nKey, pKey, sizeof(int)*nIdx, (char*)aIdx); - } - return SQLITE_OK; -} - -/* -** This variable contains pointers to all of the access methods -** used to implement the MEMORY backend. -*/ -static struct DbbeMethods memoryMethods = { - /* Close */ sqliteMemClose, - /* OpenCursor */ sqliteMemOpenCursor, - /* DropTable */ sqliteMemDropTable, - /* ReorganizeTable */ sqliteMemReorganizeTable, - /* CloseCursor */ sqliteMemCloseCursor, - /* Fetch */ sqliteMemFetch, - /* Test */ sqliteMemTest, - /* CopyKey */ sqliteMemCopyKey, - /* CopyData */ sqliteMemCopyData, - /* ReadKey */ sqliteMemReadKey, - /* ReadData */ sqliteMemReadData, - /* KeyLength */ sqliteMemKeyLength, - /* DataLength */ sqliteMemDataLength, - /* NextKey */ sqliteMemNextKey, - /* Rewind */ sqliteMemRewind, - /* New */ sqliteMemNew, - /* Put */ sqliteMemPut, - /* Delete */ sqliteMemDelete, - /* BeginTrans */ 0, - /* Commit */ 0, - /* Rollback */ 0, - /* BeginIndex */ sqliteMemBeginIndex, - /* NextIndex */ sqliteMemNextIndex, - /* PutIndex */ sqliteMemPutIndex, - /* DeleteIndex */ sqliteMemDeleteIndex, -}; - -/* -** This routine opens a new database. For the MEMORY driver -** implemented here, the database name is ignored. Every MEMORY database -** is unique and is erased when the database is closed. -** -** 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 *sqliteMemOpen( - 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; - - pNew = sqliteMalloc( sizeof(*pNew) ); - if( pNew==0 ){ - sqliteSetString(pzErrMsg, "out of memory", 0); - return 0; - } - ArrayInit(&pNew->tables); - pNew->dbbe.x = &memoryMethods; - return &pNew->dbbe; -} diff --git a/src/delete.c b/src/delete.c index 06e7d82bd0..ab5e7f2da1 100644 --- a/src/delete.c +++ b/src/delete.c @@ -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.10 2001/09/13 13:46:56 drh Exp $ +** $Id: delete.c,v 1.11 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" @@ -137,12 +137,12 @@ void sqliteDeleteFrom( addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0); if( pTab->pIndex ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); - sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0); + sqliteVdbeAddOp(v, OP_MoveTo, base, 0, 0, 0); for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ int j; sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); for(j=0; jnColumn; j++){ - sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0); + sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j], 0, 0); } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0); diff --git a/src/expr.c b/src/expr.c index abc4963819..0a1636c412 100644 --- a/src/expr.c +++ b/src/expr.c @@ -24,7 +24,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions. ** -** $Id: expr.c,v 1.25 2001/07/23 14:33:04 drh Exp $ +** $Id: expr.c,v 1.26 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" @@ -246,7 +246,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){ ** table. The cursor number of the temporary table has already ** been put in iTable by sqliteExprResolveInSelect(). */ - sqliteVdbeAddOp(v, OP_OpenIdx, pExpr->iTable, 1, 0, 0); + sqliteVdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 0, 0, 0); if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) ); }else if( pExpr->pList ){ /* Case 2: expr IN (exprlist) @@ -515,9 +515,9 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ if( pParse->useAgg ){ sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0); }else if( pExpr->iColumn>=0 ){ - sqliteVdbeAddOp(v, OP_Field, pExpr->iTable, pExpr->iColumn, 0, 0); + sqliteVdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn, 0, 0); }else{ - sqliteVdbeAddOp(v, OP_Key, pExpr->iTable, 0, 0, 0); + sqliteVdbeAddOp(v, OP_FullKey, pExpr->iTable, 0, 0, 0); } break; } diff --git a/src/insert.c b/src/insert.c index 97a21046fc..d550f13483 100644 --- a/src/insert.c +++ b/src/insert.c @@ -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.14 2001/09/13 13:46:56 drh Exp $ +** $Id: insert.c,v 1.15 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" @@ -98,7 +98,7 @@ void sqliteInsert( if( pSelect ){ int rc; srcTab = pParse->nTab++; - sqliteVdbeAddOp(v, OP_OpenTbl, srcTab, 1, 0, 0); + sqliteVdbeAddOp(v, OP_OpenTemp, srcTab, 0, 0, 0); rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab); if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; assert( pSelect->pEList ); @@ -163,9 +163,9 @@ void sqliteInsert( ** all indices of that table. */ base = pParse->nTab; - sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0); + sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, pTab->zName, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ - sqliteVdbeAddOp(v, OP_OpenIdx, idx+base, 1, pIdx->zName, 0); + sqliteVdbeAddOp(v, OP_Open, idx+base, pIdx->tnum, pIdx->zName, 0); } /* If the data source is a SELECT statement, then we have to create @@ -181,7 +181,7 @@ void sqliteInsert( /* Create a new entry in the table and fill it with data. */ - 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); } @@ -201,7 +201,7 @@ void sqliteInsert( sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0); } }else if( srcTab>=0 ){ - sqliteVdbeAddOp(v, OP_Field, srcTab, i, 0, 0); + sqliteVdbeAddOp(v, OP_Column, srcTab, i, 0, 0); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } @@ -233,7 +233,7 @@ void sqliteInsert( sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0); } }else if( srcTab>=0 ){ - sqliteVdbeAddOp(v, OP_Field, srcTab, idx, 0, 0); + sqliteVdbeAddOp(v, OP_Column, srcTab, idx, 0, 0); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } diff --git a/src/main.c b/src/main.c index 4c48c0e7f3..8345b2a399 100644 --- a/src/main.c +++ b/src/main.c @@ -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.30 2001/09/13 13:46:56 drh Exp $ +** $Id: main.c,v 1.31 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" #if defined(HAVE_USLEEP) && HAVE_USLEEP @@ -233,7 +233,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){ } } sqliteFree(db); - return rc; + return 0; } /* Assume file format 1 unless the database says otherwise */ diff --git a/src/pager.c b/src/pager.c index 71eaf9a7d5..3156f8ef5a 100644 --- a/src/pager.c +++ b/src/pager.c @@ -27,7 +27,7 @@ ** all writes in order to support rollback. Locking is used to limit ** access to one or more reader or to one writer. ** -** @(#) $Id: pager.c,v 1.14 2001/09/13 13:46:57 drh Exp $ +** @(#) $Id: pager.c,v 1.15 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -476,7 +476,7 @@ static const char *findTempDir(void){ struct stat buf; for(i=0; i0 && fd<0 ); zFilename = zTemp; @@ -1138,7 +1138,7 @@ int sqlitepager_rollback(Pager *pPager){ ** if the database is (in theory) writable. */ int sqlitepager_isreadonly(Pager *pPager){ - return pPager->readonly; + return pPager->readOnly; } /* diff --git a/src/select.c b/src/select.c index e2b834f339..ea29e12511 100644 --- a/src/select.c +++ b/src/select.c @@ -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.32 2001/09/13 13:46:57 drh Exp $ +** $Id: select.c,v 1.33 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" @@ -122,7 +122,7 @@ static int selectInnerLoop( nColumn = pEList->nExpr; }else{ for(i=0; i -#endif +#include "btree.h" #include #include #include @@ -182,7 +180,7 @@ struct 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 */ + int isDelete; /* True if this table is being deleted */ }; /* @@ -210,6 +208,7 @@ struct Index { int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ Table *pTable; /* The SQL table being indexed */ + int tnum; /* Page containing root of this index in database file */ 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 */ @@ -445,7 +444,6 @@ Vdbe *sqliteGetVdbe(Parse*); int sqliteRandomByte(void); int sqliteRandomInteger(void); void sqliteRandomName(char*,char*); -char *sqliteDbbeNameToFile(const char*,const char*,const char*); void sqliteBeginTransaction(Parse*); void sqliteCommitTransaction(Parse*); void sqliteRollbackTransaction(Parse*); diff --git a/src/vdbe.c b/src/vdbe.c index 8083ae5149..01b5e06f36 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -41,7 +41,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.60 2001/09/13 13:46:57 drh Exp $ +** $Id: vdbe.c,v 1.61 2001/09/13 14:46:11 drh Exp $ */ #include "sqliteInt.h" #include @@ -194,7 +194,7 @@ struct Keylist { */ struct Vdbe { sqlite *db; /* The whole database */ - Dbbe *pBe; /* Opaque context structure used by DB backend */ + 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[] */ @@ -235,7 +235,7 @@ Vdbe *sqliteVdbeCreate(sqlite *db){ Vdbe *p; p = sqliteMalloc( sizeof(Vdbe) ); if( p==0 ) return 0; - p->pBe = db->pBe; + p->pBt = db->pBe; p->db = db; return p; } @@ -881,20 +881,20 @@ static char *zOpName[] = { 0, "ListRewind", "ListRead", "ListClose", "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortKey", "SortCallback", "SortClose", - "FileOpen", "FileRead", "FileField", "FileClose", + "FileOpen", "FileRead", "FileColumn", "FileClose", "AggReset", "AggFocus", "AggIncr", "AggNext", "AggSet", "AggGet", "SetInsert", "SetFound", "SetNotFound", "SetClear", "MakeRecord", "MakeKey", - "Goto", "If", "Halt", "ColumnCount", - "ColumnName", "Callback", "Integer", "String", - "Null", "Pop", "Dup", "Pull", - "Add", "AddImm", "Subtract", "Multiply", - "Divide", "Min", "Max", "Like", - "Glob", "Eq", "Ne", "Lt", - "Le", "Gt", "Ge", "IsNull", - "NotNull", "Negative", "And", "Or", - "Not", "Concat", "Noop", "Strlen", - "Substr", + "MakeIdxKey", "Goto", "If", "Halt", + "ColumnCount", "ColumnName", "Callback", "Integer", + "String", "Null", "Pop", "Dup", + "Pull", "Add", "AddImm", "Subtract", + "Multiply", "Divide", "Min", "Max", + "Like", "Glob", "Eq", "Ne", + "Lt", "Le", "Gt", "Ge", + "IsNull", "NotNull", "Negative", "And", + "Or", "Not", "Concat", "Noop", + "Strlen", "Substr", }; /* @@ -1038,9 +1038,8 @@ int sqliteVdbeExec( int pc; /* The program counter */ Op *pOp; /* Current operation */ int rc; /* Value to return */ - Dbbe *pBe = p->pBe; /* The backend driver */ + Btree *pBt = p->pBt; /* The backend driver */ sqlite *db = p->db; /* The database */ - int rollbackOnError = 0; /* If TRUE, rollback if the script fails. char **zStack; /* Text stack */ Stack *aStack; /* Additional stack information */ char zBuf[100]; /* Space to sprintf() an integer */ @@ -1920,7 +1919,7 @@ case OP_MakeIdxKey: { } zNewKey[j++] = 0; Integerify(p, p->tos-nField); - memcpy(&zNewKey[j], aStack[p->tos-nField].i, sizeof(int)); + memcpy(&zNewKey[j], &aStack[p->tos-nField].i, sizeof(int)); PopStack(p, nField+1); VERIFY( NeedStack(p, p->tos+1); ) p->tos++; @@ -1940,7 +1939,7 @@ case OP_MakeIdxKey: { ** database. */ case OP_Transaction: { - rc = sqliteBtreeBeginTrans(pBe); + rc = sqliteBtreeBeginTrans(pBt); break; } @@ -1951,7 +1950,7 @@ case OP_Transaction: { ** are allowed until another transaction is started. */ case OP_Commit: { - rc = sqliteBtreeCommit(pBe); + rc = sqliteBtreeCommit(pBt); if( rc==SQLITE_OK ){ sqliteCommitInternalChanges(db); }else{ @@ -1968,7 +1967,7 @@ case OP_Commit: { ** are allowed until another transaction is started. */ case OP_Rollback: { - rc = sqliteBtreeRollback(pBe); + rc = sqliteBtreeRollback(pBt); sqliteRollbackInternalChanges(db); break; } @@ -1999,8 +1998,8 @@ case OP_Open: { sqliteBtreeCloseCursor(p->aCsr[i].pCursor); } memset(&p->aCsr[i], 0, sizeof(Cursor)); - do { - rc = sqliteBtreeOpenCursor(pBe, pOp->p2, &p->aCsr[i].pCursor); + do{ + rc = sqliteBtreeCursor(pBt, pOp->p2, &p->aCsr[i].pCursor); switch( rc ){ case SQLITE_BUSY: { if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){ @@ -2029,7 +2028,6 @@ case OP_Open: { ** cursor is closed. */ case OP_OpenTemp: { - int busy = 0; int i = pOp->p1; Cursor *pCx; VERIFY( if( i<0 ) goto bad_instruction; ) @@ -2046,7 +2044,7 @@ case OP_OpenTemp: { memset(pCx, 0, sizeof(*pCx)); rc = sqliteBtreeOpen(0, 0, 100, &pCx->pBt); if( rc==SQLITE_OK ){ - rc = sqliteBtreeOpenCursor(pCx->pBt, 2, &pCx->pCursor); + rc = sqliteBtreeCursor(pCx->pBt, 2, &pCx->pCursor); } if( rc==SQLITE_OK ){ rc = sqliteBtreeBeginTrans(pCx->pBt); @@ -2091,14 +2089,13 @@ case OP_MoveTo: { if( i>=0 && inCursor && p->aCsr[i].pCursor ){ int res; if( aStack[tos].flags & STK_Int ){ - sqliteBtreeMoveTo(p->aCsr[i].pCursor, sizeof(int), - (char*)&aStack[tos].i, &res); + sqliteBtreeMoveto(p->aCsr[i].pCursor, + (char*)&aStack[tos].i, sizeof(int), &res); p->aCsr[i].lastRecno = aStack[tos].i; p->aCsr[i].recnoIsValid = 1; }else{ if( Stringify(p, tos) ) goto no_mem; - pBex->Fetch(p->aCsr[i].pCursor, aStack[tos].n, - zStack[tos], &res); + sqliteBtreeMoveto(p->aCsr[i].pCursor, zStack[tos], aStack[tos].n, &res); p->aCsr[i].recnoIsValid = 0; } p->nFetch++; @@ -2161,12 +2158,12 @@ case OP_Found: { if( VERIFY( i>=0 && inCursor && ) p->aCsr[i].pCursor ){ int res, rx; if( aStack[tos].flags & STK_Int ){ - rx = sqliteBtreeMoveTo(p->aCsr[i].pCursor, sizeof(int), - (char*)&aStack[tos].i, &res); + rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, + (char*)&aStack[tos].i, sizeof(int), &res); }else{ if( Stringify(p, tos) ) goto no_mem; - rx = sqliteBtreeMoveTo(p->aCsr[i].pCursor,aStack[tos].n, - zStack[tos], &res); + rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, + zStack[tos], aStack[tos].n, &res); } alreadyExists = rx==SQLITE_OK && res==0; } @@ -2198,7 +2195,7 @@ case OP_NewRecno: { cnt = 0; do{ v = sqliteRandomInteger(); - rx = sqliteBtreeMoveTo(p->aCsr[i].pCursor, sizeof(v), &v, &res); + rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, &v, sizeof(v), &res); cnt++; }while( cnt<10 && rx==SQLITE_OK && res==0 ); } @@ -2233,9 +2230,8 @@ case OP_Put: { nKey = sizeof(int); zKey = (char*)&aStack[nos].i; } - rc = sqliteBtreeInsert(p->aCsr[i].pCursor, nKey, zKey, - aStack[tos].n, zStack[tos]); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey, + zStack[tos], aStack[tos].n); } POPSTACK; POPSTACK; @@ -2250,6 +2246,7 @@ case OP_Put: { case OP_Delete: { int tos = p->tos; int i = pOp->p1; + int res; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && inCursor && ) p->aCsr[i].pCursor!=0 ){ char *zKey; @@ -2262,8 +2259,8 @@ case OP_Delete: { nKey = aStack[tos].n; zKey = zStack[tos]; } - rc = sqliteBtreeDelete(p->aCsr[i].pCursor, nKey, zKey); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + rc = sqliteBtreeMoveto(p->aCsr[i].pCursor, zKey, nKey, &res); + rc = sqliteBtreeDelete(p->aCsr[i].pCursor); } POPSTACK; break; @@ -2301,7 +2298,6 @@ case OP_KeyAsData: { ** data. */ case OP_Column: { - int *pAddr; int amt, offset, nCol, payloadSize; int aHdr[10]; const int mxHdr = sizeof(aHdr)/sizeof(aHdr[0]); @@ -2314,7 +2310,7 @@ case OP_Column: { VERIFY( if( NeedStack(p, tos) ) goto no_mem; ) if( VERIFY( i>=0 && inCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int (*xSize)(BtCursor*, int*); - int (*xRead)(BtCursor*, int, int, void*); + int (*xRead)(BtCursor*, int, int, char*); /* Use different access functions depending on whether the information ** is coming from the key or the data of the record. @@ -2340,7 +2336,7 @@ case OP_Column: { goto abort_due_to_error; } if( p2+1aCsr[i].recnoIsValid ){ v = p->aCsr[i].lastRecno; }else{ - sqliteBtreeKey(pCrsr, 0, sizeof(int), &v); + sqliteBtreeKey(pCrsr, 0, sizeof(int), (char*)&v); } aStack[tos].i = v; aStack[tos].flags = STK_Int; @@ -2506,7 +2502,7 @@ case OP_BeginIdx: { pCrsr->zBuf = &pCrsr->zKey[pCrsr->nKey+1]; strncpy(pCrsr->zKey, zStack[tos], aStack[tos].n); pCrsr->zKey[aStack[tos].n] = 0; - rx = sqliteBtreeMoveTo(pCrsr->pCursor, aStack[tos].n, zStack[tos], &res); + rx = sqliteBtreeMoveto(pCrsr->pCursor, zStack[tos], aStack[tos].n, &res); pCrsr->atFirst = rx==SQLITE_OK && res>0; pCrsr->recnoIsValid = 0; } @@ -2526,16 +2522,16 @@ case OP_NextIdx: { int i = pOp->p1; int tos = ++p->tos; Cursor *pCrsr; - BtCursr *pCur; + BtCursor *pCur; int rx, res, size; VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) zStack[tos] = 0; - if( VERIFY( i>=0 && inCursor && ) (pCrsr = &p->aCsr[i])->pCursor)!=0 ){ + if( VERIFY( i>=0 && inCursor && ) (pCrsr = &p->aCsr[i])->pCursor!=0 ){ pCur = pCrsr->pCursor; rx = sqliteBtreeNext(pCur, &res); if( rx!=SQLITE_OK ) goto abort_due_to_error; - sqliteBtreeKeySzie(pCur, &size); + sqliteBtreeKeySize(pCur, &size); if( res>0 || size!=pCrsr->nKey+sizeof(int) || sqliteBtreeKey(pCur, 0, pCrsr->nKey, pCrsr->zBuf)!=pCrsr->nKey || strncmp(pCrsr->zKey, pCrsr->zBuf, pCrsr->nKey)!=0 @@ -2544,7 +2540,7 @@ case OP_NextIdx: { POPSTACK; }else{ int recno; - sqliteBtreeKey(pCur, pCrsr->nKey, sizeof(int), &recno); + sqliteBtreeKey(pCur, pCrsr->nKey, sizeof(int), (char*)&recno); p->aCsr[i].lastRecno = aStack[tos].i = recno; p->aCsr[i].recnoIsValid = 1; aStack[tos].flags = STK_Int; @@ -2565,7 +2561,7 @@ case OP_PutIdx: { BtCursor *pCrsr; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && inCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ - sqliteBtreePut(pCrsr, aStack[tos].n, zStack[tos], 0, ""); + sqliteBtreeInsert(pCrsr, zStack[tos], aStack[tos].n, "", 0); } POPSTACK; break; @@ -2583,7 +2579,7 @@ case OP_DeleteIdx: { VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && inCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int rx, res; - rx = sqliteBtreeMoveTo(pCrsr, aStack[tos].n, zStack[tos], &res); + rx = sqliteBtreeMoveto(pCrsr, zStack[tos], aStack[tos].n, &res); if( rx==SQLITE_OK && res==0 ){ sqliteBtreeDelete(pCrsr); } @@ -2598,7 +2594,7 @@ case OP_DeleteIdx: { ** file is given by P1. */ case OP_Destroy: { - sqliteBtreeDropTable(pBe, pOp->p1); + sqliteBtreeDropTable(pBt, pOp->p1); break; } @@ -3115,12 +3111,12 @@ fileread_jump: break; } -/* Opcode: FileField P1 * * +/* Opcode: FileColumn P1 * * ** ** Push onto the stack the P1-th field of the most recently read line ** from the input file. */ -case OP_FileField: { +case OP_FileColumn: { int i = pOp->p1; char *z; VERIFY( if( NeedStack(p, p->tos+1) ) goto no_mem; ) @@ -3628,7 +3624,7 @@ default: { cleanup: Cleanup(p); if( rc!=SQLITE_OK && (db->flags & SQLITE_InTrans)!=0 ){ - sqliteBtreeRollback(pBe); + sqliteBtreeRollback(pBt); sqliteRollbackInternalChanges(db); db->flags &= ~SQLITE_InTrans; } @@ -3645,7 +3641,7 @@ no_mem: /* Jump to here for any other kind of fatal error. The "rc" variable ** should hold the error number. */ -abort_due_to_err: +abort_due_to_error: sqliteSetString(pzErrMsg, sqliteErrStr(rc), 0); goto cleanup; diff --git a/src/vdbe.h b/src/vdbe.h index e939232cc0..59f8340226 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -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.19 2001/09/13 13:46:57 drh Exp $ +** $Id: vdbe.h,v 1.20 2001/09/13 14:46:11 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -124,7 +124,7 @@ typedef struct VdbeOp VdbeOp; #define OP_FileOpen 45 #define OP_FileRead 46 -#define OP_FileField 47 +#define OP_FileColumn 47 #define OP_FileClose 48 #define OP_AggReset 49 diff --git a/src/where.c b/src/where.c index 4b0e8ed8b0..33cb3897d7 100644 --- a/src/where.c +++ b/src/where.c @@ -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.16 2001/09/13 13:46:57 drh Exp $ +** $Id: where.c,v 1.17 2001/09/13 14:46:11 drh Exp $ */ #include "sqliteInt.h" @@ -300,7 +300,7 @@ WhereInfo *sqliteWhereBegin( sqliteVdbeAddOp(v, OP_Open, base+i, pTabList->a[i].pTab->tnum, pTabList->a[i].pTab->zName, 0); if( inId+i, aIdx[i]->tnum + sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, aIdx[i]->tnum, aIdx[i]->zName, 0); } } @@ -351,7 +351,7 @@ WhereInfo *sqliteWhereBegin( if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; }else{ - sqliteVdbeAddOp(v, OP_Fetch, base+idx, 0, 0, 0); + sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0, 0, 0); haveKey = 0; } }else if( pIdx==0 ){ @@ -392,7 +392,7 @@ WhereInfo *sqliteWhereBegin( if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; }else{ - sqliteVdbeAddOp(v, OP_Fetch, base+idx, 0, 0, 0); + sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0, 0, 0); haveKey = 0; } } @@ -407,7 +407,7 @@ WhereInfo *sqliteWhereBegin( if( (aExpr[j].prereqLeft & loopMask)!=aExpr[j].prereqLeft ) continue; if( haveKey ){ haveKey = 0; - sqliteVdbeAddOp(v, OP_Fetch, base+idx, 0, 0, 0); + sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0, 0, 0); } sqliteExprIfFalse(pParse, aExpr[j].p, cont); aExpr[j].p = 0; @@ -416,7 +416,7 @@ WhereInfo *sqliteWhereBegin( } pWInfo->iContinue = cont; if( pushKey && !haveKey ){ - sqliteVdbeAddOp(v, OP_Key, base, 0, 0, 0); + sqliteVdbeAddOp(v, OP_Recno, base, 0, 0, 0); } sqliteFree(aOrder); return pWInfo; diff --git a/test/btree2.test b/test/btree2.test index 7329313bf0..0eb2f6ec90 100644 --- a/test/btree2.test +++ b/test/btree2.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # -# $Id: btree2.test,v 1.4 2001/08/20 00:33:58 drh Exp $ +# $Id: btree2.test,v 1.5 2001/09/13 14:46:11 drh Exp $ set testdir [file dirname $argv0] @@ -288,8 +288,8 @@ foreach {N L} { 10 2 50 2 200 3 + 2000 5 } { -# 2000 5 puts "**** N=$N L=$L ****" set hash [md5file test2.bt] do_test btree2-$testno.1 [subst -nocommands {